@kizenapps/cli 1.13.0-poc-bcd37de → 1.13.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.
- package/dist/index.js +13 -13
- package/dist/index.js.map +1 -1
- package/package.json +26 -21
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/lib/proxyEnv.ts","../src/program.ts","../src/commands/block.ts","../src/lib/clipboard.ts","../src/lib/exportBlock.ts","../src/lib/runBuild.ts","../src/lib/readFiles.ts","../src/lib/formatValidationIssues.ts","../src/lib/pushHeadless.ts","../shared/lib/kizenUrls.ts","../src/lib/config.ts","../src/lib/credentials.ts","../shared/lib/credentials.ts","../src/lib/gitignore.ts","../src/lib/kizenClient.ts","../src/lib/pushBlock.ts","../src/lib/setupClaude.ts","raw:/Users/keegan/Developer/app-builder/src/templates/claude/skills/kizen-custom-block/SKILL.md?raw","raw:/Users/keegan/Developer/app-builder/src/templates/claude/skills/kizen-custom-block/design.md?raw","raw:/Users/keegan/Developer/app-builder/src/templates/github/copilot-instructions.md?raw","raw:/Users/keegan/Developer/app-builder/src/templates/github/instructions/security.instructions.md?raw","raw:/Users/keegan/Developer/app-builder/src/templates/github/instructions/version-discipline.instructions.md?raw","raw:/Users/keegan/Developer/app-builder/src/templates/plugin/lib/kizenData.js?raw","../src/lib/createCopilotFiles.ts","../src/ui/PushUI.tsx","../src/ui/AppHeader.tsx","../src/ui/Logo.tsx","../src/ui/SelectList.tsx","../src/lib/moveCursor.ts","../src/ui/Spinner.tsx","../src/commands/build.ts","../src/ui/BuildUI.tsx","../shared/lib/formatBytes.ts","../src/ui/ValidationIssues.tsx","../src/commands/create.ts","../src/ui/CreateUI.tsx","../src/lib/createPlugin.ts","raw:/Users/keegan/Developer/app-builder/src/templates/artifacts/floatingFrames/helloFrame/config.json?raw","raw:/Users/keegan/Developer/app-builder/src/templates/artifacts/floatingFrames/helloFrame/script.js?raw","raw:/Users/keegan/Developer/app-builder/src/templates/artifacts/floatingFrames/helloFrame/styles.css?raw","raw:/Users/keegan/Developer/app-builder/src/templates/artifacts/blocks/helloBlock/config.json?raw","raw:/Users/keegan/Developer/app-builder/src/templates/artifacts/blocks/helloBlock/script.js?raw","raw:/Users/keegan/Developer/app-builder/src/templates/artifacts/blocks/helloBlock/styles.css?raw","raw:/Users/keegan/Developer/app-builder/src/templates/artifacts/dataAdornments/helloAdornment/config.json?raw","raw:/Users/keegan/Developer/app-builder/src/templates/artifacts/dataAdornments/helloAdornment/script.js?raw","raw:/Users/keegan/Developer/app-builder/src/templates/artifacts/pages/helloPage/config.json?raw","raw:/Users/keegan/Developer/app-builder/src/templates/artifacts/pages/helloPage/script.js?raw","raw:/Users/keegan/Developer/app-builder/src/templates/artifacts/pages/helloPage/styles.css?raw","raw:/Users/keegan/Developer/app-builder/src/templates/artifacts/pages/helloPage/eventScripts/greet.js?raw","raw:/Users/keegan/Developer/app-builder/src/templates/artifacts/toolbarItems/helloToolbarItem/config.json?raw","raw:/Users/keegan/Developer/app-builder/src/templates/artifacts/toolbarItems/helloToolbarItem/script.js?raw","raw:/Users/keegan/Developer/app-builder/src/templates/artifacts/objectSettingsItems/helloObjectSettingsItem/config.json?raw","raw:/Users/keegan/Developer/app-builder/src/templates/artifacts/objectSettingsItems/helloObjectSettingsItem/script.js?raw","raw:/Users/keegan/Developer/app-builder/src/templates/artifacts/actions/helloAction/config.json?raw","raw:/Users/keegan/Developer/app-builder/src/templates/artifacts/actions/helloAction/script.js?raw","../src/lib/createArtifacts.ts","../src/lib/createThumbnail.ts","../src/lib/createForm.ts","../src/lib/createHeadless.ts","../src/commands/dev.ts","../src/ui/DevUI.tsx","../src/server/requestHandler.ts","../src/lib/proxyCache.ts","../src/lib/constants.ts","../src/lib/wizardUrl.ts","../src/server/pythonExecutor.ts","../src/server/python-requirements.txt","../src/lib/pythonRuntime.ts","../shared/lib/execution.ts","../shared/lib/fileExtensions.ts","../shared/lib/proxy.ts","../src/chrome/launcher.ts","../src/hooks/useLogHistory.ts","../src/ui/CredentialSetupUI.tsx","../src/commands/encrypt.ts","../src/ui/EncryptUI.tsx","../src/lib/encryptionClient.ts","../src/lib/encryptHelpers.ts","../src/lib/encryptHeadless.ts","../shared/lib/validIcons.ts","../src/commands/icons.ts","../src/commands/report.ts","../src/lib/reportHelpers.ts","../src/commands/setupClaude.ts"],"sourcesContent":["import * as http from 'node:http';\nimport { applyProxyFromEnv } from './lib/proxyEnv.js';\nimport { createProgram } from './program.js';\n\napplyProxyFromEnv({ env: process.env, http });\n\ncreateProgram().parse();\n","export type ProxyEnvStatus = 'applied' | 'unavailable' | 'not-configured' | 'already-set';\n\nexport interface ProxyHttp {\n setGlobalProxyFromEnv?: (proxyEnv?: NodeJS.ProcessEnv) => unknown;\n}\n\nexport interface ApplyProxyFromEnvOptions {\n env: NodeJS.ProcessEnv;\n http: ProxyHttp;\n}\n\nexport const PROXY_UNAVAILABLE_HINT =\n \"If you're behind a proxy, upgrade Node to 24.14+ or set NODE_USE_ENV_PROXY=1 on a Node version that supports it.\";\n\nconst PROXY_VARS = ['HTTPS_PROXY', 'https_proxy', 'HTTP_PROXY', 'http_proxy'] as const;\n\nconst isSet = (value: string | undefined): boolean => value !== undefined && value !== '';\n\nlet status: ProxyEnvStatus = 'not-configured';\n\nexport function applyProxyFromEnv({ env, http }: ApplyProxyFromEnvOptions): ProxyEnvStatus {\n if (status === 'applied') {\n return status;\n }\n\n if (!PROXY_VARS.some((name) => isSet(env[name]))) {\n status = 'not-configured';\n } else if (isSet(env.NODE_USE_ENV_PROXY)) {\n status = 'already-set';\n } else if (typeof http.setGlobalProxyFromEnv !== 'function') {\n status = 'unavailable';\n } else {\n http.setGlobalProxyFromEnv(env);\n status = 'applied';\n }\n\n return status;\n}\n\nexport const getProxyEnvStatus = (): ProxyEnvStatus => status;\n","import { readFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { Command } from 'commander';\nimport { blockCommand } from './commands/block.js';\nimport { buildCommand } from './commands/build.js';\nimport { createCommand } from './commands/create.js';\nimport { devCommand } from './commands/dev.js';\nimport { encryptCommand } from './commands/encrypt.js';\nimport { iconsCommand } from './commands/icons.js';\nimport { reportCommand } from './commands/report.js';\nimport { setupClaudeCommand } from './commands/setupClaude.js';\n\nfunction readVersion(): string {\n const pkgPath = join(dirname(fileURLToPath(import.meta.url)), '..', 'package.json');\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8')) as { version: string };\n\n return pkg.version;\n}\n\nexport function createProgram(): Command {\n const program = new Command();\n\n program.name('appbuilder').description('Kizen plugin app builder').version(readVersion());\n\n createCommand(program);\n\n setupClaudeCommand(program);\n\n buildCommand(program);\n\n devCommand(program);\n\n encryptCommand(program);\n\n reportCommand(program);\n\n iconsCommand(program);\n\n blockCommand(program);\n\n return program;\n}\n","import { createElement } from 'react';\nimport { render } from 'ink';\nimport type { Command } from 'commander';\nimport { PluginValidationError } from '@kizenapps/packager';\nimport { copyToClipboard } from '../lib/clipboard.js';\nimport { exportBlock } from '../lib/exportBlock.js';\nimport { formatValidationIssues } from '../lib/formatValidationIssues.js';\nimport {\n createDefaultPushDeps,\n runPushHeadless,\n runTargetsHeadless,\n type PushCommandOptions,\n type TargetsCommandOptions,\n} from '../lib/pushHeadless.js';\nimport { PushUI } from '../ui/PushUI.js';\n\nconst describeError = (error: unknown): string => {\n if (error instanceof PluginValidationError) {\n return formatValidationIssues(error.issues);\n }\n\n return `Error: ${error instanceof Error ? error.message : String(error)}`;\n};\n\nexport function blockCommand(program: Command): void {\n const block = program.command('block').description('Work with plugin content blocks');\n\n block\n .command('export')\n .description('Print one packaged block as JSON for the Custom Block (AI Coded) paste editor')\n .argument('[api_name]', 'api_name of the block to export (optional when there is only one)')\n .option('--copy', 'also copy the JSON to the clipboard')\n .action(async (apiName: string | undefined, options: { copy?: boolean }) => {\n try {\n const { block: exported, warnings } = await exportBlock(process.cwd(), apiName);\n\n if (warnings.length > 0) {\n console.error(formatValidationIssues(warnings));\n }\n\n const json = JSON.stringify(exported, null, 2);\n\n console.log(json);\n\n if (options.copy) {\n console.error(\n (await copyToClipboard(json))\n ? `Copied block \"${exported.api_name}\" to the clipboard.`\n : \"Couldn't copy to the clipboard; use the JSON printed to stdout instead.\",\n );\n }\n } catch (error) {\n console.error(describeError(error));\n process.exitCode = 1;\n }\n });\n block\n .command('push')\n .description('Push a block to a Kizen dashboard, homepage or chart group dashlet')\n .argument('[api_name]', 'api_name of the block to push (optional when there is only one)')\n .option('-c, --credentials <path>', 'path to a credentials JSON file')\n .option('--profile <name>', 'stored credential profile to use')\n .option('--dashboard <id>', 'dashboard, homepage or chart group to push to')\n .option('--dashlet <id>', 'existing custom code dashlet to update (needs --dashboard)')\n .option('--create', 'create a new dashlet instead of updating one')\n .option('--dry-run', 'show the request without writing anything')\n .option('--yes', 'write without asking (headless runs are dry runs without it)')\n .option('--allow-production', 'allow headless writes to go/fmo')\n .option('--force', 'overwrite even if the block was edited in Kizen since the last push')\n .option('--forget', 'clear the remembered target for this block first')\n .option('--json', 'print a JSON result to stdout (always headless)')\n .action(async (apiName: string | undefined, options: PushCommandOptions) => {\n try {\n if (!process.stdin.isTTY || !process.stdout.isTTY || options.json === true) {\n await runPushHeadless(apiName, options, createDefaultPushDeps(process.cwd()));\n\n return;\n }\n\n const { waitUntilExit } = render(\n createElement(PushUI, {\n ...(apiName !== undefined && { apiName }),\n options,\n deps: createDefaultPushDeps(process.cwd()),\n }),\n { exitOnCtrlC: false },\n );\n\n await waitUntilExit();\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exitCode = 1;\n }\n });\n\n block\n .command('targets')\n .description('List the dashboards, homepages and chart groups a block can be pushed to')\n .option('-c, --credentials <path>', 'path to a credentials JSON file')\n .option('--profile <name>', 'stored credential profile to use')\n .option('--object <id>', 'list the chart groups of this custom object')\n .option('--json', 'print a JSON result to stdout')\n .action(async (options: TargetsCommandOptions) => {\n try {\n await runTargetsHeadless(options, createDefaultPushDeps(process.cwd()));\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exitCode = 1;\n }\n });\n}\n","/**\n * Best-effort system-clipboard copy with no third-party dependency. Used by the\n * `encrypt` command so the user can paste the envelope without the terminal's\n * soft-wrapping turning into real line breaks in the copied text.\n *\n * Only the encrypted envelope (ciphertext) is ever copied — never a plaintext\n * secret — so writing it to the clipboard is safe.\n */\nimport { spawn } from 'node:child_process';\nimport { platform } from 'node:process';\n\ninterface ClipboardCommand {\n cmd: string;\n args: string[];\n}\n\n/**\n * Clipboard tools to try, in order, for the current platform. Linux/other has\n * several candidates (Wayland first, then X11) since none is guaranteed.\n */\nfunction clipboardCommands(): ClipboardCommand[] {\n if (platform === 'darwin') {\n return [{ cmd: 'pbcopy', args: [] }];\n }\n\n if (platform === 'win32') {\n return [{ cmd: 'clip', args: [] }];\n }\n\n return [\n // wl-copy (Wayland) intentionally WITHOUT --foreground: the default forks a\n // background process that keeps serving the selection after this CLI exits.\n // --foreground would instead tie the selection to our process, so the 2s\n // kill-timeout below would terminate it and wipe the clipboard.\n { cmd: 'wl-copy', args: [] },\n { cmd: 'xclip', args: ['-selection', 'clipboard'] },\n { cmd: 'xsel', args: ['--clipboard', '--input'] },\n ];\n}\n\n/** How long to wait for a clipboard tool before giving up. Encryption has\n * already succeeded by the time we copy, so a tool that hangs (some Linux\n * xclip/xsel setups can) must never freeze the CLI — it just falls back. */\nconst CLIPBOARD_TIMEOUT_MS = 2000;\n\n/** Pipes `text` into one clipboard command. Resolves false (never rejects) on\n * any failure — a missing tool (ENOENT), a non-zero exit, a broken pipe, or a\n * tool that doesn't exit within the timeout. */\nfunction runClipboardCommand(text: string, { cmd, args }: ClipboardCommand): Promise<boolean> {\n return new Promise((resolve) => {\n let child;\n\n try {\n child = spawn(cmd, args, { stdio: ['pipe', 'ignore', 'ignore'] });\n } catch {\n // Spawn threw synchronously (e.g. invalid command) — nothing to clean up.\n resolve(false);\n\n return;\n }\n\n const spawned = child;\n let settled = false;\n\n function finish(ok: boolean): void {\n if (settled) {\n return;\n }\n\n settled = true;\n clearTimeout(timer);\n resolve(ok);\n }\n\n const timer = setTimeout(() => {\n spawned.kill();\n finish(false);\n }, CLIPBOARD_TIMEOUT_MS);\n\n // Don't let a pending clipboard timer keep the process alive on its own.\n timer.unref();\n\n spawned.on('error', () => {\n finish(false);\n });\n spawned.on('close', (code) => {\n finish(code === 0);\n });\n spawned.stdin.on('error', () => {\n finish(false);\n });\n\n try {\n spawned.stdin.end(text);\n } catch {\n finish(false);\n }\n });\n}\n\n/**\n * Copies `text` to the system clipboard, returning whether it succeeded. Tries\n * each platform candidate until one works; returns false if none is available.\n */\nexport async function copyToClipboard(text: string): Promise<boolean> {\n for (const command of clipboardCommands()) {\n if (await runClipboardCommand(text, command)) {\n return true;\n }\n }\n\n return false;\n}\n","import {\n BLOCKS_DIRECTORY_NAME,\n CONFIG_FILE_NAME,\n MANIFEST_FILE_NAME,\n sanitizeToAPIName,\n} from '@kizenapps/packager';\nimport type { Block, DeployablePlugin, FileContent, ValidationIssue } from '@kizenapps/packager';\nimport { packageLocalPlugin } from './runBuild.js';\n\nexport type BlockSelectionFailure = 'not_found' | 'ambiguous' | 'no_blocks';\n\nexport type BlockExportReason = BlockSelectionFailure | 'invalid_block';\n\nexport interface AvailableBlock {\n pluginApiName: string;\n apiName: string;\n}\n\nexport type BlockSelection =\n | { ok: true; block: Block; pluginApiName: string }\n | { ok: false; reason: BlockSelectionFailure; available: AvailableBlock[] };\n\nexport interface ExportedBlock {\n block: Block;\n pluginApiName: string;\n warnings: ValidationIssue[];\n}\n\nconst DIMENSION_FIELDS = ['min_w', 'max_w', 'min_h', 'max_h'] as const;\n\nconst DIMENSION_RANGES = [\n ['min_w', 'max_w'],\n ['min_h', 'max_h'],\n] as const;\n\nconst DEFAULT_SIZE_BOUNDS = {\n default_w: ['min_w', 'max_w'],\n default_h: ['min_h', 'max_h'],\n} as const;\n\ntype DefaultSizeField = keyof typeof DEFAULT_SIZE_BOUNDS;\n\nconst DEFAULT_SIZE_FIELDS = Object.keys(DEFAULT_SIZE_BOUNDS) as DefaultSizeField[];\n\nconst SIZE_FIELDS = [...DIMENSION_FIELDS, ...DEFAULT_SIZE_FIELDS] as const;\n\nconst AUTHORED_FIELDS = [...SIZE_FIELDS, 'host_chrome'] as const;\n\ntype AuthoredField = (typeof AUTHORED_FIELDS)[number];\n\nconst UNSUPPORTED_SEQUENCES = ['\\u0000', '{__ref:'];\n\nexport class BlockExportError extends Error {\n readonly reason: BlockExportReason;\n readonly available: AvailableBlock[];\n readonly field: string | undefined;\n\n constructor(\n reason: BlockExportReason,\n message: string,\n options: { available?: AvailableBlock[]; field?: string } = {},\n ) {\n super(message);\n this.name = 'BlockExportError';\n this.reason = reason;\n this.available = options.available ?? [];\n this.field = options.field;\n }\n}\n\nexport function formatAvailableBlocks(available: AvailableBlock[]): string {\n const multiplePlugins = new Set(available.map((entry) => entry.pluginApiName)).size > 1;\n\n return available\n .map((entry) => (multiplePlugins ? `${entry.pluginApiName}/${entry.apiName}` : entry.apiName))\n .join(', ');\n}\n\nexport function selectBlock(deployable: DeployablePlugin[], apiName?: string): BlockSelection {\n const candidates = deployable.flatMap((plugin) =>\n plugin.artifacts.custom_blocks.map((block) => ({ block, pluginApiName: plugin.api_name })),\n );\n const available = candidates.map(({ block, pluginApiName }) => ({\n pluginApiName,\n apiName: block.api_name,\n }));\n\n if (candidates.length === 0) {\n return { ok: false, reason: 'no_blocks', available };\n }\n\n if (apiName === undefined) {\n const [only] = candidates;\n\n return candidates.length === 1 && only\n ? { ok: true, ...only }\n : { ok: false, reason: 'ambiguous', available };\n }\n\n const matches = candidates.filter(({ block }) => block.api_name === apiName);\n const [match] = matches;\n\n if (!match) {\n return { ok: false, reason: 'not_found', available };\n }\n\n if (matches.length > 1) {\n return {\n ok: false,\n reason: 'ambiguous',\n available: matches.map(({ block, pluginApiName }) => ({\n pluginApiName,\n apiName: block.api_name,\n })),\n };\n }\n\n return { ok: true, ...match };\n}\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value);\n\nconst isPositiveInteger = (value: unknown): boolean =>\n typeof value === 'number' && Number.isInteger(value) && value > 0;\n\nconst hasUnsupportedContent = (value: string): boolean =>\n UNSUPPORTED_SEQUENCES.some((sequence) => value.includes(sequence));\n\nexport function findInvalidBlockField(block: Block): string | undefined {\n const raw = block as unknown as Record<string, unknown>;\n const { name, script, styles, event_scripts: eventScripts } = raw;\n\n if (typeof script !== 'string' || !script.trim()) {\n return 'script';\n }\n\n if (name !== undefined && typeof name !== 'string') {\n return 'name';\n }\n\n if (styles !== undefined && typeof styles !== 'string') {\n return 'styles';\n }\n\n if (eventScripts !== undefined) {\n if (!isRecord(eventScripts)) {\n return 'event_scripts';\n }\n\n const invalidEntry = Object.entries(eventScripts).find(\n ([eventName, body]) =>\n typeof body !== 'string' || hasUnsupportedContent(eventName) || hasUnsupportedContent(body),\n );\n\n if (invalidEntry) {\n return `event_scripts.${invalidEntry[0]}`;\n }\n }\n\n const unsupported = (\n [\n ['name', name],\n ['script', script],\n ['styles', styles],\n ] as const\n ).find(([, value]) => typeof value === 'string' && hasUnsupportedContent(value));\n\n if (unsupported) {\n return unsupported[0];\n }\n\n const invalidDimension = DIMENSION_FIELDS.find(\n (field) => raw[field] !== undefined && !isPositiveInteger(raw[field]),\n );\n\n if (invalidDimension) {\n return invalidDimension;\n }\n\n const invertedMin = DIMENSION_RANGES.find(([minField, maxField]) => {\n const min = raw[minField];\n const max = raw[maxField];\n\n return typeof min === 'number' && typeof max === 'number' && min > max;\n });\n\n if (invertedMin) {\n return invertedMin[0];\n }\n\n const invalidDefault = DEFAULT_SIZE_FIELDS.find((field) => {\n const value = raw[field];\n\n if (value === undefined) {\n return false;\n }\n\n if (typeof value !== 'number' || !isPositiveInteger(value)) {\n return true;\n }\n\n const [minField, maxField] = DEFAULT_SIZE_BOUNDS[field];\n const min = raw[minField];\n const max = raw[maxField];\n\n return (typeof min === 'number' && value < min) || (typeof max === 'number' && value > max);\n });\n\n if (invalidDefault) {\n return invalidDefault;\n }\n\n if (raw.host_chrome !== undefined && typeof raw.host_chrome !== 'boolean') {\n return 'host_chrome';\n }\n\n return undefined;\n}\n\nexport const invalidBlockMessage = (apiName: string, field: string): string => {\n if (field === 'script') {\n return `Block \"${apiName}\" has no script. Add a non-empty script.js to the block directory.`;\n }\n\n if (field === 'host_chrome') {\n return `Block \"${apiName}\" has an invalid host_chrome: it must be true or false.`;\n }\n\n const range = DIMENSION_RANGES.find(([minField]) => minField === field);\n\n if (range) {\n return `Block \"${apiName}\" has an invalid ${field}: it must be a positive integer no greater than ${range[1]}.`;\n }\n\n if ((DIMENSION_FIELDS as readonly string[]).includes(field)) {\n return `Block \"${apiName}\" has an invalid ${field}: it must be a positive integer.`;\n }\n\n if (field in DEFAULT_SIZE_BOUNDS) {\n const [minField, maxField] = DEFAULT_SIZE_BOUNDS[field as DefaultSizeField];\n\n return `Block \"${apiName}\" has an invalid ${field}: it must be a positive integer between ${minField} and ${maxField}.`;\n }\n\n return `Block \"${apiName}\" has an invalid ${field}: it must be a string without NUL characters or \"{__ref:\".`;\n};\n\nexport const selectionError = (\n selection: Extract<BlockSelection, { ok: false }>,\n apiName: string | undefined,\n): BlockExportError => {\n const { reason, available } = selection;\n const list = formatAvailableBlocks(available);\n\n if (reason === 'no_blocks') {\n return new BlockExportError(\n reason,\n 'This plugin has no blocks. Scaffold one with `appbuilder create --artifacts block`.',\n { available },\n );\n }\n\n if (reason === 'not_found') {\n return new BlockExportError(\n reason,\n `No block with api_name \"${apiName ?? ''}\". Available blocks: ${list}`,\n { available },\n );\n }\n\n return new BlockExportError(\n reason,\n apiName === undefined\n ? `This plugin has several blocks; pass the api_name of the one to export: ${list}`\n : `More than one plugin has a block with api_name \"${apiName}\": ${list}`,\n { available },\n );\n};\n\nconst parseJsonRecord = (content: string): Record<string, unknown> | undefined => {\n try {\n const parsed: unknown = JSON.parse(content);\n\n return isRecord(parsed) ? parsed : undefined;\n } catch {\n return undefined;\n }\n};\n\nconst manifestEntries = (files: readonly FileContent[]): Map<string, string> => {\n const manifestFile = files.find((file) => file.path === MANIFEST_FILE_NAME);\n const parsed: unknown = manifestFile ? JSON.parse(manifestFile.content) : [];\n const manifests: unknown[] = Array.isArray(parsed) ? parsed : [parsed];\n const entries = new Map<string, string>();\n\n for (const manifest of manifests) {\n if (\n isRecord(manifest) &&\n typeof manifest.api_name === 'string' &&\n typeof manifest.entry === 'string'\n ) {\n entries.set(manifest.api_name, manifest.entry);\n }\n }\n\n return entries;\n};\n\nconst authoredBlockConfig = (\n files: readonly FileContent[],\n entry: string,\n): Map<string, Partial<Record<AuthoredField, unknown>>> => {\n const prefix = `${entry.replace(/\\/+$/, '')}/${BLOCKS_DIRECTORY_NAME}/`;\n const authoredByApiName = new Map<string, Partial<Record<AuthoredField, unknown>>>();\n\n for (const file of files) {\n if (!file.path.startsWith(prefix)) {\n continue;\n }\n\n const [directory, fileName, ...rest] = file.path.slice(prefix.length).split('/');\n\n if (!directory || fileName !== CONFIG_FILE_NAME || rest.length > 0) {\n continue;\n }\n\n const config = parseJsonRecord(file.content);\n\n if (!config) {\n continue;\n }\n\n const apiName =\n typeof config.api_name === 'string' && config.api_name !== ''\n ? config.api_name\n : sanitizeToAPIName(directory);\n const authored: Partial<Record<AuthoredField, unknown>> = {};\n\n for (const field of AUTHORED_FIELDS) {\n if (config[field] !== undefined) {\n authored[field] = config[field];\n }\n }\n\n authoredByApiName.set(apiName, authored);\n }\n\n return authoredByApiName;\n};\n\nconst withAuthoredConfig = (\n block: Block,\n authored: Partial<Record<AuthoredField, unknown>> = {},\n): Block => {\n const packaged = Object.fromEntries(\n Object.entries(block).filter(([key]) => !(AUTHORED_FIELDS as readonly string[]).includes(key)),\n );\n\n return { ...packaged, ...authored } as unknown as Block;\n};\n\nexport function applyAuthoredConfig(\n deployable: DeployablePlugin[],\n files: readonly FileContent[],\n): DeployablePlugin[] {\n const entries = manifestEntries(files);\n\n return deployable.map((plugin) => {\n const entry = entries.get(plugin.api_name);\n const authored =\n entry === undefined\n ? new Map<string, Partial<Record<AuthoredField, unknown>>>()\n : authoredBlockConfig(files, entry);\n\n return {\n ...plugin,\n artifacts: {\n ...plugin.artifacts,\n custom_blocks: plugin.artifacts.custom_blocks.map((block) =>\n withAuthoredConfig(block, authored.get(block.api_name)),\n ),\n },\n };\n });\n}\n\nexport async function packageBlocks(\n pluginDir: string,\n): Promise<{ deployable: DeployablePlugin[]; warnings: ValidationIssue[] }> {\n const { files, deployable, issues } = await packageLocalPlugin(pluginDir);\n\n return {\n deployable: applyAuthoredConfig(deployable, files),\n warnings: issues.filter((issue) => issue.severity === 'warning'),\n };\n}\n\nexport async function exportBlock(pluginDir: string, apiName?: string): Promise<ExportedBlock> {\n const { deployable, warnings } = await packageBlocks(pluginDir);\n const selection = selectBlock(deployable, apiName);\n\n if (!selection.ok) {\n throw selectionError(selection, apiName);\n }\n\n const invalidField = findInvalidBlockField(selection.block);\n\n if (invalidField !== undefined) {\n throw new BlockExportError(\n 'invalid_block',\n invalidBlockMessage(selection.block.api_name, invalidField),\n { field: invalidField },\n );\n }\n\n return { block: selection.block, pluginApiName: selection.pluginApiName, warnings };\n}\n","import { mkdir, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport {\n PluginValidationError,\n packagePlugin,\n parseManifestFromFiles,\n transformDeployablePlugin,\n transformFiles,\n validatePluginApp,\n} from '@kizenapps/packager';\nimport type { DeployablePlugin, FileContent, ValidationIssue } from '@kizenapps/packager';\nimport { readLocalFiles } from './readFiles.js';\n\nexport type BuildStepName =\n | 'creating-dir'\n | 'reading-files'\n | 'validating'\n | 'minifying'\n | 'packaging'\n | 'writing-bundle';\n\ninterface ReleaseNote {\n version: string;\n notes: string;\n}\n\ntype SerializableDeployablePlugin = Omit<DeployablePlugin, 'thumbnail' | 'kznFile'> & {\n thumbnail: string | null;\n kznFile: string | null;\n allReleaseNotes: ReleaseNote[];\n};\n\nconst serializePlugin = (\n plugin: DeployablePlugin,\n allReleaseNotes: ReleaseNote[],\n): SerializableDeployablePlugin => ({\n ...plugin,\n thumbnail: plugin.thumbnail ? Buffer.from(plugin.thumbnail).toString('base64') : null,\n kznFile: plugin.kznFile ? Buffer.from(plugin.kznFile).toString('base64') : null,\n allReleaseNotes,\n});\n\nexport interface BuildResult {\n bundleSize: number;\n}\n\nexport interface PackagedLocalPlugin {\n files: FileContent[];\n deployable: DeployablePlugin[];\n issues: ValidationIssue[];\n}\n\nexport async function packageLocalPlugin(\n pluginDir: string,\n onStep?: (step: BuildStepName) => void,\n): Promise<PackagedLocalPlugin> {\n onStep?.('reading-files');\n\n const files = await readLocalFiles(pluginDir);\n\n onStep?.('validating');\n\n const issues = validatePluginApp(files);\n\n if (issues.some((issue) => issue.severity === 'error')) {\n throw new PluginValidationError(issues);\n }\n\n onStep?.('minifying');\n\n const minified = await transformFiles(files);\n\n onStep?.('packaging');\n\n const manifests = parseManifestFromFiles(minified);\n const packaged = packagePlugin(minified, manifests);\n const deployable = Object.values(packaged).map(transformDeployablePlugin);\n\n return { files, deployable, issues };\n}\n\nexport async function runBuild(\n pluginDir: string,\n outputDir: string,\n onStep?: (step: BuildStepName) => void,\n): Promise<BuildResult> {\n await mkdir(outputDir, { recursive: true });\n\n const { files, deployable } = await packageLocalPlugin(pluginDir, onStep);\n\n onStep?.('writing-bundle');\n\n const bundle = deployable.map((plugin) => {\n const notesDir = plugin.release_notes_directory?.replace(/\\/$/, '');\n const allReleaseNotes: ReleaseNote[] = notesDir\n ? files\n .filter((f) => f.path.startsWith(notesDir + '/') && f.path.endsWith('.md') && f.content)\n .map((f) => ({\n version: f.path.slice(f.path.lastIndexOf('/') + 1, -3),\n notes: f.content,\n }))\n .sort((a, b) => b.version.localeCompare(a.version, undefined, { numeric: true }))\n : [];\n\n return serializePlugin(plugin, allReleaseNotes);\n });\n\n const jsonStr = JSON.stringify(bundle, null, 2);\n\n // Report the size of the plugin bundle excluding the informational release\n // notes, so \"bundle: 12KB\" reflects actual plugin code rather than long\n // markdown changelogs.\n const stripReleaseNotes = (key: string, value: unknown): unknown =>\n key === 'allReleaseNotes' ? undefined : value;\n const bundleSize = Buffer.byteLength(JSON.stringify(bundle, stripReleaseNotes, 2), 'utf-8');\n\n await writeFile(join(outputDir, 'bundle.json'), jsonStr, 'utf-8');\n\n return { bundleSize };\n}\n","import { readdir, readFile } from 'node:fs/promises';\nimport { join, relative } from 'node:path';\nimport type { FileContent } from '@kizenapps/packager';\n\nconst IMAGE_EXTENSIONS = new Set(['.png', '.svg']);\nconst BINARY_EXTENSIONS = new Set(['.kzn']);\nconst SKIP_FILES = new Set(['.DS_Store']);\n\nexport const SKIP_DIRS = new Set([\n 'node_modules',\n '.git',\n '.kizenapp',\n '.github',\n '.claude',\n '__pycache__',\n]);\n\n// a NUL in the first 8 KB means binary\nconst BINARY_SNIFF_BYTES = 8000;\n\nfunction looksBinary(buf: Buffer): boolean {\n return buf.subarray(0, BINARY_SNIFF_BYTES).includes(0);\n}\n\nexport interface ReadLocalFilesOptions {\n detectBinaryByContent?: boolean;\n}\n\nasync function walk(dir: string, rootDir: string): Promise<string[]> {\n const entries = await readdir(dir, { withFileTypes: true });\n const paths: string[] = [];\n\n for (const entry of entries) {\n if (entry.isDirectory()) {\n if (SKIP_DIRS.has(entry.name)) {\n continue;\n }\n\n paths.push(...(await walk(join(dir, entry.name), rootDir)));\n } else if (entry.isFile()) {\n if (!SKIP_FILES.has(entry.name)) {\n paths.push(join(dir, entry.name));\n }\n }\n }\n\n return paths;\n}\n\nexport async function readLocalFiles(\n rootDir: string,\n { detectBinaryByContent = false }: ReadLocalFilesOptions = {},\n): Promise<FileContent[]> {\n const absolutePaths = await walk(rootDir, rootDir);\n\n return Promise.all(\n absolutePaths.map(async (absPath): Promise<FileContent> => {\n const relPath = relative(rootDir, absPath).split('\\\\').join('/');\n const dotIndex = relPath.lastIndexOf('.');\n const ext = dotIndex >= 0 ? relPath.slice(dotIndex).toLowerCase() : '';\n\n if (IMAGE_EXTENSIONS.has(ext)) {\n const buf = await readFile(absPath);\n\n return { path: relPath, content: '', base64Image: buf.toString('base64') };\n }\n\n const buf = await readFile(absPath);\n\n if (BINARY_EXTENSIONS.has(ext) || (detectBinaryByContent && looksBinary(buf))) {\n return { path: relPath, content: '', binaryData: buf };\n }\n\n return { path: relPath, content: buf.toString('utf-8') };\n }),\n );\n}\n","import type { ValidationIssue } from '@kizenapps/packager';\n\nconst plural = (count: number, singular: string, pluralForm: string): string =>\n `${String(count)} ${count === 1 ? singular : pluralForm}`;\n\nconst groupIssuesByPath = (issues: ValidationIssue[]): Map<string, ValidationIssue[]> => {\n const groups = new Map<string, ValidationIssue[]>();\n\n for (const issue of issues) {\n const key = issue.path ?? issue.pluginApiName ?? 'general';\n const group = groups.get(key) ?? [];\n\n group.push(issue);\n groups.set(key, group);\n }\n\n return groups;\n};\n\nconst formatHeader = (issues: ValidationIssue[]): string => {\n const errorCount = issues.filter((issue) => issue.severity === 'error').length;\n const warningCount = issues.length - errorCount;\n\n if (errorCount === 0) {\n return `⚠ ${plural(warningCount, 'validation warning', 'validation warnings')}`;\n }\n\n const errors = `✗ ${plural(errorCount, 'validation error', 'validation errors')}`;\n\n return warningCount === 0 ? errors : `${errors}, ${plural(warningCount, 'warning', 'warnings')}`;\n};\n\nexport function formatValidationIssues(issues: ValidationIssue[]): string {\n if (issues.length === 0) {\n return '';\n }\n\n const sections = [...groupIssuesByPath(issues)].map(([path, group]) =>\n [\n path,\n ...group.map(\n (issue) => ` ${issue.severity === 'error' ? '✗' : '⚠'} ${issue.message} (${issue.rule})`,\n ),\n ].join('\\n'),\n );\n\n return [formatHeader(issues), ...sections].join('\\n\\n');\n}\n","import { randomUUID } from 'node:crypto';\nimport { join } from 'node:path';\nimport { PluginValidationError } from '@kizenapps/packager';\nimport type { Block, DeployablePlugin, ValidationIssue } from '@kizenapps/packager';\nimport { APP_URLS, isProductionEnvironment } from '../../shared/lib/kizenUrls.js';\nimport { loadConfig, type AppBuilderConfig } from './config.js';\nimport {\n ENVIRONMENTS,\n GLOBAL_CREDENTIALS_PATH,\n listLoadableCredentialProfiles,\n loadCredentialsDetailed,\n type CredentialProfile,\n type Credentials,\n type DetailedCredentials,\n type Environment,\n} from './credentials.js';\nimport {\n findInvalidBlockField,\n invalidBlockMessage,\n packageBlocks,\n selectBlock,\n formatAvailableBlocks,\n} from './exportBlock.js';\nimport { formatValidationIssues } from './formatValidationIssues.js';\nimport { ensureGitignore } from './gitignore.js';\nimport { createKizenClient, KizenApiError } from './kizenClient.js';\nimport type {\n CreateDashletBody,\n CustomCodeContent,\n KizenClient,\n PushMapEntry,\n Surface,\n UpdateDashletBody,\n WireCustomObject,\n WireDashboard,\n WireDashboardSummary,\n WireDashlet,\n} from './kizenTypes.js';\nimport {\n buildCreateBody,\n buildDashboardUrl,\n buildUpdateBody,\n canonicalContentHash,\n customCodeName,\n dashboardTypeToSurface,\n detectDrift,\n findCustomCodeDashlets,\n findPushMapEntry,\n isCustomCodeDashlet,\n matchPushTarget,\n parsePushKey,\n PUSH_MAP_RELATIVE_PATH,\n readPushMap,\n removePushMapEntry,\n toCustomCodeContent,\n upsertPushMapEntry,\n writePushMap,\n type PushMapKey,\n} from './pushBlock.js';\nimport { isClaudeSkillStale, STALE_CLAUDE_SKILL_WARNING } from './setupClaude.js';\n\nexport type PushErrorCode =\n | 'needs_choice'\n | 'validation_failed'\n | 'invalid_block'\n | 'auth_failed'\n | 'forbidden'\n | 'remembered_target_missing'\n | 'drift_detected'\n | 'network_error'\n | 'credentials_invalid'\n | 'production_requires_flag'\n | 'not_found'\n | 'usage_error'\n | 'api_error'\n | 'local_error';\n\nexport type ChoiceKind = 'profile' | 'block' | 'dashboard' | 'target';\n\nexport interface PushChoice {\n value: string;\n label: string;\n args: string[];\n surface?: Surface;\n canEdit?: boolean | null;\n pushKey?: string | null;\n isFromThisPlugin?: boolean;\n}\n\nexport interface PushFailure {\n ok: false;\n code: PushErrorCode;\n message: string;\n choice?: ChoiceKind;\n choices?: PushChoice[];\n issues?: ValidationIssue[];\n field?: string;\n hint?: string;\n}\n\nexport type Step<T> = { ok: true; value: T } | PushFailure;\n\nexport interface PushCommandOptions {\n credentials?: string;\n profile?: string;\n dashboard?: string;\n dashlet?: string;\n create?: boolean;\n dryRun?: boolean;\n yes?: boolean;\n allowProduction?: boolean;\n force?: boolean;\n forget?: boolean;\n json?: boolean;\n}\n\nexport interface TargetsCommandOptions {\n credentials?: string;\n profile?: string;\n object?: string;\n json?: boolean;\n}\n\nexport interface PushDeps {\n cwd: string;\n loadCredentialsDetailed: (path: string) => Promise<DetailedCredentials>;\n listLoadableCredentialProfiles: () => Promise<CredentialProfile[]>;\n loadConfig: (outputDir: string) => Promise<AppBuilderConfig>;\n packageBlocks: (\n dir: string,\n ) => Promise<{ deployable: DeployablePlugin[]; warnings: ValidationIssue[] }>;\n createClient: (credentials: Credentials) => KizenClient;\n readPushMap: (dir: string) => Promise<PushMapEntry[]>;\n writePushMap: (dir: string, entries: readonly PushMapEntry[]) => Promise<void>;\n ensureGitignore: (dir: string) => void;\n isClaudeSkillStale: (dir: string) => Promise<boolean>;\n randomUUID: () => string;\n now: () => Date;\n writeStdout: (text: string) => void;\n writeStderr: (text: string) => void;\n setExitCode: (code: number) => void;\n}\n\nexport function createDefaultPushDeps(cwd: string): PushDeps {\n return {\n cwd,\n loadCredentialsDetailed,\n listLoadableCredentialProfiles,\n loadConfig,\n packageBlocks,\n createClient: (credentials) => createKizenClient({ credentials }),\n readPushMap,\n writePushMap,\n ensureGitignore,\n isClaudeSkillStale: (dir) => isClaudeSkillStale(dir),\n randomUUID,\n now: () => new Date(),\n writeStdout: (text) => {\n process.stdout.write(text);\n },\n writeStderr: (text) => {\n process.stderr.write(text);\n },\n setExitCode: (code) => {\n process.exitCode = code;\n },\n };\n}\n\nconst EDIT_ACCESS_LEVELS = new Set(['owner', 'admin', 'edit']);\n\nconst CHART_GROUP_HINT =\n 'Chart groups are not listed here; find them with `appbuilder block targets --object <id> --json` and pass --dashboard <id>.';\n\nconst errorMessage = (error: unknown): string =>\n error instanceof Error ? error.message : typeof error === 'string' ? error : 'Unknown error';\n\nfunction failure(\n code: PushErrorCode,\n message: string,\n extra: Omit<PushFailure, 'ok' | 'code' | 'message'> = {},\n): PushFailure {\n return { ok: false, code, message, ...extra };\n}\n\nconst success = <T>(value: T): Step<T> => ({ ok: true, value });\n\nexport function apiFailure(error: unknown): PushFailure {\n if (error instanceof KizenApiError) {\n return failure(error.kind, error.message, error.hint === undefined ? {} : { hint: error.hint });\n }\n\n if (error instanceof PluginValidationError) {\n return failure('validation_failed', formatValidationIssues(error.issues), {\n issues: error.issues,\n });\n }\n\n return failure('local_error', errorMessage(error));\n}\n\nexport interface ResolvedCredentials {\n credentials: Credentials;\n source: { kind: 'file'; path: string } | { kind: 'profile'; name: string; path: string };\n}\n\nconst environmentList = (): string => ENVIRONMENTS.join(', ');\n\nasync function loadCredentialSource(\n source: ResolvedCredentials['source'],\n deps: PushDeps,\n): Promise<Step<ResolvedCredentials>> {\n let detailed: DetailedCredentials;\n\n try {\n detailed = await deps.loadCredentialsDetailed(source.path);\n } catch (error) {\n return failure(\n 'credentials_invalid',\n `Couldn't read credentials from ${source.path}: ${errorMessage(error)}`,\n );\n }\n\n if (detailed.environmentSource !== 'explicit') {\n const problem =\n detailed.environmentSource === 'missing'\n ? 'has no \"environment\"'\n : 'has an invalid \"environment\"';\n\n return failure(\n 'credentials_invalid',\n `${source.path} ${problem}. Set it to one of: ${environmentList()}. The CLI won't default to production.`,\n );\n }\n\n const { credentials } = detailed;\n const empty = (['apiKey', 'userId', 'businessId'] as const).filter(\n (field) => credentials[field].trim() === '',\n );\n\n if (empty.length > 0) {\n return failure(\n 'credentials_invalid',\n `${source.path} is missing ${empty.map((field) => `\"${field}\"`).join(', ')}.`,\n );\n }\n\n return success({ credentials, source });\n}\n\nconst profileSource = (profile: CredentialProfile): ResolvedCredentials['source'] => ({\n kind: 'profile',\n name: profile.name,\n path: profile.path,\n});\n\nexport async function resolveCredentials(\n options: { credentials?: string; profile?: string },\n deps: PushDeps,\n): Promise<Step<ResolvedCredentials>> {\n if (options.credentials !== undefined) {\n return loadCredentialSource({ kind: 'file', path: options.credentials }, deps);\n }\n\n const profiles = await deps.listLoadableCredentialProfiles();\n const names = profiles.map((profile) => profile.name);\n\n if (options.profile !== undefined) {\n const profile = profiles.find((candidate) => candidate.name === options.profile);\n\n if (!profile) {\n return failure(\n 'credentials_invalid',\n names.length === 0\n ? `No loadable credential profile named \"${options.profile}\". No profiles are loadable; create ${GLOBAL_CREDENTIALS_PATH} or pass -c <path>.`\n : `No loadable credential profile named \"${options.profile}\". Loadable profiles: ${names.join(', ')}`,\n );\n }\n\n return loadCredentialSource(profileSource(profile), deps);\n }\n\n const config = await deps.loadConfig(join(deps.cwd, '.kizenapp'));\n\n if (config.credentialMode === 'local') {\n return failure(\n 'credentials_invalid',\n \"This plugin is set to use local browser-only credentials the CLI can't read. Pass -c <path> or --profile <name>.\",\n );\n }\n\n const active =\n config.activeCredentialProfile === undefined\n ? undefined\n : profiles.find((candidate) => candidate.name === config.activeCredentialProfile);\n\n if (active) {\n return loadCredentialSource(profileSource(active), deps);\n }\n\n const [only] = profiles;\n\n if (profiles.length === 1 && only) {\n return loadCredentialSource(profileSource(only), deps);\n }\n\n if (profiles.length === 0) {\n return failure(\n 'credentials_invalid',\n `No credentials found. Create ${GLOBAL_CREDENTIALS_PATH} or pass -c <path>.`,\n );\n }\n\n return failure(\n 'needs_choice',\n `Several credential profiles are available; pass --profile <name>: ${names.join(', ')}`,\n {\n choice: 'profile',\n choices: profiles.map((profile) => ({\n value: profile.name,\n label: profile.isDefault ? `${profile.name} (default)` : profile.name,\n args: ['--profile', profile.name],\n })),\n },\n );\n}\n\nexport interface ResolvedBlock {\n block: Block;\n pluginApiName: string;\n content: CustomCodeContent;\n contentHash: string;\n warnings: ValidationIssue[];\n}\n\nfunction blockChoices(\n deployable: DeployablePlugin[],\n available: { pluginApiName: string; apiName: string }[],\n): PushChoice[] {\n const multiplePlugins = new Set(available.map((entry) => entry.pluginApiName)).size > 1;\n\n return available.map(({ pluginApiName, apiName }) => {\n const block = deployable\n .find((plugin) => plugin.api_name === pluginApiName)\n ?.artifacts.custom_blocks.find((candidate) => candidate.api_name === apiName);\n const qualified = multiplePlugins ? `${pluginApiName}/${apiName}` : apiName;\n\n return {\n value: apiName,\n label: `${block?.name ?? apiName} (${qualified})`,\n args: [apiName],\n };\n });\n}\n\nfunction blockSelectionMessage(\n selection: Extract<ReturnType<typeof selectBlock>, { ok: false }>,\n apiName: string | undefined,\n): string {\n const list = formatAvailableBlocks(selection.available);\n\n if (selection.reason === 'no_blocks') {\n return 'This plugin has no blocks. Scaffold one with `appbuilder create --artifacts block`.';\n }\n\n if (selection.reason === 'not_found') {\n return `No block with api_name \"${apiName ?? ''}\". Available blocks: ${list}`;\n }\n\n return apiName === undefined\n ? `This plugin has several blocks; pass the api_name of the one to push: ${list}`\n : `More than one plugin has a block with api_name \"${apiName}\": ${list}`;\n}\n\nexport async function resolveBlock(\n apiName: string | undefined,\n deps: PushDeps,\n): Promise<Step<ResolvedBlock>> {\n let packaged: { deployable: DeployablePlugin[]; warnings: ValidationIssue[] };\n\n try {\n packaged = await deps.packageBlocks(deps.cwd);\n } catch (error) {\n if (error instanceof PluginValidationError) {\n return failure('validation_failed', formatValidationIssues(error.issues), {\n issues: error.issues,\n });\n }\n\n throw error;\n }\n\n const selection = selectBlock(packaged.deployable, apiName);\n\n if (!selection.ok) {\n const message = blockSelectionMessage(selection, apiName);\n\n if (selection.reason === 'no_blocks') {\n return failure('invalid_block', message);\n }\n\n return failure('needs_choice', message, {\n choice: 'block',\n choices: blockChoices(packaged.deployable, selection.available),\n });\n }\n\n const field = findInvalidBlockField(selection.block);\n\n if (field !== undefined) {\n return failure('invalid_block', invalidBlockMessage(selection.block.api_name, field), {\n field,\n });\n }\n\n const content = toCustomCodeContent(selection.block);\n\n return success({\n block: selection.block,\n pluginApiName: selection.pluginApiName,\n content,\n contentHash: canonicalContentHash(content),\n warnings: packaged.warnings,\n });\n}\n\nexport interface TargetRow {\n id: string;\n name: string;\n type: Surface;\n dashletsCount: number | null;\n employeeAccess: string | null;\n hidden: boolean;\n canEdit: boolean | null;\n}\n\nexport interface TargetCustomObject {\n id: string;\n objectName: string;\n fetchUrl: string;\n}\n\nexport type TargetsResult =\n | {\n ok: true;\n environment: Environment;\n businessId: string;\n surfaces: { dashboard: TargetRow[]; homepage: TargetRow[] };\n customObjects: TargetCustomObject[];\n }\n | {\n ok: true;\n environment: Environment;\n businessId: string;\n object: TargetCustomObject | null;\n surfaces: { chart_group: TargetRow[] };\n };\n\nconst canEditFor = (employeeAccess: string | null | undefined): boolean | null =>\n employeeAccess === undefined || employeeAccess === null\n ? null\n : EDIT_ACCESS_LEVELS.has(employeeAccess.toLowerCase());\n\nexport function toTargetRow(summary: WireDashboardSummary, surface: Surface): TargetRow {\n return {\n id: summary.id,\n name: summary.name,\n type: surface,\n dashletsCount: summary.dashlets_count ?? null,\n employeeAccess: summary.employee_access ?? null,\n hidden: summary.hidden ?? false,\n canEdit: canEditFor(summary.employee_access),\n };\n}\n\nconst toTargetCustomObject = (object: WireCustomObject): TargetCustomObject => ({\n id: object.id,\n objectName: object.object_name,\n fetchUrl: object.fetch_url,\n});\n\nconst CONTACTS_OBJECT_NAME = 'Contacts';\n\nexport async function listPushableObjects(client: KizenClient): Promise<TargetCustomObject[]> {\n const [objects, clientObjectId] = await Promise.all([\n client.listCustomObjects(),\n client.getClientObjectId().catch((): null => null),\n ]);\n const pushable = objects\n .map(toTargetCustomObject)\n .sort((left, right) => left.objectName.localeCompare(right.objectName));\n\n if (\n clientObjectId !== null &&\n clientObjectId !== '' &&\n !pushable.some((object) => object.id === clientObjectId)\n ) {\n pushable.push({ id: clientObjectId, objectName: CONTACTS_OBJECT_NAME, fetchUrl: 'client' });\n }\n\n return pushable;\n}\n\nexport async function listTargets(\n client: KizenClient,\n credentials: Credentials,\n options: { object?: string },\n): Promise<Step<TargetsResult>> {\n const { environment, businessId } = credentials;\n\n try {\n if (options.object !== undefined) {\n const objectId = options.object;\n const [object, chartGroups] = await Promise.all([\n client.getCustomObject(objectId).catch((): null => null),\n client.listDashboards('chart_group', objectId),\n ]);\n\n return success({\n ok: true,\n environment,\n businessId,\n object: object ? toTargetCustomObject(object) : null,\n surfaces: { chart_group: chartGroups.map((row) => toTargetRow(row, 'chart_group')) },\n });\n }\n\n const [dashboards, homepages, customObjects] = await Promise.all([\n client.listDashboards('generic_dashboard'),\n client.listDashboards('homepage'),\n listPushableObjects(client),\n ]);\n\n return success({\n ok: true,\n environment,\n businessId,\n surfaces: {\n dashboard: dashboards.map((row) => toTargetRow(row, 'dashboard')),\n homepage: homepages.map((row) => toTargetRow(row, 'homepage')),\n },\n customObjects,\n });\n } catch (error) {\n return apiFailure(error);\n }\n}\n\nexport interface PushContext {\n client: KizenClient;\n credentials: Credentials;\n block: ResolvedBlock;\n pushMap: PushMapEntry[];\n entry: PushMapEntry | undefined;\n}\n\nexport type ResolvedBy = 'flag' | 'remembered' | 'push_map' | 'name';\n\nexport interface ResolvedTarget {\n dashboard: WireDashboard;\n surface: Surface;\n action: 'create' | 'update';\n dashlet: WireDashlet | undefined;\n resolvedBy: ResolvedBy;\n}\n\nconst isMemberDashlet = (dashboard: WireDashboard, dashlet: WireDashlet): boolean =>\n dashlet.dashboard === dashboard.id;\n\nexport function buildTargetChoices(dashboard: WireDashboard, block: ResolvedBlock): PushChoice[] {\n const existing = findCustomCodeDashlets(dashboard)\n .filter((dashlet) => isMemberDashlet(dashboard, dashlet))\n .map((dashlet): PushChoice => {\n const parsed = parsePushKey(dashlet.name);\n\n return {\n value: dashlet.id,\n label: customCodeName(dashlet),\n args: ['--dashboard', dashboard.id, '--dashlet', dashlet.id],\n pushKey: parsed ? dashlet.name : null,\n isFromThisPlugin: parsed?.pluginApiName === block.pluginApiName,\n };\n });\n\n return [\n ...existing,\n { value: 'new', label: 'Create a new block', args: ['--dashboard', dashboard.id, '--create'] },\n ];\n}\n\nfunction target(\n dashboard: WireDashboard,\n action: 'create' | 'update',\n dashlet: WireDashlet | undefined,\n resolvedBy: ResolvedBy,\n): Step<ResolvedTarget> {\n return success({\n dashboard,\n surface: dashboardTypeToSurface(dashboard.type),\n action,\n dashlet,\n resolvedBy,\n });\n}\n\nasync function chooseDashboard(context: PushContext): Promise<Step<ResolvedTarget>> {\n const [dashboards, homepages] = await Promise.all([\n context.client.listDashboards('generic_dashboard'),\n context.client.listDashboards('homepage'),\n ]);\n const toChoice =\n (surface: Surface) =>\n (summary: WireDashboardSummary): PushChoice => ({\n value: summary.id,\n label: summary.name,\n args: ['--dashboard', summary.id],\n surface,\n canEdit: canEditFor(summary.employee_access),\n });\n\n return failure(\n 'needs_choice',\n `Choose where to push; pass --dashboard <id>. ${CHART_GROUP_HINT}`,\n {\n choice: 'dashboard',\n choices: [...dashboards.map(toChoice('dashboard')), ...homepages.map(toChoice('homepage'))],\n },\n );\n}\n\nasync function resolveFlaggedDashboard(\n context: PushContext,\n dashboardId: string,\n options: PushCommandOptions,\n): Promise<Step<ResolvedTarget>> {\n const dashboard = await context.client.getDashboard(dashboardId);\n\n if (options.create) {\n return target(dashboard, 'create', undefined, 'flag');\n }\n\n const choices = (): PushChoice[] => buildTargetChoices(dashboard, context.block);\n\n if (options.dashlet !== undefined) {\n const dashletId = options.dashlet;\n const dashlet = dashboard.dashlets.find(\n (candidate) => candidate.id === dashletId && isMemberDashlet(dashboard, candidate),\n );\n\n if (!dashlet) {\n return failure(\n 'not_found',\n `Dashlet ${dashletId} is not on dashboard \"${dashboard.name}\" (${dashboard.id}).`,\n { choice: 'target', choices: choices() },\n );\n }\n\n if (!isCustomCodeDashlet(dashlet)) {\n return failure(\n 'usage_error',\n `Dashlet ${dashletId} is not a custom code block, so it can't be updated with a pushed block. Pass --create to add a new one.`,\n );\n }\n\n return target(dashboard, 'update', dashlet, 'flag');\n }\n\n const match = matchPushTarget({\n dashboardId: dashboard.id,\n dashlets: dashboard.dashlets,\n pluginApiName: context.block.pluginApiName,\n blockApiName: context.block.block.api_name,\n entry: context.entry,\n });\n\n if (match.kind === 'map') {\n return target(dashboard, 'update', match.dashlet, 'push_map');\n }\n\n if (match.kind === 'name') {\n return target(dashboard, 'update', match.dashlet, 'name');\n }\n\n return failure(\n 'needs_choice',\n match.kind === 'ambiguous'\n ? `Dashboard \"${dashboard.name}\" has ${String(match.dashlets.length)} blocks pushed from this block; pass --dashlet <id> to pick one, or --create.`\n : `Choose a block to update on \"${dashboard.name}\", or create a new one; pass --dashlet <id> or --create.`,\n { choice: 'target', choices: choices() },\n );\n}\n\nasync function resolveRemembered(\n context: PushContext,\n entry: PushMapEntry,\n options: PushCommandOptions,\n): Promise<Step<ResolvedTarget>> {\n let dashboard: WireDashboard;\n\n try {\n dashboard = await context.client.getDashboard(entry.dashboardId);\n } catch (error) {\n if (error instanceof KizenApiError && error.kind === 'not_found') {\n return failure(\n 'remembered_target_missing',\n `The remembered dashboard ${entry.dashboardId} no longer exists. Pass --dashboard <id> to choose another, or --forget to clear it.`,\n );\n }\n\n throw error;\n }\n\n if (options.create) {\n return target(dashboard, 'create', undefined, 'remembered');\n }\n\n const dashlet = dashboard.dashlets.find(\n (candidate) => candidate.id === entry.dashletId && isMemberDashlet(dashboard, candidate),\n );\n\n if (dashlet && isCustomCodeDashlet(dashlet)) {\n return target(dashboard, 'update', dashlet, 'remembered');\n }\n\n return failure(\n 'remembered_target_missing',\n `The remembered block (dashlet ${entry.dashletId}) is no longer on \"${dashboard.name}\". Choose a block to update, or create a new one.`,\n { choice: 'target', choices: buildTargetChoices(dashboard, context.block) },\n );\n}\n\nexport async function resolveTarget(\n context: PushContext,\n options: PushCommandOptions,\n): Promise<Step<ResolvedTarget>> {\n if (options.dashlet !== undefined && options.create) {\n return failure('usage_error', 'Pass either --dashlet <id> or --create, not both.');\n }\n\n if (options.dashlet !== undefined && options.dashboard === undefined) {\n return failure('usage_error', '--dashlet <id> needs --dashboard <id>.');\n }\n\n try {\n if (options.dashboard !== undefined) {\n return await resolveFlaggedDashboard(context, options.dashboard, options);\n }\n\n if (context.entry) {\n return await resolveRemembered(context, context.entry, options);\n }\n\n return await chooseDashboard(context);\n } catch (error) {\n return apiFailure(error);\n }\n}\n\nexport interface PushSummary {\n environment: Environment;\n businessId: string;\n isProduction: boolean;\n surface: Surface;\n dashboardId: string;\n dashboardName: string;\n action: 'create' | 'update';\n actionLine: string;\n dashletId: string | null;\n blockName: string;\n blockApiName: string;\n pluginApiName: string;\n scriptBytes: number;\n stylesBytes: number;\n}\n\nexport interface PushPlan {\n action: 'create' | 'update';\n method: 'POST' | 'PATCH';\n path: string;\n body: CreateDashletBody | UpdateDashletBody;\n dashboard: { id: string; name: string; type: Surface };\n dashletId: string | null;\n url: string;\n resolvedBy: ResolvedBy;\n summary: PushSummary;\n warnings: string[];\n}\n\nasync function customObjectOf(\n client: KizenClient,\n dashboard: WireDashboard,\n surface: Surface,\n): Promise<{ id: string; fetchUrl?: string } | null> {\n const raw: unknown = dashboard.custom_object;\n\n if (raw === null || raw === undefined || raw === '') {\n return null;\n }\n\n if (typeof raw !== 'string') {\n if (typeof raw !== 'object' || typeof (raw as { id?: unknown }).id !== 'string') {\n return null;\n }\n\n const { id, fetch_url: fetchUrl } = raw as { id: string; fetch_url?: unknown };\n\n return typeof fetchUrl === 'string' ? { id, fetchUrl } : { id };\n }\n\n if (surface !== 'chart_group') {\n return { id: raw };\n }\n\n try {\n const object = await client.getCustomObject(raw);\n\n return { id: raw, fetchUrl: object.fetch_url };\n } catch {\n return { id: raw };\n }\n}\n\nconst segment = encodeURIComponent;\n\nexport async function buildPlan(\n context: PushContext,\n resolved: ResolvedTarget,\n options: Pick<PushCommandOptions, 'force'>,\n deps: Pick<PushDeps, 'randomUUID'>,\n): Promise<Step<PushPlan>> {\n const { credentials, block } = context;\n const { dashboard, surface, dashlet } = resolved;\n const warnings: string[] = [];\n let body: CreateDashletBody | UpdateDashletBody;\n let path: string;\n let actionLine: string;\n\n if (resolved.action === 'update') {\n if (!dashlet) {\n return failure('usage_error', 'An update needs a dashlet to update.');\n }\n\n if (detectDrift(dashlet, context.entry)) {\n const drift = `\"${customCodeName(dashlet)}\" (dashlet ${dashlet.id}) was changed in Kizen since the last push.`;\n\n if (!options.force) {\n return failure(\n 'drift_detected',\n `${drift} Pushing would overwrite those changes; pass --force to overwrite them.`,\n );\n }\n\n warnings.push(`${drift} Overwriting it because of --force.`);\n }\n\n body = buildUpdateBody(dashlet, block.content);\n path = `/dashboards/${segment(dashboard.id)}/dashlet/${segment(dashlet.id)}`;\n actionLine = `Update \"${customCodeName(dashlet)}\" (dashlet ${dashlet.id})`;\n } else {\n body = buildCreateBody({\n pluginApiName: block.pluginApiName,\n blockApiName: block.block.api_name,\n content: block.content,\n dashlets: dashboard.dashlets,\n objectId: deps.randomUUID(),\n layoutId: deps.randomUUID(),\n });\n path = `/dashboards/${segment(dashboard.id)}/dashlet`;\n actionLine = `Create a new block on \"${dashboard.name}\"`;\n }\n\n const dashletId = resolved.action === 'update' && dashlet ? dashlet.id : null;\n const url = buildDashboardUrl({\n appBaseUrl: APP_URLS[credentials.environment],\n surface,\n dashboardId: dashboard.id,\n customObject: await customObjectOf(context.client, dashboard, surface),\n });\n\n return success({\n action: resolved.action,\n method: resolved.action === 'update' ? 'PATCH' : 'POST',\n path,\n body,\n dashboard: { id: dashboard.id, name: dashboard.name, type: surface },\n dashletId,\n url,\n resolvedBy: resolved.resolvedBy,\n warnings,\n summary: {\n environment: credentials.environment,\n businessId: credentials.businessId,\n isProduction: isProductionEnvironment(credentials.environment),\n surface,\n dashboardId: dashboard.id,\n dashboardName: dashboard.name,\n action: resolved.action,\n actionLine,\n dashletId,\n blockName: block.block.name,\n blockApiName: block.block.api_name,\n pluginApiName: block.pluginApiName,\n scriptBytes: Buffer.byteLength(block.content.script, 'utf8'),\n stylesBytes: Buffer.byteLength(block.content.styles, 'utf8'),\n },\n });\n}\n\nexport interface AppliedPush {\n dashletId: string;\n remembered: boolean;\n warnings: string[];\n}\n\nexport const pushMapKeyOf = (context: Pick<PushContext, 'credentials' | 'block'>): PushMapKey => ({\n environment: context.credentials.environment,\n businessId: context.credentials.businessId,\n pluginApiName: context.block.pluginApiName,\n blockApiName: context.block.block.api_name,\n});\n\nexport async function applyPlan(\n context: PushContext,\n plan: PushPlan,\n deps: PushDeps,\n): Promise<Step<AppliedPush>> {\n let dashletId: string;\n\n try {\n if (plan.action === 'create') {\n const created = await context.client.createDashlet(\n plan.dashboard.id,\n plan.body as CreateDashletBody,\n );\n\n const createdId: unknown = created.id;\n\n if (typeof createdId !== 'string' || createdId === '') {\n return failure(\n 'api_error',\n `POST ${plan.path} succeeded but the response had no dashlet id; check \"${plan.dashboard.name}\" before pushing again.`,\n );\n }\n\n dashletId = createdId;\n } else {\n if (plan.dashletId === null) {\n return failure('usage_error', 'An update needs a dashlet to update.');\n }\n\n await context.client.updateDashlet(plan.dashboard.id, plan.dashletId, plan.body);\n dashletId = plan.dashletId;\n }\n } catch (error) {\n return apiFailure(error);\n }\n\n const warnings = [...plan.warnings];\n const entry: PushMapEntry = {\n ...pushMapKeyOf(context),\n dashboardId: plan.dashboard.id,\n dashletId,\n contentHash: context.block.contentHash,\n pushedAt: deps.now().toISOString(),\n };\n let remembered = false;\n\n try {\n deps.ensureGitignore(deps.cwd);\n await deps.writePushMap(deps.cwd, upsertPushMapEntry(context.pushMap, entry));\n remembered = true;\n } catch (error) {\n warnings.push(\n `The push succeeded, but ${PUSH_MAP_RELATIVE_PATH} couldn't be written, so this target isn't remembered: ${errorMessage(error)}`,\n );\n }\n\n return success({ dashletId, remembered, warnings });\n}\n\nexport interface BrowserRefresh {\n dashboardId: string;\n script: string;\n}\n\nconst UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\nexport function buildBrowserRefresh(dashboardId: string): BrowserRefresh | null {\n if (!UUID_PATTERN.test(dashboardId)) {\n return null;\n }\n\n return {\n dashboardId,\n script: `await window.__kizenCustomBlocks?.refresh('${dashboardId}')`,\n };\n}\n\nexport async function forgetRemembered(\n context: Pick<PushContext, 'credentials' | 'block' | 'pushMap'>,\n deps: Pick<PushDeps, 'cwd' | 'writePushMap'>,\n): Promise<boolean> {\n const key = pushMapKeyOf(context);\n\n if (!findPushMapEntry(context.pushMap, key)) {\n return false;\n }\n\n await deps.writePushMap(deps.cwd, removePushMapEntry(context.pushMap, key));\n\n return true;\n}\n\nexport type WriteGate = { kind: 'dry-run'; reason: 'flag' | 'no_yes' } | { kind: 'apply' };\n\nexport function headlessWriteGate(\n options: PushCommandOptions,\n environment: Environment,\n): Step<WriteGate> {\n if (options.dryRun) {\n return success({ kind: 'dry-run', reason: 'flag' });\n }\n\n if (!options.yes) {\n return success({ kind: 'dry-run', reason: 'no_yes' });\n }\n\n if (isProductionEnvironment(environment) && !options.allowProduction) {\n return failure(\n 'production_requires_flag',\n `${environment} is a production environment. Pass --allow-production with --yes to write to it.`,\n );\n }\n\n return success({ kind: 'apply' });\n}\n\nexport const DRY_RUN_NOTE = 'Dry run only: pass --yes to write.';\n\nexport function formatSummaryLines(summary: PushSummary): string[] {\n return [\n `Environment: ${summary.environment}${summary.isProduction ? ' (production)' : ''}`,\n `Business: ${summary.businessId}`,\n `Surface: ${summary.surface}`,\n `Dashboard: \"${summary.dashboardName}\" (${summary.dashboardId})`,\n `Action: ${summary.actionLine}`,\n `Block: ${summary.blockName} (${summary.pluginApiName}/${summary.blockApiName})`,\n `Size: script ${String(summary.scriptBytes)} bytes, styles ${String(summary.stylesBytes)} bytes`,\n ];\n}\n\nconst formatIssueWarning = (issue: ValidationIssue): string =>\n `${issue.path === undefined ? '' : `${issue.path}: `}${issue.message} (${issue.rule})`;\n\nconst quoteArg = (arg: string): string => (/^[\\w./:@=-]+$/.test(arg) ? arg : JSON.stringify(arg));\n\ntype ChoiceArgs = (choice: PushChoice, kind: ChoiceKind | undefined) => string[];\n\nfunction formatFailureText(result: PushFailure, command: string, choiceArgs: ChoiceArgs): string {\n const lines = [`Error: ${result.message}`];\n\n if (result.hint !== undefined) {\n lines.push(`Hint: ${result.hint}`);\n }\n\n if (result.choices && result.choices.length > 0) {\n lines.push('Choices:');\n\n for (const choice of result.choices) {\n const args = choiceArgs(choice, result.choice).map(quoteArg).join(' ');\n\n lines.push(` ${choice.label} → ${command} ${args}`);\n }\n }\n\n return `${lines.join('\\n')}\\n`;\n}\n\ninterface Output {\n json: boolean;\n deps: PushDeps;\n}\n\nfunction writeFailure(\n output: Output,\n result: PushFailure,\n command: string,\n choiceArgs: ChoiceArgs,\n): void {\n if (output.json) {\n output.deps.writeStdout(`${JSON.stringify(result, null, 2)}\\n`);\n } else {\n output.deps.writeStderr(formatFailureText(result, command, choiceArgs));\n }\n\n output.deps.setExitCode(1);\n}\n\nconst credentialArgs = (options: { credentials?: string; profile?: string }): string[] => {\n if (options.credentials !== undefined) {\n return ['-c', options.credentials];\n }\n\n return options.profile === undefined ? [] : ['--profile', options.profile];\n};\n\nasync function claudeSkillWarnings(deps: PushDeps): Promise<string[]> {\n try {\n return (await deps.isClaudeSkillStale(deps.cwd)) ? [STALE_CLAUDE_SKILL_WARNING] : [];\n } catch {\n return [];\n }\n}\n\nexport async function runPushHeadless(\n apiName: string | undefined,\n options: PushCommandOptions,\n deps: PushDeps,\n): Promise<void> {\n const output: Output = { json: options.json === true, deps };\n const command = 'appbuilder block push';\n let blockArgs = apiName === undefined ? [] : [apiName];\n const choiceArgs: ChoiceArgs = (choice, kind) => {\n if (kind === 'profile') {\n return [...blockArgs, ...choice.args];\n }\n\n if (kind === 'block') {\n return [...choice.args, ...credentialArgs(options)];\n }\n\n return [...blockArgs, ...credentialArgs(options), ...choice.args];\n };\n\n const fail = (result: PushFailure): void => {\n writeFailure(output, result, command, choiceArgs);\n };\n\n try {\n const credentialStep = await resolveCredentials(options, deps);\n\n if (!credentialStep.ok) {\n fail(credentialStep);\n\n return;\n }\n\n const { credentials } = credentialStep.value;\n const client = deps.createClient(credentials);\n const blockStep = await resolveBlock(apiName, deps);\n\n if (!blockStep.ok) {\n fail(blockStep);\n\n return;\n }\n\n const block = blockStep.value;\n\n blockArgs = [block.block.api_name];\n\n if (block.warnings.length > 0) {\n deps.writeStderr(`${formatValidationIssues(block.warnings)}\\n`);\n }\n\n const context: PushContext = { client, credentials, block, pushMap: [], entry: undefined };\n\n context.pushMap = await deps.readPushMap(deps.cwd);\n\n let forgotten = false;\n\n if (options.forget) {\n forgotten = await forgetRemembered(context, deps);\n\n if (forgotten) {\n context.pushMap = removePushMapEntry(context.pushMap, pushMapKeyOf(context));\n deps.writeStderr(`Forgot the remembered target for ${block.block.api_name}.\\n`);\n }\n }\n\n context.entry = findPushMapEntry(context.pushMap, pushMapKeyOf(context));\n\n const targetStep = await resolveTarget(context, options);\n\n if (!targetStep.ok) {\n fail(targetStep);\n\n return;\n }\n\n const gateStep = headlessWriteGate(options, credentials.environment);\n\n if (!gateStep.ok) {\n fail(gateStep);\n\n return;\n }\n\n const planStep = await buildPlan(context, targetStep.value, options, deps);\n\n if (!planStep.ok) {\n fail(planStep);\n\n return;\n }\n\n const plan = planStep.value;\n const blockInfo = {\n pluginApiName: block.pluginApiName,\n apiName: block.block.api_name,\n name: block.block.name,\n };\n const common = {\n environment: credentials.environment,\n businessId: credentials.businessId,\n dashboard: plan.dashboard,\n };\n const issueWarnings = [\n ...block.warnings.map(formatIssueWarning),\n ...(await claudeSkillWarnings(deps)),\n ];\n const gate = gateStep.value;\n\n if (gate.kind === 'dry-run') {\n const warnings = [...issueWarnings, ...plan.warnings];\n const result = {\n ok: true as const,\n applied: false as const,\n dryRun: true as const,\n reason: gate.reason,\n action: plan.action,\n ...common,\n dashletId: plan.dashletId,\n url: plan.url,\n resolvedBy: plan.resolvedBy,\n block: blockInfo,\n method: plan.method,\n path: plan.path,\n body: plan.body,\n warnings,\n ...(forgotten ? { forgotten: true as const } : {}),\n };\n\n if (output.json) {\n deps.writeStdout(`${JSON.stringify(result, null, 2)}\\n`);\n deps.writeStderr(\n [...formatSummaryLines(plan.summary), ...warnings.map((w) => `Warning: ${w}`), ''].join(\n '\\n',\n ),\n );\n } else {\n deps.writeStdout(\n [\n ...formatSummaryLines(plan.summary),\n `URL: ${plan.url}`,\n ...warnings.map((warning) => `Warning: ${warning}`),\n '',\n `${plan.method} ${plan.path}`,\n JSON.stringify(plan.body, null, 2),\n '',\n ].join('\\n'),\n );\n }\n\n if (gate.reason === 'no_yes') {\n deps.writeStderr(`${DRY_RUN_NOTE}\\n`);\n }\n\n return;\n }\n\n const appliedStep = await applyPlan(context, plan, deps);\n\n if (!appliedStep.ok) {\n fail(appliedStep);\n\n return;\n }\n\n const applied = appliedStep.value;\n const warnings = [...issueWarnings, ...applied.warnings];\n const refresh = buildBrowserRefresh(plan.dashboard.id);\n const result = {\n ok: true as const,\n applied: true as const,\n dryRun: false as const,\n action: plan.action === 'create' ? ('created' as const) : ('updated' as const),\n ...common,\n dashletId: applied.dashletId,\n url: plan.url,\n ...(refresh ? { refresh } : {}),\n resolvedBy: plan.resolvedBy,\n block: blockInfo,\n remembered: applied.remembered,\n warnings,\n ...(forgotten ? { forgotten: true as const } : {}),\n };\n\n const text = [\n `✓ ${result.action === 'created' ? 'Created' : 'Updated'} ${block.block.name} on \"${plan.dashboard.name}\" (dashlet ${applied.dashletId})`,\n ...formatSummaryLines(plan.summary),\n `URL: ${plan.url}`,\n ...(refresh ? [`Refresh an open tab: ${refresh.script}`] : []),\n ...warnings.map((warning) => `Warning: ${warning}`),\n '',\n ].join('\\n');\n\n if (output.json) {\n deps.writeStdout(`${JSON.stringify(result, null, 2)}\\n`);\n deps.writeStderr(text);\n } else {\n deps.writeStdout(text);\n }\n } catch (error) {\n fail(apiFailure(error));\n }\n}\n\nconst pad = (value: string, width: number): string => value.padEnd(width);\n\nfunction formatTargetTable(title: string, rows: TargetRow[]): string[] {\n if (rows.length === 0) {\n return [title, ' (none)'];\n }\n\n const header = ['NAME', 'ID', 'DASHLETS', 'ACCESS'];\n const cells = rows.map((row) => [\n `${row.name}${row.hidden ? ' (hidden)' : ''}`,\n row.id,\n row.dashletsCount === null ? '-' : String(row.dashletsCount),\n `${row.employeeAccess ?? '-'}${row.canEdit === false ? ' (no edit access)' : ''}`,\n ]);\n const widths = header.map((label, index) =>\n Math.max(label.length, ...cells.map((cell) => (cell[index] ?? '').length)),\n );\n const line = (cell: string[]): string =>\n ` ${cell.map((value, index) => pad(value, widths[index] ?? 0)).join(' ')}`.trimEnd();\n\n return [title, line(header), ...cells.map(line)];\n}\n\nfunction formatTargetsText(result: TargetsResult): string {\n const lines = [`Environment: ${result.environment}`, `Business: ${result.businessId}`, ''];\n\n if ('object' in result) {\n lines.push(\n result.object === null\n ? 'Custom object: not found in /custom-objects'\n : `Custom object: ${result.object.objectName} (${result.object.id})`,\n '',\n ...formatTargetTable('Chart groups', result.surfaces.chart_group),\n );\n } else {\n lines.push(\n ...formatTargetTable('Dashboards', result.surfaces.dashboard),\n '',\n ...formatTargetTable('Homepages', result.surfaces.homepage),\n '',\n 'Custom objects',\n ...(result.customObjects.length === 0\n ? [' (none)']\n : result.customObjects.map((object) => ` ${object.objectName} ${object.id}`)),\n '',\n 'List an object’s chart groups with `appbuilder block targets --object <id>`.',\n );\n }\n\n return `${lines.join('\\n')}\\n`;\n}\n\nexport async function runTargetsHeadless(\n options: TargetsCommandOptions,\n deps: PushDeps,\n): Promise<void> {\n const output: Output = { json: options.json === true, deps };\n const command = 'appbuilder block targets';\n const objectArgs = options.object === undefined ? [] : ['--object', options.object];\n const choiceArgs: ChoiceArgs = (choice) => [...choice.args, ...objectArgs];\n const fail = (result: PushFailure): void => {\n writeFailure(output, result, command, choiceArgs);\n };\n\n try {\n const credentialStep = await resolveCredentials(options, deps);\n\n if (!credentialStep.ok) {\n fail(credentialStep);\n\n return;\n }\n\n const { credentials } = credentialStep.value;\n const targetsStep = await listTargets(\n deps.createClient(credentials),\n credentials,\n options.object === undefined ? {} : { object: options.object },\n );\n\n if (!targetsStep.ok) {\n fail(targetsStep);\n\n return;\n }\n\n deps.writeStdout(\n output.json\n ? `${JSON.stringify(targetsStep.value, null, 2)}\\n`\n : formatTargetsText(targetsStep.value),\n );\n } catch (error) {\n fail(apiFailure(error));\n }\n}\n","import type { Environment } from './credentials.js';\n\nexport const BASE_URLS: Record<Environment, string> = {\n go: 'https://app.go.kizen.com/api',\n fmo: 'https://app.fmo.kizen.com/api',\n staging: 'https://staging.kizen.com/api',\n integration: 'https://integration.kizen.dev/api',\n test1: 'https://test1.kizen.dev/api',\n};\n\nexport const APP_URLS: Record<Environment, string> = {\n go: 'https://go.kizen.com',\n fmo: 'https://fmo.kizen.com',\n staging: 'https://v2.staging.kizen.com',\n integration: 'https://v2.integration.kizen.dev',\n test1: 'https://test1.kizen.dev',\n};\n\nexport const PRODUCTION_ENVIRONMENTS: readonly Environment[] = ['go', 'fmo'];\n\nexport function isProductionEnvironment(env: Environment): boolean {\n return PRODUCTION_ENVIRONMENTS.includes(env);\n}\n","import { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nexport interface AppBuilderConfig {\n credentialMode?: 'global' | 'local';\n activeCredentialProfile?: string;\n lastPath?: string;\n // Which encryption API the Secrets page fetches public keys from. Defaults to\n // 'prod' when unset; 'dev' is an explicit per-project override (KZN-16467).\n // (A legacy 'auto' value may exist in older config files; it is read as the\n // 'prod' default — see GET /api/encryption-target.)\n encryptionTarget?: 'dev' | 'prod';\n}\n\nexport async function loadConfig(outputDir: string): Promise<AppBuilderConfig> {\n try {\n const content = await readFile(join(outputDir, 'config.json'), 'utf-8');\n\n return JSON.parse(content) as AppBuilderConfig;\n } catch {\n return {};\n }\n}\n\nexport async function saveConfig(outputDir: string, config: AppBuilderConfig): Promise<void> {\n await mkdir(outputDir, { recursive: true });\n\n await writeFile(join(outputDir, 'config.json'), JSON.stringify(config, null, 2), 'utf-8');\n}\n","import { mkdir, readFile, readdir, writeFile } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { dirname, join } from 'node:path';\nimport {\n ENVIRONMENTS,\n normalizeCredentialIds,\n type Environment,\n type Credentials,\n} from '../../shared/lib/credentials.js';\nexport {\n ENVIRONMENTS,\n cleanCredentialId,\n normalizeCredentialIds,\n type CredentialIds,\n type Environment,\n type Credentials,\n} from '../../shared/lib/credentials.js';\n\nexport interface CredentialProfile {\n name: string;\n path: string;\n isDefault: boolean;\n}\n\nexport const GLOBAL_CREDENTIALS_DIR = join(homedir(), '.kizenappbuilder');\nexport const GLOBAL_CREDENTIALS_PATH = join(GLOBAL_CREDENTIALS_DIR, 'credentials.json');\nexport const DEFAULT_PROFILE_NAME = 'credentials';\n\nfunction isValidEnvironment(value: unknown): value is Environment {\n return ENVIRONMENTS.includes(value as Environment);\n}\n\nfunction trimString(value: unknown): unknown {\n return typeof value === 'string' ? value.trim() : value;\n}\n\nfunction parseCredentials(raw: unknown): Credentials {\n if (typeof raw !== 'object' || raw === null) {\n throw new Error('Credentials must be a JSON object');\n }\n\n const obj = raw as Record<string, unknown>;\n const env = trimString(obj.environment);\n\n return {\n ...normalizeCredentialIds(obj),\n environment: isValidEnvironment(env) ? env : 'go',\n };\n}\n\nexport async function loadCredentialsFromFile(filePath: string): Promise<Credentials> {\n const content = await readFile(filePath, 'utf-8');\n\n return parseCredentials(JSON.parse(content) as unknown);\n}\n\nexport type EnvironmentSource = 'explicit' | 'missing' | 'invalid';\n\nexport interface DetailedCredentials {\n credentials: Credentials;\n environmentSource: EnvironmentSource;\n}\n\nfunction environmentSourceOf(raw: unknown): EnvironmentSource {\n const env = trimString((raw as Record<string, unknown>).environment);\n\n if (env === undefined || env === null || env === '') {\n return 'missing';\n }\n\n return isValidEnvironment(env) ? 'explicit' : 'invalid';\n}\n\nexport async function loadCredentialsDetailed(filePath: string): Promise<DetailedCredentials> {\n const content = await readFile(filePath, 'utf-8');\n const raw = JSON.parse(content) as unknown;\n const credentials = parseCredentials(raw);\n\n return { credentials, environmentSource: environmentSourceOf(raw) };\n}\n\nexport async function loadGlobalCredentials(): Promise<Credentials | null> {\n try {\n return await loadCredentialsFromFile(GLOBAL_CREDENTIALS_PATH);\n } catch {\n return null;\n }\n}\n\nexport async function saveGlobalCredentials(credentials: Credentials): Promise<void> {\n await mkdir(dirname(GLOBAL_CREDENTIALS_PATH), { recursive: true, mode: 0o700 });\n\n await writeFile(GLOBAL_CREDENTIALS_PATH, JSON.stringify(credentials, null, 2), {\n encoding: 'utf-8',\n mode: 0o600,\n });\n}\n\nexport function getProfilePath(name: string): string {\n return join(GLOBAL_CREDENTIALS_DIR, `${name}.json`);\n}\n\nexport async function listCredentialProfiles(): Promise<CredentialProfile[]> {\n const profiles: CredentialProfile[] = [\n { name: DEFAULT_PROFILE_NAME, path: GLOBAL_CREDENTIALS_PATH, isDefault: true },\n ];\n\n try {\n const entries = await readdir(GLOBAL_CREDENTIALS_DIR);\n\n for (const entry of entries) {\n if (!entry.endsWith('.json')) {\n continue;\n }\n\n const name = entry.slice(0, -5);\n\n if (name === DEFAULT_PROFILE_NAME) {\n continue;\n }\n\n profiles.push({ name, path: join(GLOBAL_CREDENTIALS_DIR, entry), isDefault: false });\n }\n } catch {\n // directory doesn't exist yet — only the default profile\n }\n\n return profiles;\n}\n\nexport async function saveCredentialProfile(name: string, credentials: Credentials): Promise<void> {\n if (name === DEFAULT_PROFILE_NAME) {\n await saveGlobalCredentials(credentials);\n\n return;\n }\n\n await mkdir(GLOBAL_CREDENTIALS_DIR, { recursive: true, mode: 0o700 });\n\n await writeFile(getProfilePath(name), JSON.stringify(credentials, null, 2), {\n encoding: 'utf-8',\n mode: 0o600,\n });\n}\n\nexport async function loadCredentialProfile(name: string): Promise<Credentials | null> {\n try {\n return await loadCredentialsFromFile(getProfilePath(name));\n } catch {\n return null;\n }\n}\n\nexport async function listLoadableCredentialProfiles(): Promise<CredentialProfile[]> {\n const profiles = await listCredentialProfiles();\n const loadable = await Promise.all(\n profiles.map((profile) =>\n loadCredentialsDetailed(profile.path).then(\n () => true,\n () => false,\n ),\n ),\n );\n\n return profiles.filter((_, index) => loadable[index] === true);\n}\n","export const ENVIRONMENTS = ['go', 'fmo', 'staging', 'integration', 'test1'] as const;\nexport type Environment = (typeof ENVIRONMENTS)[number];\n\nexport interface Credentials {\n apiKey: string;\n userId: string;\n businessId: string;\n environment: Environment;\n}\n\nexport type CredentialIds = Pick<Credentials, 'apiKey' | 'userId' | 'businessId'>;\n\nexport function cleanCredentialId(value: unknown): string {\n return typeof value === 'string' ? value.trim() : '';\n}\n\nexport function normalizeCredentialIds(\n values: Partial<Record<keyof CredentialIds, unknown>>,\n): CredentialIds {\n return {\n apiKey: cleanCredentialId(values.apiKey),\n userId: cleanCredentialId(values.userId),\n businessId: cleanCredentialId(values.businessId),\n };\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\n\nexport function ensureGitignore(projectDir: string): void {\n const gitignorePath = path.join(projectDir, '.gitignore');\n const entry = '.kizenapp/';\n\n let contents = '';\n\n if (fs.existsSync(gitignorePath)) {\n contents = fs.readFileSync(gitignorePath, 'utf8');\n\n const lines = contents.split('\\n').map((l) => l.trim());\n\n if (lines.includes(entry) || lines.includes('.kizenapp')) {\n return;\n }\n }\n\n const addition = contents.endsWith('\\n') ? entry + '\\n' : '\\n' + entry + '\\n';\n\n fs.writeFileSync(gitignorePath, contents + addition);\n}\n","import { BASE_URLS } from '../../shared/lib/kizenUrls.js';\nimport type { Credentials } from './credentials.js';\nimport type {\n CreateDashletBody,\n DashboardType,\n KizenApiErrorKind,\n KizenClient,\n UpdateDashletBody,\n WireCustomObject,\n WireDashboard,\n WireDashboardSummary,\n WireDashlet,\n} from './kizenTypes.js';\nimport { getProxyEnvStatus, PROXY_UNAVAILABLE_HINT } from './proxyEnv.js';\n\nexport interface KizenClientOptions {\n credentials: Credentials;\n fetch?: typeof fetch;\n baseUrl?: string;\n}\n\nconst AUTH_FAILED_HINT =\n \"The API key is invalid for this business, or the user id doesn't match. Check the credentials file's apiKey, userId and businessId.\";\n\nconst FORBIDDEN_HINT =\n \"The API key's user needs the Standard API Keys permission and edit access to this dashboard. Homepages also need the Customize Homepages permission.\";\n\ninterface ListPage {\n results: unknown[];\n next: unknown;\n}\n\nconst MAX_PAGES = 100;\n\nconst UNPREFIXED_KEYS = new Set(['detail', 'non_field_errors']);\n\nexport class KizenApiError extends Error {\n readonly kind: KizenApiErrorKind;\n readonly status: number | undefined;\n readonly hint: string | undefined;\n\n constructor(\n kind: KizenApiErrorKind,\n message: string,\n options: { status?: number; hint?: string } = {},\n ) {\n super(message);\n this.name = 'KizenApiError';\n this.kind = kind;\n this.status = options.status;\n this.hint = options.hint;\n }\n}\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value);\n\nfunction collectMessages(value: unknown, prefix: string, out: string[]): void {\n const push = (text: string): void => {\n out.push(prefix === '' ? text : `${prefix}: ${text}`);\n };\n\n if (typeof value === 'string') {\n if (value.trim() !== '') {\n push(value);\n }\n\n return;\n }\n\n if (typeof value === 'number' || typeof value === 'boolean') {\n push(String(value));\n\n return;\n }\n\n if (Array.isArray(value)) {\n const texts = value.filter(\n (item): item is string | number | boolean =>\n (typeof item === 'string' && item.trim() !== '') ||\n typeof item === 'number' ||\n typeof item === 'boolean',\n );\n\n if (texts.length > 0) {\n push(texts.map(String).join(' '));\n }\n\n for (const item of value) {\n if (typeof item === 'object' && item !== null) {\n collectMessages(item, prefix, out);\n }\n }\n\n return;\n }\n\n if (isRecord(value)) {\n for (const [key, child] of Object.entries(value)) {\n const childPrefix =\n prefix === '' && UNPREFIXED_KEYS.has(key) ? '' : prefix === '' ? key : `${prefix}.${key}`;\n\n collectMessages(child, childPrefix, out);\n }\n }\n}\n\nexport function formatDrfError(body: unknown): string | undefined {\n if (typeof body !== 'object' || body === null) {\n return undefined;\n }\n\n const messages: string[] = [];\n\n collectMessages(body, '', messages);\n\n return messages.length > 0 ? messages.join('; ') : undefined;\n}\n\nfunction errorCause(err: unknown): string {\n const e = err as { code?: string; message?: string; cause?: { code?: string; message?: string } };\n\n return e.cause?.code ?? e.code ?? e.cause?.message ?? e.message ?? String(err);\n}\n\nasync function readBody(res: Response): Promise<{ text: string; json: unknown }> {\n const text = await res.text();\n\n if (text === '') {\n return { text, json: undefined };\n }\n\n try {\n return { text, json: JSON.parse(text) as unknown };\n } catch {\n return { text, json: undefined };\n }\n}\n\nfunction statusError(method: string, path: string, status: number, body: unknown): KizenApiError {\n const detail = formatDrfError(body);\n const message = `${method} ${path} failed with ${String(status)}${detail === undefined ? '' : `: ${detail}`}`;\n\n if (status === 401) {\n return new KizenApiError('auth_failed', message, { status, hint: AUTH_FAILED_HINT });\n }\n\n if (status === 403) {\n return new KizenApiError('forbidden', message, { status, hint: FORBIDDEN_HINT });\n }\n\n if (status === 404) {\n return new KizenApiError('not_found', message, { status });\n }\n\n return new KizenApiError('api_error', message, { status });\n}\n\nfunction listResults(method: string, path: string, data: unknown): ListPage {\n if (Array.isArray(data)) {\n return { results: data, next: null };\n }\n\n if (isRecord(data) && Array.isArray(data.results)) {\n return { results: data.results, next: data.next };\n }\n\n throw new KizenApiError('api_error', `${method} ${path} returned an unexpected response shape`);\n}\n\nexport function createKizenClient(options: KizenClientOptions): KizenClient {\n const { credentials } = options;\n const fetchImpl = options.fetch ?? fetch;\n const baseUrl = options.baseUrl ?? BASE_URLS[credentials.environment];\n\n const request = async (method: string, target: string, body?: unknown): Promise<unknown> => {\n const url = /^https?:\\/\\//.test(target) ? target : `${baseUrl}${target}`;\n const path = url.startsWith(baseUrl) ? url.slice(baseUrl.length) : url;\n const headers: Record<string, string> = {\n 'X-API-KEY': credentials.apiKey,\n 'X-USER-ID': credentials.userId,\n 'X-BUSINESS-ID': credentials.businessId,\n Accept: 'application/json',\n };\n const init: RequestInit = { method, headers };\n\n if (body !== undefined) {\n headers['Content-Type'] = 'application/json';\n init.body = JSON.stringify(body);\n }\n\n let res: Response;\n\n try {\n res = await fetchImpl(url, init);\n } catch (err) {\n throw new KizenApiError(\n 'network_error',\n `Couldn't reach Kizen at ${baseUrl}: ${errorCause(err)}${getProxyEnvStatus() === 'unavailable' ? ` ${PROXY_UNAVAILABLE_HINT}` : ''}`,\n );\n }\n\n let text: string;\n let json: unknown;\n\n try {\n ({ text, json } = await readBody(res));\n } catch (err) {\n throw new KizenApiError(\n 'network_error',\n `${method} ${path}: couldn't read the response: ${errorCause(err)}. The request may have been applied; check Kizen before retrying.`,\n { status: res.status },\n );\n }\n\n if (!res.ok) {\n throw statusError(method, path, res.status, json);\n }\n\n if (json === undefined && text !== '') {\n throw new KizenApiError(\n 'api_error',\n `${method} ${path} returned a response that is not JSON`,\n { status: res.status },\n );\n }\n\n return json;\n };\n\n const segment = encodeURIComponent;\n\n const resolveNext = (next: string): string => {\n const base = new URL(baseUrl);\n const resolved = new URL(next, base.origin);\n\n if (resolved.hostname !== base.hostname) {\n throw new KizenApiError(\n 'api_error',\n `GET /custom-objects pagination pointed at an unexpected host ${resolved.hostname}`,\n );\n }\n\n return new URL(`${resolved.pathname}${resolved.search}`, base.origin).toString();\n };\n\n return {\n async listDashboards(type: DashboardType, customObjectId?: string) {\n const params = new URLSearchParams({\n size: '10000',\n include_sharing: 'true',\n dashboard_type: type,\n });\n\n if (customObjectId !== undefined) {\n params.set('custom_object_id', customObjectId);\n }\n\n const path = `/dashboards/mine?${params.toString()}`;\n\n return listResults('GET', path, await request('GET', path)).results as WireDashboardSummary[];\n },\n\n async listCustomObjects() {\n const all: WireCustomObject[] = [];\n const seen = new Set<string>();\n let target: string | undefined = '/custom-objects?page_size=200';\n\n while (target !== undefined && !seen.has(target) && seen.size < MAX_PAGES) {\n seen.add(target);\n\n const page: ListPage = listResults('GET', target, await request('GET', target));\n\n all.push(...(page.results as WireCustomObject[]));\n target =\n typeof page.next === 'string' && page.next !== '' ? resolveNext(page.next) : undefined;\n }\n\n return all;\n },\n\n async getCustomObject(id: string) {\n const path = `/custom-objects/${segment(id)}`;\n const data = await request('GET', path);\n\n if (!isRecord(data) || typeof data.id !== 'string' || typeof data.fetch_url !== 'string') {\n throw new KizenApiError('api_error', `GET ${path} returned an unexpected response shape`);\n }\n\n return data as unknown as WireCustomObject;\n },\n\n async getClientObjectId() {\n const data = await request('GET', '/auth/bootstrap');\n const business = isRecord(data) ? data.business : undefined;\n const clientObject = isRecord(business) ? business.client_object : undefined;\n const id = isRecord(clientObject) ? clientObject.id : undefined;\n\n return typeof id === 'string' && id !== '' ? id : null;\n },\n\n async getDashboard(id: string) {\n return (await request('GET', `/dashboards/${segment(id)}`)) as WireDashboard;\n },\n\n async createDashlet(dashboardId: string, body: CreateDashletBody) {\n return (await request(\n 'POST',\n `/dashboards/${segment(dashboardId)}/dashlet`,\n body,\n )) as WireDashlet;\n },\n\n async updateDashlet(dashboardId: string, dashletId: string, body: UpdateDashletBody) {\n return (await request(\n 'PATCH',\n `/dashboards/${segment(dashboardId)}/dashlet/${segment(dashletId)}`,\n body,\n )) as WireDashlet;\n },\n };\n}\n","import { createHash } from 'node:crypto';\nimport { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\nimport type { Block } from '@kizenapps/packager';\nimport { cleanCredentialId } from '../../shared/lib/credentials.js';\nimport type {\n CreateDashletBody,\n CustomCodeContent,\n DashboardType,\n DashletLayout,\n EventScriptEntry,\n PushMapEntry,\n Surface,\n UpdateDashletBody,\n WireDashboard,\n WireDashlet,\n} from './kizenTypes.js';\n\nexport const PUSH_NAME_PREFIX = 'appbuilder:';\n\nexport const PUSH_MAP_RELATIVE_PATH = '.kizenapp/pushes.json';\n\nconst DIMENSION_KEYS = ['min_w', 'max_w', 'min_h', 'max_h', 'default_w', 'default_h'] as const;\n\ntype DimensionKey = (typeof DIMENSION_KEYS)[number];\n\nconst PUSH_MAP_STRING_FIELDS = [\n 'environment',\n 'businessId',\n 'pluginApiName',\n 'blockApiName',\n 'dashboardId',\n 'dashletId',\n 'contentHash',\n 'pushedAt',\n] as const satisfies readonly (keyof PushMapEntry)[];\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction isFiniteNumber(value: unknown): value is number {\n return typeof value === 'number' && Number.isFinite(value);\n}\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.min(Math.max(value, min), max);\n}\n\nfunction withoutCustomObject(record: Record<string, unknown>): Record<string, unknown> {\n const rest = { ...record };\n\n delete rest.custom_object;\n\n return rest;\n}\n\nexport function pushKey(pluginApiName: string, blockApiName: string): string {\n return `${PUSH_NAME_PREFIX}${pluginApiName}/${blockApiName}`;\n}\n\nexport function parsePushKey(name: string): { pluginApiName: string; blockApiName: string } | null {\n if (!name.startsWith(PUSH_NAME_PREFIX)) {\n return null;\n }\n\n const parts = name.slice(PUSH_NAME_PREFIX.length).split('/');\n\n if (parts.length !== 2) {\n return null;\n }\n\n const [pluginApiName, blockApiName] = parts;\n\n if (!pluginApiName || !blockApiName) {\n return null;\n }\n\n return { pluginApiName, blockApiName };\n}\n\nfunction pickDimensions(source: Record<string, unknown>): Partial<Record<DimensionKey, number>> {\n const dimensions: Partial<Record<DimensionKey, number>> = {};\n\n for (const key of DIMENSION_KEYS) {\n const value = source[key];\n\n if (isFiniteNumber(value)) {\n dimensions[key] = value;\n }\n }\n\n return dimensions;\n}\n\nfunction pickHostChrome(source: Record<string, unknown>): { host_chrome?: boolean } {\n return typeof source.host_chrome === 'boolean' ? { host_chrome: source.host_chrome } : {};\n}\n\nexport function toCustomCodeContent(block: Block): CustomCodeContent {\n return {\n kind: 'custom_code',\n version: 1,\n name: block.name,\n script: block.script,\n styles: block.styles,\n event_scripts: Object.entries(block.event_scripts).map(([name, script]) => ({ name, script })),\n ...pickDimensions(block as unknown as Record<string, unknown>),\n ...pickHostChrome(block as unknown as Record<string, unknown>),\n };\n}\n\nexport function buildDashletConfig(args: {\n content: CustomCodeContent;\n objectId: string;\n}): Record<string, unknown> {\n return {\n object_id: args.objectId,\n entity_type: 'static_content',\n report_type: 'html',\n chart_type: 'html',\n content: args.content,\n fe_extra_info: {},\n };\n}\n\nexport function computeMaxBottom(dashlets: readonly WireDashlet[]): number {\n let maxBottom = 0;\n\n for (const dashlet of dashlets) {\n const layout: unknown = dashlet.layout;\n\n if (!isRecord(layout)) {\n continue;\n }\n\n const { y, h } = layout;\n\n if (!isFiniteNumber(y) || !isFiniteNumber(h)) {\n continue;\n }\n\n maxBottom = Math.max(maxBottom, y + h);\n }\n\n return maxBottom;\n}\n\nexport function computeCreateLayout(\n dashlets: readonly WireDashlet[],\n content: CustomCodeContent,\n layoutId: string,\n): DashletLayout {\n const w = clamp(content.default_w ?? content.min_w ?? 6, content.min_w ?? 1, content.max_w ?? 12);\n const h = clamp(content.default_h ?? content.min_h ?? 3, content.min_h ?? 1, content.max_h ?? 99);\n\n return {\n i: layoutId,\n x: 0,\n y: computeMaxBottom(dashlets),\n w: clamp(w, 2, 12),\n h: clamp(h, 1, 99),\n };\n}\n\nexport function buildCreateBody(args: {\n pluginApiName: string;\n blockApiName: string;\n content: CustomCodeContent;\n dashlets: readonly WireDashlet[];\n objectId: string;\n layoutId: string;\n}): CreateDashletBody {\n return {\n name: pushKey(args.pluginApiName, args.blockApiName),\n layout: computeCreateLayout(args.dashlets, args.content, args.layoutId),\n config: buildDashletConfig({\n content: args.content,\n objectId: args.objectId,\n }),\n };\n}\n\nexport function buildUpdateBody(\n existing: WireDashlet,\n content: CustomCodeContent,\n): UpdateDashletBody {\n const rawConfig: unknown = existing.config;\n const config = withoutCustomObject(isRecord(rawConfig) ? rawConfig : {});\n\n return {\n config: {\n ...config,\n content,\n },\n };\n}\n\nfunction contentOf(dashlet: WireDashlet): unknown {\n const config: unknown = dashlet.config;\n\n return isRecord(config) ? config.content : undefined;\n}\n\nexport function isCustomCodeDashlet(dashlet: WireDashlet): boolean {\n const config: unknown = dashlet.config;\n\n if (!isRecord(config) || config.chart_type !== 'html') {\n return false;\n }\n\n const content = config.content;\n\n return isRecord(content) && content.kind === 'custom_code';\n}\n\nexport function findCustomCodeDashlets(dashboard: Pick<WireDashboard, 'dashlets'>): WireDashlet[] {\n return dashboard.dashlets.filter(isCustomCodeDashlet);\n}\n\nexport function customCodeName(dashlet: WireDashlet): string {\n const content = contentOf(dashlet);\n\n if (isRecord(content) && typeof content.name === 'string') {\n return content.name;\n }\n\n return dashlet.name;\n}\n\nfunction normalizeEventScripts(value: unknown): EventScriptEntry[] {\n const stringOr = (candidate: unknown): string => (typeof candidate === 'string' ? candidate : '');\n\n if (Array.isArray(value)) {\n return value\n .filter(isRecord)\n .map((entry) => ({ name: stringOr(entry.name), script: stringOr(entry.script) }));\n }\n\n if (isRecord(value)) {\n return Object.entries(value).map(([name, script]) => ({ name, script: stringOr(script) }));\n }\n\n return [];\n}\n\nfunction sortKeysDeep(value: unknown): unknown {\n if (Array.isArray(value)) {\n return value.map(sortKeysDeep);\n }\n\n if (isRecord(value)) {\n const sorted: Record<string, unknown> = {};\n\n for (const key of Object.keys(value).sort()) {\n sorted[key] = sortKeysDeep(value[key]);\n }\n\n return sorted;\n }\n\n return value;\n}\n\nfunction nameOf(value: unknown): string {\n if (typeof value === 'string') {\n return value.trim();\n }\n\n if (typeof value === 'number' || typeof value === 'boolean') {\n return String(value).trim();\n }\n\n return '';\n}\n\nexport function canonicalContentHash(content: unknown): string {\n const source = isRecord(content) ? content : {};\n const canonical = {\n name: nameOf(source.name),\n script: typeof source.script === 'string' ? source.script : '',\n styles: typeof source.styles === 'string' ? source.styles : '',\n event_scripts: normalizeEventScripts(source.event_scripts),\n ...pickDimensions(source),\n ...pickHostChrome(source),\n };\n\n return createHash('sha256')\n .update(JSON.stringify(sortKeysDeep(canonical)))\n .digest('hex');\n}\n\nexport type TargetMatch =\n | { kind: 'map'; dashlet: WireDashlet; entry: PushMapEntry }\n | { kind: 'name'; dashlet: WireDashlet }\n | { kind: 'ambiguous'; dashlets: WireDashlet[] }\n | { kind: 'none' };\n\nexport function matchPushTarget(args: {\n dashboardId: string;\n dashlets: readonly WireDashlet[];\n pluginApiName: string;\n blockApiName: string;\n entry: PushMapEntry | undefined;\n}): TargetMatch {\n const { entry } = args;\n\n if (entry?.dashboardId === args.dashboardId) {\n const mapped = args.dashlets.find((dashlet) => dashlet.id === entry.dashletId);\n\n if (mapped && isCustomCodeDashlet(mapped)) {\n return { kind: 'map', dashlet: mapped, entry };\n }\n }\n\n const key = pushKey(args.pluginApiName, args.blockApiName);\n const named = args.dashlets.filter(\n (dashlet) => dashlet.name === key && isCustomCodeDashlet(dashlet),\n );\n const [first] = named;\n\n if (named.length === 1 && first) {\n return { kind: 'name', dashlet: first };\n }\n\n if (named.length > 1) {\n return { kind: 'ambiguous', dashlets: named };\n }\n\n return { kind: 'none' };\n}\n\nexport function detectDrift(dashlet: WireDashlet, entry: PushMapEntry | undefined): boolean {\n if (entry?.dashletId !== dashlet.id) {\n return false;\n }\n\n return canonicalContentHash(contentOf(dashlet)) !== entry.contentHash;\n}\n\nexport interface PushMapKey {\n environment: string;\n businessId: string;\n pluginApiName: string;\n blockApiName: string;\n}\n\nfunction matchesKey(entry: PushMapKey, key: PushMapKey): boolean {\n return (\n entry.environment === key.environment &&\n entry.businessId === key.businessId &&\n entry.pluginApiName === key.pluginApiName &&\n entry.blockApiName === key.blockApiName\n );\n}\n\nexport function findPushMapEntry(\n entries: readonly PushMapEntry[],\n key: PushMapKey,\n): PushMapEntry | undefined {\n return entries.find((entry) => matchesKey(entry, key));\n}\n\nexport function upsertPushMapEntry(\n entries: readonly PushMapEntry[],\n entry: PushMapEntry,\n): PushMapEntry[] {\n const index = entries.findIndex((candidate) => matchesKey(candidate, entry));\n\n if (index === -1) {\n return [...entries, entry];\n }\n\n return entries.map((candidate, candidateIndex) => (candidateIndex === index ? entry : candidate));\n}\n\nexport function removePushMapEntry(\n entries: readonly PushMapEntry[],\n key: PushMapKey,\n): PushMapEntry[] {\n return entries.filter((entry) => !matchesKey(entry, key));\n}\n\nfunction toPushMapEntry(value: unknown): PushMapEntry | null {\n if (!isRecord(value)) {\n return null;\n }\n\n for (const field of PUSH_MAP_STRING_FIELDS) {\n if (typeof value[field] !== 'string') {\n return null;\n }\n }\n\n const record = value as Record<(typeof PUSH_MAP_STRING_FIELDS)[number], string>;\n\n return {\n environment: record.environment,\n businessId: cleanCredentialId(record.businessId),\n pluginApiName: record.pluginApiName,\n blockApiName: record.blockApiName,\n dashboardId: record.dashboardId,\n dashletId: record.dashletId,\n contentHash: record.contentHash,\n pushedAt: record.pushedAt,\n };\n}\n\nconst pushedAtTime = (entry: PushMapEntry): number => Date.parse(entry.pushedAt) || 0;\n\nfunction latestPerKey(entries: readonly PushMapEntry[]): PushMapEntry[] {\n const byKey = new Map<string, PushMapEntry>();\n\n for (const entry of entries) {\n const id = [entry.environment, entry.businessId, entry.pluginApiName, entry.blockApiName].join(\n '\\u0000',\n );\n const current = byKey.get(id);\n\n if (current === undefined || pushedAtTime(entry) > pushedAtTime(current)) {\n byKey.set(id, entry);\n }\n }\n\n return [...byKey.values()];\n}\n\nconst isMissingFileError = (error: unknown): boolean =>\n error instanceof Error && (error as NodeJS.ErrnoException).code === 'ENOENT';\n\nconst pushMapErrorDetail = (error: unknown): string =>\n error instanceof Error ? error.message : String(error);\n\nexport async function readPushMap(pluginDir: string): Promise<PushMapEntry[]> {\n let raw: string;\n\n try {\n raw = await readFile(join(pluginDir, PUSH_MAP_RELATIVE_PATH), 'utf8');\n } catch (error) {\n if (isMissingFileError(error)) {\n return [];\n }\n\n throw new Error(\n `Couldn't read ${PUSH_MAP_RELATIVE_PATH}: ${pushMapErrorDetail(error)}. Fix its permissions, or delete it to start a fresh push map.`,\n );\n }\n\n let parsed: unknown;\n\n try {\n parsed = JSON.parse(raw);\n } catch (error) {\n throw new Error(\n `${PUSH_MAP_RELATIVE_PATH} is not valid JSON (${pushMapErrorDetail(error)}). Fix it, or delete it to start a fresh push map.`,\n );\n }\n\n if (!Array.isArray(parsed)) {\n throw new Error(\n `${PUSH_MAP_RELATIVE_PATH} must contain a JSON array of push entries. Fix it, or delete it to start a fresh push map.`,\n );\n }\n\n return latestPerKey(\n parsed.map(toPushMapEntry).filter((entry): entry is PushMapEntry => entry !== null),\n );\n}\n\nexport async function writePushMap(\n pluginDir: string,\n entries: readonly PushMapEntry[],\n): Promise<void> {\n const filePath = join(pluginDir, PUSH_MAP_RELATIVE_PATH);\n\n await mkdir(dirname(filePath), { recursive: true });\n await writeFile(filePath, `${JSON.stringify(entries, null, 2)}\\n`, 'utf8');\n}\n\nconst DASHBOARD_TYPE_TO_SURFACE: Record<DashboardType, Surface> = {\n generic_dashboard: 'dashboard',\n homepage: 'homepage',\n chart_group: 'chart_group',\n};\n\nconst SURFACE_TO_DASHBOARD_TYPE: Record<Surface, DashboardType> = {\n dashboard: 'generic_dashboard',\n homepage: 'homepage',\n chart_group: 'chart_group',\n};\n\nexport function dashboardTypeToSurface(type: DashboardType): Surface {\n return DASHBOARD_TYPE_TO_SURFACE[type];\n}\n\nexport function surfaceToDashboardType(surface: Surface): DashboardType {\n return SURFACE_TO_DASHBOARD_TYPE[surface];\n}\n\nexport function buildDashboardUrl(args: {\n appBaseUrl: string;\n surface: Surface;\n dashboardId: string;\n customObject?: { id: string; fetchUrl?: string } | null;\n}): string {\n const base = args.appBaseUrl.replace(/\\/+$/, '');\n const id = args.dashboardId;\n\n if (args.surface === 'homepage') {\n return `${base}/home/${id}`;\n }\n\n if (args.surface === 'chart_group' && args.customObject) {\n if (args.customObject.fetchUrl === 'client') {\n return `${base}/clients/charts/${id}`;\n }\n\n return `${base}/custom-objects/${args.customObject.id}/charts/${id}`;\n }\n\n return `${base}/dashboard/${id}`;\n}\n","import { access, mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { dirname, join, posix } from 'node:path';\nimport type { ScaffoldedFile } from './createArtifacts.js';\nimport { claudeFiles } from './createCopilotFiles.js';\n\nexport const CLAUDE_SKILL_PATH = '.claude/skills/kizen-custom-block/SKILL.md';\n\nexport const STALE_CLAUDE_SKILL_WARNING =\n 'Claude files managed by appbuilder are out of date; run appbuilder setup-claude';\n\nexport type ClaudeFileStatus = 'created' | 'updated' | 'unchanged';\n\nexport interface ClaudeFilePlan {\n path: string;\n status: ClaudeFileStatus;\n}\n\nexport interface ClaudeFs {\n readFile: (path: string) => Promise<string | undefined>;\n writeFile: (path: string, content: string) => Promise<void>;\n exists: (path: string) => Promise<boolean>;\n}\n\nconst isMissing = (error: unknown): boolean =>\n error instanceof Error && 'code' in error && error.code === 'ENOENT';\n\nexport const nodeClaudeFs: ClaudeFs = {\n readFile: async (path) => {\n try {\n return await readFile(path, 'utf-8');\n } catch (error) {\n if (isMissing(error)) {\n return undefined;\n }\n\n throw error;\n }\n },\n writeFile: async (path, content) => {\n await mkdir(dirname(path), { recursive: true });\n await writeFile(path, content, 'utf-8');\n },\n exists: async (path) => {\n try {\n await access(path);\n\n return true;\n } catch {\n return false;\n }\n },\n};\n\nconst normalizeEntryDir = (entry: unknown): string | undefined => {\n if (typeof entry !== 'string' || entry.trim() === '') {\n return undefined;\n }\n\n const normalized = posix.normalize(entry.trim().replaceAll('\\\\', '/')).replace(/\\/+$/, '');\n\n if (normalized === '..' || normalized.startsWith('../') || normalized.startsWith('/')) {\n return undefined;\n }\n\n return normalized === '.' ? '' : normalized;\n};\n\nexport function entryDirsOf(manifest: unknown): string[] {\n const manifests: unknown[] = Array.isArray(manifest) ? manifest : [manifest];\n const entryDirs = manifests\n .map((entry) =>\n typeof entry === 'object' && entry !== null && 'entry' in entry\n ? normalizeEntryDir(entry.entry)\n : undefined,\n )\n .filter((entryDir): entryDir is string => entryDir !== undefined);\n\n return entryDirs.length > 0 ? [...new Set(entryDirs)] : ['src'];\n}\n\nexport async function pluginClaudeFiles(\n dir: string,\n fs: ClaudeFs = nodeClaudeFs,\n): Promise<ScaffoldedFile[]> {\n try {\n const manifest = await fs.readFile(join(dir, 'kizen.json'));\n\n return claudeFiles(manifest === undefined ? undefined : entryDirsOf(JSON.parse(manifest)));\n } catch {\n return claudeFiles();\n }\n}\n\nconst statusOf = (current: string | undefined, bundled: string): ClaudeFileStatus => {\n if (current === undefined) {\n return 'created';\n }\n\n return current === bundled ? 'unchanged' : 'updated';\n};\n\nexport async function planClaudeFiles(\n dir: string,\n fs: ClaudeFs = nodeClaudeFs,\n files: readonly ScaffoldedFile[] = claudeFiles(),\n): Promise<ClaudeFilePlan[]> {\n return Promise.all(\n files.map(async (file) => ({\n path: file.path,\n status: statusOf(await fs.readFile(join(dir, file.path)), file.content),\n })),\n );\n}\n\nexport async function applyClaudeFiles(\n dir: string,\n options: { dryRun?: boolean } = {},\n fs: ClaudeFs = nodeClaudeFs,\n files: readonly ScaffoldedFile[] = claudeFiles(),\n): Promise<ClaudeFilePlan[]> {\n const plan = await planClaudeFiles(dir, fs, files);\n\n if (options.dryRun === true) {\n return plan;\n }\n\n await Promise.all(\n files\n .filter((_file, index) => plan[index]?.status !== 'unchanged')\n .map((file) => fs.writeFile(join(dir, file.path), file.content)),\n );\n\n return plan;\n}\n\nexport async function isClaudeSkillStale(\n dir: string,\n fs: ClaudeFs = nodeClaudeFs,\n files?: readonly ScaffoldedFile[],\n): Promise<boolean> {\n try {\n const managed = files ?? (await pluginClaudeFiles(dir, fs));\n\n if (!managed.some((file) => file.path === CLAUDE_SKILL_PATH)) {\n return false;\n }\n\n if ((await fs.readFile(join(dir, CLAUDE_SKILL_PATH))) === undefined) {\n return false;\n }\n\n const plan = await planClaudeFiles(dir, fs, managed);\n\n return plan.some((entry) => entry.status !== 'unchanged');\n } catch {\n return false;\n }\n}\n\nexport interface SetupClaudeDeps {\n fs: ClaudeFs;\n log: (line: string) => void;\n error: (line: string) => void;\n setExitCode: (code: number) => void;\n}\n\nexport const defaultSetupClaudeDeps: SetupClaudeDeps = {\n fs: nodeClaudeFs,\n log: (line) => {\n console.log(line);\n },\n error: (line) => {\n console.error(line);\n },\n setExitCode: (code) => {\n process.exitCode = code;\n },\n};\n\nconst count = (plan: readonly ClaudeFilePlan[], status: ClaudeFileStatus): string =>\n `${String(plan.filter((entry) => entry.status === status).length)} ${status}`;\n\nexport async function runSetupClaude(\n dir: string,\n options: { dryRun?: boolean },\n deps: SetupClaudeDeps = defaultSetupClaudeDeps,\n files?: readonly ScaffoldedFile[],\n): Promise<void> {\n if (!(await deps.fs.exists(join(dir, 'kizen.json')))) {\n deps.error('Error: kizen.json not found. Run this command from a plugin directory.');\n deps.setExitCode(1);\n\n return;\n }\n\n const dryRun = options.dryRun === true;\n let plan: ClaudeFilePlan[];\n\n try {\n plan = await applyClaudeFiles(\n dir,\n { dryRun },\n deps.fs,\n files ?? (await pluginClaudeFiles(dir, deps.fs)),\n );\n } catch (error) {\n deps.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n deps.setExitCode(1);\n\n return;\n }\n\n for (const entry of plan) {\n deps.log(`${entry.status.padEnd(9)} ${entry.path}`);\n }\n\n const counts = `${count(plan, 'created')}, ${count(plan, 'updated')}, ${count(plan, 'unchanged')}`;\n const managed = 'these files are managed by appbuilder, so local edits to them are replaced';\n\n deps.log(\n dryRun\n ? `Dry run: ${counts}; nothing written (${managed}).`\n : `Claude files: ${counts} (${managed}).`,\n );\n}\n","---\nname: kizen-custom-block\ndescription: Use this skill when the user asks to build, change or publish a Kizen content block, custom block, chart, or dashboard/homepage visualization in this plugin. It covers the block file layout, the plugin engine runtime rules, and the appbuilder validate, preview and push loop.\n---\n\n# Kizen custom blocks\n\nFollow these rules exactly. The runtime is strict, and a push changes a live Kizen dashlet.\n\n## Keep this skill current\n\nAt the start of any block task, run `appbuilder setup-claude` in the plugin directory.\n\n- If it reports `updated` for `.claude/skills/kizen-custom-block/SKILL.md`, your loaded copy of this skill is stale. Re-read `.claude/skills/kizen-custom-block/SKILL.md` before doing anything else, and follow the new copy.\n- If it reports `created` for any file, or `updated` for `.claude/skills/kizen-custom-block/design.md`, read that file before writing any markup or styles.\n- If it reports `created` or `updated` for `lib/kizenData.js` (under the plugin's entry directory, usually `src/`), re-read its exports before using them.\n- If every file line reports `unchanged`, continue.\n- If the command doesn't exist (an older CLI), skip it and continue.\n- If it fails (for example, you aren't in the plugin directory that holds `kizen.json`), switch to that directory and run it once more. If it still fails, continue without it.\n\n`setup-claude` only rewrites the CLI-managed files: the ones in this skill directory and `src/lib/kizenData.js`. It never touches block code, so it's always safe to run.\n\n## What a block is\n\nA block is a directory under `src/blocks/<dir>/`:\n\n- `config.json` (required): `name`, `api_name` (always set it explicitly), `types` (any of `homepages`, `dashboards`, `charts` for chart groups, and `records`; a block only appears on the surfaces it lists), and the optional sizes `min_w`, `max_w`, `min_h`, `max_h`, `default_w` and `default_h`. Widths are grid columns (1 to 12) and heights are grid rows. Each size you set is a positive integer, each `min_*` is no greater than its `max_*`, and each `default_*` falls within whichever of its `min_*` and `max_*` you set. `default_w` and `default_h` are the starting size when `block push` creates a new dashlet; updates never resize an existing dashlet. Only the sizes you write are exported and pushed.\n - `host_chrome` (optional boolean, default `true`): whether the host paints the dashlet card around the block. Omit it unless you are turning chrome off. Only a value you write is exported and pushed, and any value other than `true` or `false` fails validation.\n- `script.js` (required): the render script.\n- `styles.css` (optional).\n- `eventScripts/<name>.js` (optional): one file per interactive handler.\n\nShared helpers live in `src/lib/*.js`. Import them with relative named imports only, for example `import { formatMoney } from '../../lib/format.js';`. No default imports, no bare package names.\n\n`src/lib/kizenData.js` is managed by appbuilder: `setup-claude` and CLI updates replace it. Never edit it. Put your own helpers in another file under `src/lib/`.\n\n### Host chrome\n\nDecide the mode yourself from the request. Ask the user only if they already raised it and their choice is unclear.\n\n- Keep host chrome (omit `host_chrome`) for standard data dashlets such as charts, KPIs, tables and lists that should match native cards.\n- Set `\"host_chrome\": false` for full-bleed heroes, imagery, custom-shaped cards, or any design whose background is part of the visual.\n\nChrome off, in `config.json`:\n\n```json\n{\n \"name\": \"Welcome hero\",\n \"api_name\": \"welcome_hero\",\n \"types\": [\"homepages\", \"dashboards\"],\n \"host_chrome\": false\n}\n```\n\nFollow \"Chrome off\" in `design.md` for the layout rules. In your summary to the user, state which mode you chose and why in one line. `block push --dry-run --json` shows the value as `body.config.content.host_chrome` (absent when chrome is on by default), so check it there. Changing `host_chrome` on a block you already pushed is an ordinary update: validate, then `block push <api_name> --yes --json`.\n\n## Runtime rules\n\nBlocks run in the plugin engine web worker.\n\n- `script.js` is the body of an async function, and `this` is the worker context. Use `await` at the top level.\n- There is no DOM: no `document` or `window`. There are no npm packages. Don't use `eval` or `Function`.\n- Render with `this.outputUI(htmlString)`. The output is sanitized with DOMPurify, so `<script>` tags and `on*` attributes are stripped. Don't rely on them.\n- Charts are hand-built inline SVG strings. There are no chart libraries.\n- Interactivity: put `data-script=\"<eventScriptName>\"` on a `<button>` whose content is text only. Clicking it runs `eventScripts/<eventScriptName>.js` in a fresh worker, so no state carries over from `script.js`.\n- Args:\n - `this.args.dateFilter`: `{ start, end }`, or `undefined`.\n - `this.args.teamFilter`.\n - `this.args.objectId`: set on chart groups.\n - Homepages have no date or team filter. Handle both being absent.\n- Data: read records with the `kizenData.js` helpers (see \"Reading Kizen data\"). They call `this.getWithErrors` and `this.postWithErrors`, which use relative URLs and run as the viewing user.\n- Toasts: `this.showToast(message, options)`. `message` MUST be a string. Passing an object crashes the host app.\n- Styling:\n - The host applies `* { font-size: 10px }`. Set explicit px font sizes on everything.\n - With host chrome (the default), the host paints the card (background, border, border radius and shadow) from the dashboard's style settings, like native dashlets. The block root is transparent, fills the card, and paints no card of its own.\n - With `\"host_chrome\": false`, the host paints nothing: no background, border, radius or shadow. The block root fills the card edge to edge and owns its whole look (see \"Chrome off\" in `design.md`).\n - Put chart labels inside the SVG as `<text>` so they scale with the `viewBox`.\n- The code is stored in a Kizen dashlet. Never include a NUL character or the literal text `{__ref:` anywhere in any file.\n\n## Reading Kizen data\n\nRead records through `src/lib/kizenData.js`. Always import it from `../../lib/kizenData.js`. Its helpers take the worker context as their first argument, so pass `this`.\n\n- `getFields(this, object)` loads an object's fields. `object` is the object's id or name, and Contacts is `client_client`. Match fields by `name`.\n- `blockFilters(this.args, fields)` returns `{ filters, unapplied }`. Always apply `filters`, so the block reacts to the dashboard's date and team filters the way native dashlets do (date on `created`, team on `owner`). When `unapplied` contains `'teamFilter'`, the team filter couldn't be applied (a roles-only selection, or an object with no owner field). Show \"(team filter not applied)\".\n- `dropdownFilter(field, 'Name')` or `dropdownFilter(field, ['A', 'B'])` filters a dropdown by option names.\n- `searchRecords(this, { object, fieldNames, filters })` returns `{ records, count, truncated }`. When `truncated` is true, show \"Showing first N\" with N = `records.length`.\n- `fieldValue(record, name)`, `fieldLabel(record, name)`, `countBy(records, name, field?)`, `sumBy(records, name, valueOf?)` and `formatNumber(n, prefix)` read and summarize the results. `countBy` groups empty values under `key: ''`. Filter that group out, or give it a label.\n- Every record value or label you put into markup goes through `escapeHtml(value)`, including option names, owner names and text fields. `this.outputUI` sanitizes scripts, but it keeps images, links, forms and styles, and the block renders for every viewer. `escapeHtml` is the only escaping helper; never write your own.\n- Never hand-build filter or search JSON when a helper exists. Every helper throws a readable `Error`, so wrap the fetch in `try` and render the error state from `design.md`.\n\nCount Contacts by a dropdown field named `status` for the current dashboard filters. Use a field name from `getFields`:\n\n```js\nimport {\n blockFilters,\n countBy,\n escapeHtml,\n getFields,\n searchRecords,\n} from '../../lib/kizenData.js';\n\ntry {\n const fields = await getFields(this, 'client_client');\n const { filters, unapplied } = blockFilters(this.args, fields);\n const search = { object: 'client_client', fieldNames: ['status'], filters };\n const { records, count, truncated } = await searchRecords(this, search);\n const rows = countBy(records, 'status').filter((row) => row.key !== '');\n const items = rows.map((row) => `<li>${escapeHtml(row.label)}: ${row.count}</li>`).join('');\n const note = truncated ? `Showing first ${records.length} of ${count}. ` : '';\n const team = unapplied.includes('teamFilter') ? '(team filter not applied)' : '';\n this.outputUI(`<ul>${items}</ul><p>${note}${team}</p>`);\n} catch {\n this.outputUI('<div class=\"kz-state kz-state--error\">Couldn\\'t load data.</div>');\n}\n```\n\n## Design\n\nBefore writing any markup or styles, read `design.md` in this skill directory and follow it exactly.\n\n## The loop\n\nRun these exact commands. The flags and JSON keys are the contract. `<api_name>` is the block's `config.json` `api_name`. `block targets` and `block push` both accept `-c/--credentials <path>` and `--profile <name>` to pick the credential.\n\n1. **Validate.** Run `appbuilder block export <api_name>`. Fix every validation error it prints, then run it again until it passes.\n2. **Choose the target with the user (first publish only).**\n - `appbuilder block targets --json` returns `{ surfaces: { dashboard: [...], homepage: [...] }, customObjects: [{ id, objectName, fetchUrl }] }`. Contacts appears in `customObjects` when available.\n - `appbuilder block targets --object <id> --json` returns `{ surfaces: { chart_group: [...] } }` for that object.\n - Only offer rows where `canEdit !== false`. Ask the user which surface and which specific one. Don't pick for them.\n - Optionally run `appbuilder block push <api_name> --dashboard <id> --json` to get a `needs_choice` result listing the existing custom blocks and \"new\".\n3. **Preview.** Run `appbuilder block push <api_name> --dashboard <id> [--dashlet <id> | --create] --dry-run --json`. Show the user the `environment`, `businessId`, `dashboard.name`, `action` and any `warnings`.\n4. **Apply** once the user agrees: run the same command with `--yes` in place of `--dry-run`. Treat the push as done only when `applied === true`. Give the user the block URL (below), then refresh the browser (below).\n5. **Change requests.** Edit the files, validate again (step 1), then run `appbuilder block push <api_name> --yes --json`. With no target flags it updates the remembered dashlet. Refresh the browser (below) after each push. Repeat for each change.\n\nA headless run without `--yes` is always a dry run.\n\n### The block URL\n\nThe block URL is the result's `url`, with one exception: when the result's `environment` is `integration`, replace the origin of `url` with `https://pr-9378.integration.kizen.dev` and keep the path and query. For example, `https://v2.integration.kizen.dev/dashboard/<id>` becomes `https://pr-9378.integration.kizen.dev/dashboard/<id>`. Every other environment uses `url` unchanged. Use the block URL everywhere this skill says to give, open, match or navigate to the block's page. This exception is temporary for the test build and will be removed once the feature is on integration.\n\n### Refresh the browser after a push\n\nDo this after every applied push, only when Claude-in-Chrome tools are available. Dashlets don't poll, so the user's open tab keeps the old block until it's refreshed. Don't reload the page.\n\n1. List the open tabs (`tabs_context_mcp`) and find the one whose URL has the same origin and path as the block URL.\n2. If there is no such tab, open the block URL in a new tab (`tabs_create_mcp`) and go to step 5.\n3. If the result has a `refresh` field, run `refresh.script` exactly as given in that tab with the page JavaScript tool (`javascript_tool`). If it has no `refresh` field, navigate that tab to the block URL (`navigate`) and go to step 5.\n4. Check what the script returned:\n - `{ refreshed: true, ... }`: the dashboard refetched in place.\n - `undefined`: the refresh hook isn't available on this page. Navigate the tab to the block URL instead. Then run `localStorage.getItem('kizen-flag-custom-code-blocks')` in that tab with `javascript_tool`. If it isn't `'true'`, tell the user once per conversation that setting that localStorage key to `'true'` in the Kizen tab enables in-place refresh. Never set it yourself.\n5. Wait a couple of seconds, take a screenshot (`computer`), and check that the block rendered: not blank, and no visible error. Report what you saw to the user. If the block is blank or shows an error, read the console and fix the block before pushing again.\n\nNever run any other injected code in the user's tabs. `refresh.script` is the only script you may run, with one exception: the read-only `localStorage.getItem('kizen-flag-custom-code-blocks')` check above.\n\n### JSON results\n\n- Dry run: `{ ok: true, applied: false, dryRun: true, action: 'create' | 'update', environment, businessId, dashboard: { id, name, type }, dashletId | null, url, method, path, body, warnings }`.\n- Applied: `{ ok: true, applied: true, dryRun: false, action: 'created' | 'updated', ..., dashletId, url, refresh?: { dashboardId, script }, remembered }`. `refresh` is absent when the dashboard id isn't a uuid.\n- If a `block push` result's `warnings` contains `Claude files managed by appbuilder are out of date; run appbuilder setup-claude`, run `appbuilder setup-claude`, re-read `.claude/skills/kizen-custom-block/SKILL.md`, then continue.\n- Error: `{ ok: false, code, message, choice?, choices? }`. `code` is one of `needs_choice`, `validation_failed`, `invalid_block`, `auth_failed`, `forbidden`, `remembered_target_missing`, `drift_detected`, `network_error`, `credentials_invalid`, `production_requires_flag`, `not_found`, `usage_error`, `api_error` or `local_error`.\n\n### `needs_choice`\n\n`choice` is `'profile'`, `'block'`, `'dashboard'` or `'target'`. `choices` is a list of `{ value, label, args, surface?, canEdit?, pushKey?, isFromThisPlugin? }`, where `args` is a string array. Ask the user using each option's `label`, then re-run the same command with the chosen option's `args` appended exactly. Never construct these flags by hand. The \"new\" option is `{ value: 'new', args: ['--dashboard', <id>, '--create'] }`.\n\n## Guardrails\n\n- Never pass `--allow-production` unless the user explicitly asked, in this conversation, to publish to production (`go` or `fmo`).\n- On `drift_detected`, stop and ask the user. Someone edited the block in Kizen since your last push, and `--force` overwrites their changes. Pass `--force` only when the user says to discard them.\n- On `needs_choice`, ask the user using the returned `choices` as described above. Never guess.\n- On `remembered_target_missing`, the remembered dashboard or dashlet is gone. Ask the user where to publish instead, then push with `--dashboard <id>` plus `--create` or a `--dashlet` choice, or use `--forget` to clear the memory. `--create` alone won't work.\n- On `credentials_invalid`, tell the user to fix the credential file named in `message`, or to pass `--profile` or `-c`.\n- On `production_requires_flag`, the target is `go` or `fmo`. Apply the production rule above.\n- Never push to a new target without first showing the user a dry run.\n- Blocks run with the viewing user's permissions for every viewer. Don't write code that creates, updates or deletes data unless the user asked for it.\n","# Designing a Kizen custom block\n\nWith host chrome (the default), a block must look like a native Kizen dashlet. Follow every rule here exactly. Where a rule says \"use judgment\", pick the option that looks most native. A block whose `config.json` sets `\"host_chrome\": false` follows section M for its card and outer box, and skips every rule marked \"with host chrome\".\n\n## A. Card and outer box (with host chrome)\n\nThe host paints the card. Background, border, border radius and drop shadow all come from the dashboard's style settings, the same as native dashlets.\n\n- Never paint a card. The block root has no background (it stays transparent), no border, no `border-radius`, no `box-shadow` and no outer margin.\n- The block's content box starts at the card's top-left corner (0,0) and fills the whole card. The host body padding is 0. The root is always `width: 100%; height: 100%; box-sizing: border-box;`.\n- The host draws a 46px header overlay (`position: absolute`, padding `11px 15px 15px`) over the block's top edge. The dashlet menu appears at its top right on hover. The top-right strip, 60px wide and 46px tall from the card's top edge, must hold no interactive controls and no text. Non-interactive chart marks may pass under it.\n- The native grid has a 10px gap between cards and around the grid. Row height is 105px (100px at the mobile, 2-column breakpoint), so a card is `rows * 105 + (rows - 1) * 10` px tall. Width depends on the breakpoint's column count.\n- Blocks are fluid. Never assume a pixel size. Use percentages, flex or grid, and an SVG `viewBox`.\n- Set `default_w` (columns) and `default_h` (rows) in `config.json` so the content fits comfortably at its starting size: roughly 3×2 for a KPI tile, 6×4 for a chart, and 6×5 for a table or list. A card `rows` tall is `rows * 105 + (rows - 1) * 10` px, so 2 rows is 220px, 4 rows is 440px and 5 rows is 565px. Keep each default within any `min_*` and `max_*` the block sets.\n\n## B. Inner spacing\n\nWith host chrome, measure these insets from the card's edge. With chrome off, measure them from the edge of the block-owned card, or follow section M for full bleed.\n\n- Horizontal inset: 15px left and right, matching the native body padding `0 15px`.\n- With a header, use the native header band (section C). Content under a header starts at 35px from the top. The header overlay still covers the card down to 46px, so the top-right strip 60px wide from 35px to 46px must hold no interactive controls or text.\n- Without a header, use 15px top padding. The same top-right strip, 60px wide down to 46px, stays free of controls and text.\n- Bottom padding: 15px.\n- Major gaps use 15px: between a KPI value and its comparison row, and between sections.\n- Minor gaps use 10px: legend rows, list-row vertical padding, and the padding above a legend.\n\n```css\n.kz-block {\n box-sizing: border-box;\n width: 100%;\n height: 100%;\n padding: 15px;\n display: flex;\n flex-direction: column;\n font-family: var(--font-family-sans-serif);\n color: var(--color-font-primary);\n}\n.kz-block--with-header {\n padding-top: 0;\n}\n```\n\n## C. Header (optional; use judgment)\n\nA block doesn't need a header, and it may use a different kind of header when the content calls for one. When it shows a native-style title, match native exactly:\n\n- A band 35px tall with padding `7.5px 60px 7.5px 15px`. The 60px right padding keeps long titles out from under the hover menu.\n- Title text 12px, weight 100 (Proxima Nova Light), `text-transform: uppercase`, `color: var(--color-font-primary)`, `line-height: 20px`, left-aligned at 15px.\n- Blocks can't read per-dashboard title-style settings, so always use these defaults.\n- Copy `.kz-header` from the example below. Its `margin: 0 -15px` cancels the root's side padding so the title lands at 15px.\n\n## D. Typography\n\n- Font: Proxima Nova through `font-family: var(--font-family-sans-serif)`. The host already loads it.\n- The host applies `* { font-size: 10px; line-height: 1 }`. Set an explicit px `font-size` on every text element.\n- Scale (px): hero 32, header 24, subheader 18, body 14, button 13, label 12, small 11, micro 10.\n- Weights: 100 light, 400 regular, 600 bold, 900 black.\n- Text colors: `var(--color-font-primary)` (#4A5660) for primary text, `var(--color-font-secondary)` (#7E8C98) for secondary text, `var(--color-font-placeholder)` (#A8B3BC) for muted text and captions.\n- Header titles and category or axis labels are uppercase. Legend labels use sentence case.\n\n## E. Color tokens\n\nAlways use CSS custom properties. Never write raw hex, because themes can change the values. The hex values below are reference only.\n\n| Use | Token | Default |\n| ------------------------ | -------------------------------------------- | ------- |\n| Surface | `--color-background-white` | #FFFFFF |\n| Surface | `--color-background-light` | #F5F6F7 |\n| Surface | `--color-background-lighter` | #F9FAFB |\n| Surface | `--color-background-medium` | #D8DDE1 |\n| Surface | `--color-background-dark` | #A8B3BC |\n| Surface | `--color-background-darker` | #4A5660 |\n| Surface | `--color-background-hover` | #D8EAFD |\n| Border, divider | `--color-border-medium` | #D8DDE1 |\n| Border, divider | `--color-border-medium-light` | #ECEEF0 |\n| Border, divider | `--color-border-light` | #F5F6F7 |\n| Links, secondary actions | `--color-button-secondary-default`, `-hover` | #4090F7 |\n| Primary actions | `--color-button-primary-default`, `-hover` | #4BC7B4 |\n| Status good | `--color-viz-cat-1-primary` | #32C055 |\n| Status bad | `--color-viz-cat-7-primary` | #EB272B |\n\nColor SVG through CSS classes in `styles.css`, for example `.bar-1 { fill: var(--color-viz-cat-1-primary); }`. Never use `fill=\"var(...)\"` attributes; they aren't reliable.\n\n## F. Charts\n\nNative dashlets use amCharts 5. Blocks hand-build SVG that mimics it.\n\n- Series palette, in order: `--color-viz-cat-N-primary` for N = 1 to 10 (the tokens native charts read). The paired light shade `--color-viz-cat-N-secondary` is for backgrounds, tracks and comparison series.\n- Defaults (primary / secondary): 1 #32C055 / #ADE6BB, 2 #285DE4 / #6FB2F9, 3 #F3A800 / #FADC99, 4 #4926CC / #B7A6EA, 5 #38B3B9 / #9BD9DB, 6 #F26C56 / #F4A63A, 7 #EB272B / #FF8A8A, 8 #D100A0 / #FF85E2, 9 #AE764A / #D6BAA4, 10 #7A7A7A / #BCBCBC.\n- Axis labels: `fill: var(--color-background-dark)`, 10 to 11 user units, small and muted.\n- Gridlines: `stroke: var(--color-border-medium-light)`, 1px.\n- Tooltip, if you draw one: background `var(--color-background-darker)`, text `var(--color-background-white)`.\n- Donut: 2px white gaps between segments (`stroke: var(--color-background-white); stroke-width: 2;`).\n- Dashed forecast or incomplete segments: `stroke-dasharray: 4 4;`.\n- Legend: 8px circular dots, 10px gap to a 10px label, 20px column gap between items, 10px row gap when wrapping, 10px padding above the legend.\n- Put chart labels inside the SVG as `<text>` so they scale with the `viewBox`.\n\n## G. KPI tiles\n\nThe value is hero 32px, weight 400, `var(--color-font-primary)`, centered when it stands alone. A comparison or delta row sits 15px below it, `var(--color-viz-cat-1-primary)` when good and `var(--color-viz-cat-7-primary)` when bad.\n\n## H. Number formatting\n\nMatch the native `collapseNumber` rules:\n\n- Not a number: `0`.\n- |n| < 1: up to 4 decimals, trailing zeros removed.\n- |n| < 1,000: up to 5 significant digits, trailing zeros removed.\n- 1,000 to 9,999: an integer with a thousands separator.\n- 10,000 and up: round to 4 significant digits first, then show K, M or B.\n- 1 trillion and up: `999B+`, with no sign.\n- Currency: prefix the symbol, for example `$`.\n\nNever copy or rewrite this helper. Import it from the CLI-managed data lib:\n\n```js\nimport { formatNumber } from '../../lib/kizenData.js';\n```\n\n## I. States\n\n- Loading: a centered, subtle \"Loading…\" line on a transparent background (with chrome off, on whatever background the block paints). Render it with `this.outputUI` first, before any data fetch.\n- Empty: centered \"No Data\", 32px, `color: var(--color-background-medium)`.\n- Error: a centered 14px message in `var(--color-font-secondary)`, for example \"Couldn't load data.\" Never show raw error objects.\n\n## J. Icons\n\nInline SVG only, with `fill: currentColor` or a token applied through a class. Icon fonts and host icon classes aren't available.\n\n## K. Scrollbars\n\nEvery scroll container uses the app's expanding scrollbar. Add the `kds-expanding-scrollbar` class to the element that scrolls, for example `<div class=\"kz-list kds-expanding-scrollbar\">`. The host finds these containers on its own, including ones that render later, and attaches the native thin bar that widens on hover.\n\n- Put the class on the element that has `overflow: auto`, not on its parent. Give that element a bounded height, usually a flex child with `flex: 1; min-height: 0`.\n- Never style scrollbars yourself: no `::-webkit-scrollbar` rules, `scrollbar-width` or `scrollbar-color`.\n- Only scroll when the content really is a list. Otherwise fit the content to the card.\n\n## L. Don'ts\n\n- With host chrome, don't paint an outer card, shadow or border.\n- Don't use fixed pixel widths.\n- Don't use raw hex colors.\n- Don't use `em` or `rem` units. The base is 10px, so they surprise.\n- Don't load custom web fonts.\n- Don't put content under the top-right menu area.\n- Don't add a scroll container without `kds-expanding-scrollbar` (section K).\n\n## M. Chrome off (`\"host_chrome\": false`)\n\nThe host paints no background, border, radius or shadow. The block root is still `width: 100%; height: 100%; box-sizing: border-box;` and starts at the card's top-left corner (0,0) with no host padding. Pick one of these layouts:\n\n- Transparent full bleed: the root fills the card edge to edge and the dashboard background shows through wherever the block paints nothing. Use it for heroes and imagery, for example a `background-image` with `background-size: cover` on the root.\n- Block-owned card: the block paints its own card with its own background, `border-radius`, border and `box-shadow`, using tokens. The host card still clips at its edges (`overflow: hidden`), so inset the card from the root by at least its shadow's blur plus offset, usually 8 to 12px (for example `padding: 10px` on the root with the card inside). A card with no inset loses its shadow.\n\nThe host adds no backdrop behind its controls, so keep two areas visually quiet, with no dark or busy art directly under them:\n\n- The top-right menu strip, 60px wide and 46px tall. It still holds no interactive controls and no text.\n- The top-left drag-handle area in edit mode, about 30px square. The handle icon sits 5px from the left and 10px from the top and is 15px tall.\n\nSection A's grid, fluid-size and default-size rules, section C (when you show a native-style header), sections D to K and the rest of section L still apply. Inside a block-owned card, use section B's spacing.\n\n## Example: header, bar chart and legend\n\nThe block counts Contacts by their `status` dropdown for the current dashboard filters, with the helpers from `src/lib/kizenData.js` (see \"Reading Kizen data\" in `SKILL.md`). Swap `OBJECT` and `FIELD` for the object and field the user asked about. The chart's only text is the y-axis labels at the left edge and the category labels along the bottom, so nothing lands in the top-right strip under the menu.\n\n`script.js`:\n\n```js\nimport {\n blockFilters,\n countBy,\n escapeHtml,\n fieldByName,\n formatNumber,\n getFields,\n searchRecords,\n} from '../../lib/kizenData.js';\n\nconst OBJECT = 'client_client';\nconst FIELD = 'status';\n\nconst render = (body) =>\n this.outputUI(\n `<div class=\"kz-block kz-block--with-header\"><div class=\"kz-header\">Contacts by status</div>${body}</div>`,\n );\n\nrender('<div class=\"kz-state\">Loading…</div>');\n\nlet rows;\nlet notes;\ntry {\n const fields = await getFields(this, OBJECT);\n const field = fieldByName(fields, FIELD);\n if (!field) throw new Error(`${OBJECT} has no ${FIELD} field`);\n const { filters, unapplied } = blockFilters(this.args, fields);\n const { records, count, truncated } = await searchRecords(this, {\n object: OBJECT,\n fieldNames: [FIELD],\n filters,\n });\n rows = countBy(records, FIELD, field).filter((row) => row.key !== '');\n notes = [\n truncated ? `Showing first ${formatNumber(records.length)} of ${formatNumber(count)}` : '',\n unapplied.includes('teamFilter') ? '(team filter not applied)' : '',\n ].filter(Boolean);\n} catch {\n render('<div class=\"kz-state kz-state--error\">Couldn\\'t load data.</div>');\n return;\n}\n\nif (rows.length === 0) {\n render('<div class=\"kz-state kz-state--empty\">No Data</div>');\n return;\n}\n\nconst W = 300,\n H = 150,\n left = 36,\n top = 6,\n bottom = 18;\nconst plot = H - top - bottom;\nconst max = Math.max(...rows.map((r) => r.count)) || 1;\nconst y = (v) => top + plot - (v / max) * plot;\nconst step = (W - left) / rows.length;\nconst barW = Math.min(20, step / 2);\n\nconst grid = [0, 0.5, 1]\n .map((f) => f * max)\n .map(\n (t) =>\n `<line class=\"grid\" x1=\"${left}\" x2=\"${W}\" y1=\"${y(t)}\" y2=\"${y(t)}\"/>` +\n `<text class=\"axis\" x=\"${left - 6}\" y=\"${y(t) + 3}\" text-anchor=\"end\">${formatNumber(t)}</text>`,\n )\n .join('');\n\nconst bars = rows\n .map((r, i) => {\n const cx = left + i * step + step / 2;\n return (\n `<rect class=\"bar\" x=\"${cx - barW / 2}\" y=\"${y(r.count)}\" width=\"${barW}\" height=\"${top + plot - y(r.count)}\"/>` +\n `<text class=\"axis\" x=\"${cx}\" y=\"${H - 4}\" text-anchor=\"middle\">${escapeHtml(r.label)}</text>`\n );\n })\n .join('');\n\nrender(\n `<div class=\"kz-chart\"><svg viewBox=\"0 0 ${W} ${H}\">${grid}${bars}</svg></div>` +\n '<div class=\"kz-legend\">' +\n '<span class=\"kz-legend__item\"><span class=\"kz-dot\"></span>Contacts</span>' +\n notes.map((note) => `<span class=\"kz-note\">${escapeHtml(note)}</span>`).join('') +\n '</div>',\n);\n```\n\n`styles.css`:\n\n```css\n.kz-block {\n box-sizing: border-box;\n width: 100%;\n height: 100%;\n padding: 15px;\n display: flex;\n flex-direction: column;\n font-family: var(--font-family-sans-serif);\n color: var(--color-font-primary);\n}\n.kz-block--with-header {\n padding-top: 0;\n}\n.kz-header {\n flex: none;\n box-sizing: border-box;\n height: 35px;\n margin: 0 -15px;\n padding: 7.5px 60px 7.5px 15px;\n font-size: 12px;\n font-weight: 100;\n line-height: 20px;\n text-transform: uppercase;\n color: var(--color-font-primary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.kz-state {\n flex: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n text-align: center;\n font-size: 14px;\n color: var(--color-font-placeholder);\n}\n.kz-state--empty {\n font-size: 32px;\n color: var(--color-background-medium);\n}\n.kz-state--error {\n font-size: 14px;\n color: var(--color-font-secondary);\n}\n.kz-chart {\n flex: 1;\n min-height: 0;\n}\n.kz-chart svg {\n display: block;\n width: 100%;\n height: 100%;\n}\n.grid {\n stroke: var(--color-border-medium-light);\n stroke-width: 1;\n}\n.axis {\n fill: var(--color-background-dark);\n font-size: 10px;\n}\n.bar {\n fill: var(--color-viz-cat-1-primary);\n}\n.kz-legend {\n flex: none;\n display: flex;\n flex-wrap: wrap;\n column-gap: 20px;\n row-gap: 10px;\n padding-top: 10px;\n}\n.kz-legend__item {\n display: flex;\n align-items: center;\n gap: 10px;\n font-size: 10px;\n color: var(--color-font-primary);\n}\n.kz-dot {\n flex: none;\n width: 8px;\n height: 8px;\n border-radius: 50%;\n background: var(--color-viz-cat-1-primary);\n}\n.kz-note {\n font-size: 10px;\n color: var(--color-font-placeholder);\n}\n```\n","# Copilot review instructions for this Kizen plugin\n\nThis repo is a Kizen plugin app: a `kizen.json` manifest plus the artifacts\nthat `@kizenapps/packager` finds by walking the directory tree under the\nmanifest's `entry` (default `src/`). No manifest key lists artifacts. The\ndirectory layout decides what gets packaged.\n\n## Component directories\n\nUnder `entry`, the packager treats these directory names as component types:\n\n- `floatingFrames`\n- `blocks`\n- `dataAdornments`\n- `pages`\n- `views`\n- `toolbarItems`\n- `objectSettingsItems`\n- `actions`\n- `routeScripts`\n- `automationSteps`\n- `calendarSources`\n\nEvery directory under a component type needs a `config.json`. `views/` is the\none exception.\n\n## `api_name` rules\n\n- An `api_name` must match `/^[a-z_][a-z0-9_]+$/`: lowercase letters, digits\n and underscores, starting with a letter or underscore, at least 2 characters.\n- Set `api_name` explicitly in each artifact's `config.json`. The fallback\n lowercases and strips the directory name (`myFrame` becomes `myframe`), and\n that result can collide with another artifact's explicit `api_name`.\n- Data adornments have no `api_name` field. Flag one that adds it as dead\n configuration.\n- Sibling components in the same directory need unique `api_name`s. `pages/`\n and `views/` go further and share one namespace, so a page and a view with\n the same `api_name` collide even though they live in different directories.\n\n## A green build does not mean a correct artifact\n\nThe packager coerces malformed artifact config instead of rejecting it: an\ninvalid `field_type` on a data adornment becomes `phonenumber`, and an invalid\n`minimized_style` on a floating frame becomes `circle`. It also says nothing\nabout a missing required field. Publishing is the real gate. The publish step\ncreates each artifact with no defaulting, so a field the packager never emitted\nis absent and the publish request 400s. Review each\n`config.json` as if the build will not catch mistakes in it, because for these\ncases it does not.\n\nPublishing an app requires these fields per artifact type. An artifact missing\none builds clean and fails to publish:\n\n| Artifact | Required fields |\n| --- | --- |\n| Floating frame | `api_name`, `name`, `title` |\n| Block | `api_name`, `name` |\n| Data adornment | `field_type` (one of `phonenumber`, `date`, `datetime`) |\n| Routable page | `api_name`, `name` |\n| Toolbar item | `api_name`, `label`, and a non-blank `script.js` |\n| Object settings item | `api_name`, `label`, and a non-blank `script.js` |\n| JS action | `api_name`, `name`, `hint_object_name` (non-blank) |\n\nA floating frame whose `default_position` ends in `-fixed` must set\n`minimized_style: \"circle\"` or omit `minimized_style`. Any other value fails\nthe build with `structure/fixed-frame-minimized-style`.\n\n## Publishing\n\nPublishing an app requires exactly one `thumbnail.png`, and it must sit inside\nthe `entry` directory (`src/thumbnail.png` by default). The packager never sees\na thumbnail at the repo root, and publishing then fails with \"Thumbnail is\nrequired for publishing\".\n\n## Scope\n\nThis file covers repo structure and general review. Two path-scoped files\ncover the rest: `.github/instructions/security.instructions.md` for\nsecurity-sensitive patterns and\n`.github/instructions/version-discipline.instructions.md` for manifest version\nbumps.\n","---\napplyTo: \"src/**/*.js,kizen.json\"\n---\n\n# Security review rules for plugin scripts\n\nThese rules mirror the `security/*` validation rules in `@kizenapps/packager`.\nFlag violations the way the packager would, and also flag the patterns listed\nhere that its static scan cannot detect.\n\n## `__dangerouslySkipProxy`\n\nThe packager lets `__dangerouslySkipProxy` through with the build WARNING\n`security/dangerously-skip-proxy`. Flag every occurrence for human review\nanyway, because the request leaves the browser directly instead of passing\nthrough the Kizen proxy.\n\n## Plaintext credentials\n\nIn `kizen.json`, a service's `auth_credentials.token`,\n`auth_credentials.password` and `auth_credentials.client_secret` must each be\none of:\n\n- an encrypted envelope (`{ \"encrypted\": true, \"value\": \"...\" }`) that\n `appbuilder encrypt` produced\n- a `{{secret.KEY}}` reference, with `KEY` declared in `base_config.secrets`\n- a reference through `auth_credentials.integration_secret_api_name`\n\nA raw literal in any of those three fields is the build ERROR\n`security/plaintext-credential`. Treat a credential that reaches a commit in\nplaintext as compromised and rotate it; deleting the line does not undo the\nexposure.\n\n`client_id` is excluded from this rule on purpose. Public client ids are not\nsensitive, so do not flag them.\n\n## Undeclared secret references\n\nA `{{secret.KEY}}` reference whose `KEY` is missing from `base_config.secrets`\nis the build ERROR `security/undeclared-secret-reference`, because nothing\nwould supply the value at install time.\n\n## Dynamic code execution\n\n`eval(...)`, `new Function(...)` or `Function(...)`, and a string argument to\n`setTimeout` or `setInterval` are the build ERROR `security/dynamic-code`.\n\nThis rule catches direct, literal usage only. The packager's scan is\nparser-based, so a call built through a computed property or a reassigned\nreference gets past it. Obfuscated dynamic code stays a human-review concern.\n\n## Secret logging and exfiltration\n\nThe packager has no static check for a secret that gets logged, sent to an\nunexpected endpoint, or otherwise exfiltrated. Review for this by hand: look\nfor credentials or decrypted secret values flowing into `console.log`, error\nmessages, analytics calls, or outbound requests to anything other than the\nservice they belong to.\n\n## Handling secrets in this repo\n\nEncrypt secrets locally with `appbuilder encrypt` before committing them. Do\nnot commit a plaintext secret value in any form; a comment, a script fixture,\nand a commit you intend to rewrite later all count.\n","---\napplyTo: \"kizen.json\"\n---\n\n# Version-bump discipline for `kizen.json`\n\n## What a wrong bump breaks\n\nA business that installs this plugin accumulates its own stored state\n(automation runs, config values, references to entities) shaped by what was\npublished at the time. Publishing is additive: it never rewrites a business's\nstored rows, and the plugin author has no way to migrate that state for them.\nA change is breaking when it invalidates an assumption the business's existing\ndata already depends on.\n\nA MINOR or PATCH republish applies at once to a business's running automations\nand installed artifacts. Only a new MAJOR version waits for the business to\nupgrade explicitly. A change that needed MAJOR but shipped as MINOR or PATCH\ntherefore breaks the business with no upgrade gate in between.\n\nTwo kinds of change get MAJOR because they fail without an error:\n\n- Renaming a config field, changing its type, or adding a required key. A\n template reference like `{{config.key}}` for a key that no longer exists\n resolves to a literal `null`, and the artifact renders wrong or does\n nothing.\n- Removing or renaming a JS action. A business's automation and UI\n associations key on the action's `api_name` as a plain string, with no\n foreign key. After a rename or removal those associations stop firing.\n\nReview every `kizen.json` diff against the table below before approving the\nversion bump in the same PR.\n\n## Bump matrix\n\n| Resource | Change | Required bump |\n| --- | --- | --- |\n| Plugin | change `api_name` | **HARD-BLOCK**: identity can never change |\n| Service | add | MINOR |\n| Service | remove | MAJOR |\n| Service | change auth type or `auth_level` | MAJOR |\n| Service | change `auth_credentials` (client id/secret, scopes, authorize/token URLs) | MAJOR |\n| Service | change base URL or other non-auth field | PATCH |\n| Service | rename `api_name` | MAJOR |\n| Secret | add | MINOR |\n| Secret | remove | MINOR |\n| Secret | rename key | MAJOR |\n| Secret | re-encrypt value only | PATCH |\n| Automation step | add | MINOR |\n| Automation step | remove entire step | MAJOR |\n| Automation step | remove an input or output | MAJOR |\n| Automation step | change input/output `data_type` | MAJOR |\n| Automation step | add required input | MAJOR |\n| Automation step | add optional input | MINOR |\n| Automation step | change python runtime | PATCH |\n| Automation step | edit script body only | PATCH |\n| Artifact (frame, block, adornment, page, route script, toolbar/object-settings item, calendar source) | add | MINOR |\n| Artifact | remove | MINOR |\n| Artifact | rename `api_name` | MINOR |\n| Artifact | edit script or behavior | PATCH |\n| JS action | add | MINOR |\n| JS action | remove | MAJOR |\n| JS action | rename `api_name` | MAJOR |\n| JS action | change `hint_object_name` or script | PATCH |\n| Config field | add optional (with default) | MINOR |\n| Config field | add required (no default) | MAJOR |\n| Config field | remove | MINOR |\n| Config field | rename | MAJOR |\n| Config field | change type | MAJOR |\n| Config field | change default or label | PATCH |\n| `required_entitlement` | add gating | MINOR |\n| `required_entitlement` | change or remove | PATCH |\n| Manifest metadata (`name`, `description`, `entry`, `release_branches`, `release_environments`, `published`, `developer_business_id`) | any change | PATCH |\n","const MAX_PAGE_SIZE = 1000;\nconst DEFAULT_MAX_PAGES = 10;\n\nconst fieldCache = new Map();\n\nexport const formatNumber = (input, prefix = '') => {\n const n = Number.isNaN(Number(input)) ? 0 : Number(input);\n const abs = Math.abs(n);\n const sign = n < 0 ? '-' : '';\n if (abs < 1) return `${sign}${prefix}${Number(abs.toFixed(4))}`;\n if (abs < 1000) return `${sign}${prefix}${Number(abs.toPrecision(5))}`;\n if (abs < 10000) return `${sign}${prefix}${Math.round(abs).toLocaleString()}`;\n const rounded = Number(abs.toPrecision(4));\n if (rounded >= 1e12) return `${prefix}999B+`;\n const [unit, suffix] = rounded >= 1e9 ? [1e9, 'B'] : rounded >= 1e6 ? [1e6, 'M'] : [1e3, 'K'];\n return `${sign}${prefix}${Number((rounded / unit).toPrecision(4))}${suffix}`;\n};\n\nconst HTML_ESCAPES = { '&': '&', '<': '<', '>': '>', '\"': '"', \"'\": ''' };\n\nexport const escapeHtml = (value) =>\n value === null || value === undefined\n ? ''\n : String(value).replace(/[&<>\"']/g, (char) => HTML_ESCAPES[char]);\n\nconst describeError = (error) => {\n if (typeof error === 'string') return error;\n if (error instanceof Error) return error.message;\n if (error && typeof error === 'object') {\n if (typeof error.message === 'string') return error.message;\n try {\n return JSON.stringify(error);\n } catch {\n return String(error);\n }\n }\n return String(error);\n};\n\nconst loadFields = async (ctx, object) => {\n const [data, error] = await ctx.getWithErrors(\n `/custom-objects/${encodeURIComponent(object)}/fields`,\n );\n if (error) {\n throw new Error(`Couldn't load fields for ${object}: ${describeError(error)}`);\n }\n if (!Array.isArray(data)) {\n throw new Error(`Couldn't load fields for ${object}: the response was not a list of fields`);\n }\n return data;\n};\n\nexport const getFields = (ctx, object) => {\n if (!fieldCache.has(object)) {\n const pending = loadFields(ctx, object);\n fieldCache.set(object, pending);\n pending.catch(() => {\n if (fieldCache.get(object) === pending) fieldCache.delete(object);\n });\n }\n return fieldCache.get(object);\n};\n\nexport const fieldByName = (fields, name) => fields.find((field) => field.name === name);\n\nconst nonCustomFilter = (field, condition, value) => ({\n type: 'fields_v2',\n subtype: 'non_custom',\n field,\n condition,\n value,\n});\n\nexport const blockFilters = (args, fields) => {\n const filters = [];\n const unapplied = [];\n const dateFilter = args?.dateFilter;\n const teamFilter = args?.teamFilter;\n\n if (dateFilter) {\n if (dateFilter.start && dateFilter.end) {\n filters.push(nonCustomFilter('created', 'between', [dateFilter.start, dateFilter.end]));\n } else {\n unapplied.push('dateFilter');\n }\n }\n\n const teamMembers = teamFilter?.teamMembers ?? [];\n const roles = teamFilter?.roles ?? [];\n\n if (teamMembers.length > 0) {\n if (fieldByName(fields, 'owner')) {\n filters.push(nonCustomFilter('owner', 'is_any_of', [...teamMembers]));\n } else {\n unapplied.push('teamFilter');\n }\n } else if (roles.length > 0) {\n unapplied.push('teamFilter');\n }\n\n return { filters, unapplied };\n};\n\nexport const dropdownFilter = (field, optionNameOrNames) => {\n const names = Array.isArray(optionNameOrNames) ? optionNameOrNames : [optionNameOrNames];\n const ids = names.map((name) => {\n const option = (field.options ?? []).find((candidate) => candidate.name === name);\n if (!option) {\n throw new Error(`${field.display_name ?? field.name} has no option named \"${name}\"`);\n }\n return option.id;\n });\n const multiple = Array.isArray(optionNameOrNames);\n return {\n type: 'fields_v2',\n subtype: 'custom',\n field: `custom::${field.id}`,\n condition: multiple ? 'is_any_of' : '=',\n value: multiple ? ids : ids[0],\n };\n};\n\nexport const searchRecords = async (\n ctx,\n {\n object,\n fieldNames,\n filters = [],\n pageSize = MAX_PAGE_SIZE,\n maxPages = DEFAULT_MAX_PAGES,\n ordering,\n },\n) => {\n const size = Number.isFinite(Number(pageSize))\n ? Math.max(1, Math.min(MAX_PAGE_SIZE, Math.floor(Number(pageSize))))\n : MAX_PAGE_SIZE;\n const pages = Number.isFinite(Number(maxPages))\n ? Math.max(1, Math.floor(Number(maxPages)))\n : DEFAULT_MAX_PAGES;\n const body = {\n field_names: fieldNames,\n query: Array.isArray(filters) && filters.length > 0 ? [{ and: true, filters }] : [],\n };\n const orderingParam = ordering ? `&ordering=${encodeURIComponent(ordering)}` : '';\n const records = [];\n let count = 0;\n let hasMore = false;\n\n for (let page = 1; page <= pages; page += 1) {\n const [data, error] = await ctx.postWithErrors(\n `/records/${encodeURIComponent(object)}/search?page_size=${size}&page=${page}${orderingParam}`,\n body,\n );\n if (error) {\n throw new Error(`Couldn't search ${object}: ${describeError(error)}`);\n }\n const results = Array.isArray(data?.results) ? data.results : [];\n records.push(...results);\n count = typeof data?.count === 'number' ? data.count : records.length;\n hasMore = Boolean(data?.next) && results.length > 0;\n if (!hasMore) break;\n }\n\n return { records, count, truncated: hasMore || count > records.length };\n};\n\nconst fieldEntry = (record, name) =>\n Object.values(record?.fields ?? {}).find((entry) => entry?.name === name);\n\nexport const fieldValue = (record, name) => fieldEntry(record, name)?.value;\n\nconst labelOf = (value) => {\n if (value === null || value === undefined || value === '') return '';\n if (Array.isArray(value)) return value.map(labelOf).filter(Boolean).join(', ');\n if (typeof value === 'object') {\n if ('amount' in value) {\n if (value.amount === null || value.amount === undefined || value.amount === '') return '';\n return formatNumber(Number(value.amount), value.symbol ?? '');\n }\n if ('first_name' in value || 'last_name' in value) {\n const fullName = [value.first_name, value.last_name].filter(Boolean).join(' ');\n return fullName || value.email || '';\n }\n return String(value.name ?? value.display_name ?? '');\n }\n return String(value);\n};\n\nexport const fieldLabel = (record, name) => labelOf(fieldValue(record, name));\n\nconst keyOf = (value) => {\n if (value === null || value === undefined) return '';\n if (typeof value === 'object') return String(value.id ?? labelOf(value));\n return String(value);\n};\n\nconst valuesOf = (value) => {\n if (Array.isArray(value)) return value.length > 0 ? value : [null];\n return [value];\n};\n\nexport const countBy = (records, name, field) => {\n const groups = new Map();\n\n for (const record of records) {\n for (const value of valuesOf(fieldValue(record, name))) {\n const key = keyOf(value);\n const group = groups.get(key);\n if (group) {\n group.count += 1;\n } else {\n groups.set(key, { key, label: labelOf(value), count: 1 });\n }\n }\n }\n\n const order = new Map(\n (field?.options ?? [])\n .filter((option) => typeof option.order === 'number' && Number.isFinite(option.order))\n .map((option) => [String(option.id), option.order]),\n );\n const rank = (key) => (order.has(key) ? order.get(key) : Number.POSITIVE_INFINITY);\n\n return [...groups.values()].sort((a, b) => {\n if (b.count !== a.count) return b.count - a.count;\n const ra = rank(a.key);\n const rb = rank(b.key);\n return ra === rb ? 0 : ra < rb ? -1 : 1;\n });\n};\n\nconst numberOf = (value) => {\n if (value === null || value === undefined || value === '') return 0;\n const raw = typeof value === 'object' ? value.amount : value;\n if (raw === null || raw === undefined || raw === '') return 0;\n const n = Number(raw);\n return Number.isFinite(n) ? n : 0;\n};\n\nexport const sumBy = (records, name, valueOf) =>\n records.reduce(\n (total, record) =>\n total + (valueOf ? numberOf(valueOf(record)) : numberOf(fieldValue(record, name))),\n 0,\n );\n","import kizenCustomBlockSkill from '../templates/claude/skills/kizen-custom-block/SKILL.md?raw';\nimport kizenCustomBlockDesign from '../templates/claude/skills/kizen-custom-block/design.md?raw';\nimport copilotInstructions from '../templates/github/copilot-instructions.md?raw';\nimport securityInstructions from '../templates/github/instructions/security.instructions.md?raw';\nimport versionDisciplineInstructions from '../templates/github/instructions/version-discipline.instructions.md?raw';\nimport kizenDataLib from '../templates/plugin/lib/kizenData.js?raw';\nimport type { ScaffoldedFile } from './createArtifacts.js';\n\nexport function copilotFiles(): ScaffoldedFile[] {\n return [\n { path: '.github/copilot-instructions.md', content: copilotInstructions },\n { path: '.github/instructions/security.instructions.md', content: securityInstructions },\n {\n path: '.github/instructions/version-discipline.instructions.md',\n content: versionDisciplineInstructions,\n },\n ];\n}\n\nexport const KIZEN_DATA_LIB_FILE = 'lib/kizenData.js';\n\nexport const kizenDataLibPath = (entryDir = 'src'): string =>\n entryDir === '' ? KIZEN_DATA_LIB_FILE : `${entryDir}/${KIZEN_DATA_LIB_FILE}`;\n\nexport function claudeFiles(entryDirs: readonly string[] = ['src']): ScaffoldedFile[] {\n return [\n { path: '.claude/skills/kizen-custom-block/SKILL.md', content: kizenCustomBlockSkill },\n { path: '.claude/skills/kizen-custom-block/design.md', content: kizenCustomBlockDesign },\n ...[...new Set(entryDirs)].map((entryDir) => ({\n path: kizenDataLibPath(entryDir),\n content: kizenDataLib,\n })),\n ];\n}\n","import {\n useEffect,\n useState,\n type Dispatch,\n type FC,\n type ReactNode,\n type SetStateAction,\n} from 'react';\nimport { Box, Text, useApp, useInput } from 'ink';\nimport { type ValidationIssue } from '@kizenapps/packager';\nimport { type Credentials } from '../lib/credentials.js';\nimport { formatValidationIssues } from '../lib/formatValidationIssues.js';\nimport { type Surface } from '../lib/kizenTypes.js';\nimport {\n findPushMapEntry,\n matchPushTarget,\n removePushMapEntry,\n surfaceToDashboardType,\n} from '../lib/pushBlock.js';\nimport {\n apiFailure,\n applyPlan,\n buildBrowserRefresh,\n buildPlan,\n buildTargetChoices,\n forgetRemembered,\n formatSummaryLines,\n pushMapKeyOf,\n headlessWriteGate,\n listPushableObjects,\n resolveBlock,\n resolveCredentials,\n resolveTarget,\n toTargetRow,\n type AppliedPush,\n type PushChoice,\n type PushCommandOptions,\n type PushContext,\n type PushDeps,\n type PushPlan,\n type ResolvedBlock,\n type ResolvedTarget,\n type TargetCustomObject,\n type TargetRow,\n} from '../lib/pushHeadless.js';\nimport { AppHeader } from './AppHeader.js';\nimport { SelectList, type SelectItem } from './SelectList.js';\nimport { Spinner } from './Spinner.js';\n\nexport interface PushUIProps {\n apiName?: string;\n options: PushCommandOptions;\n deps: PushDeps;\n}\n\ninterface ErrorView {\n message: string;\n hint?: string;\n choices?: PushChoice[];\n issues?: ValidationIssue[];\n}\n\ninterface Session {\n credentials: Credentials | null;\n warnings: ValidationIssue[];\n notices: string[];\n}\n\ninterface Resolving {\n options: PushCommandOptions;\n context: PushContext;\n}\n\ntype Phase =\n | { type: 'loading'; label: string }\n | { type: 'profile-select'; options: PushCommandOptions; choices: PushChoice[] }\n | { type: 'packaging' }\n | {\n type: 'block-select';\n options: PushCommandOptions;\n credentials: Credentials;\n choices: PushChoice[];\n }\n | ({ type: 'surface-select' } & Resolving)\n | ({ type: 'object-select'; objects: TargetCustomObject[]; back: Phase } & Resolving)\n | ({\n type: 'dashboard-select';\n surface: Surface;\n objectId: string | null;\n title: string;\n rows: TargetRow[];\n back: Phase;\n } & Resolving)\n | ({\n type: 'target-select';\n dashboardId: string;\n title: string;\n message: string | null;\n choices: PushChoice[];\n matchedId: string | null;\n back: Phase | null;\n } & Resolving)\n | ({ type: 'confirm'; kind: 'drift'; message: string; target: ResolvedTarget } & Resolving)\n | ({ type: 'confirm'; kind: 'push'; plan: PushPlan } & Resolving)\n | { type: 'applying'; plan: PushPlan }\n | { type: 'done'; plan: PushPlan; applied: AppliedPush | null }\n | { type: 'error'; view: ErrorView };\n\ntype Setter<T> = Dispatch<SetStateAction<T>>;\n\nconst SURFACE_ITEMS: readonly (SelectItem & { key: Surface })[] = [\n { key: 'dashboard', label: 'Dashboard' },\n { key: 'homepage', label: 'Homepage' },\n { key: 'chart_group', label: 'Chart group' },\n];\n\nconst SURFACE_NOUNS: Record<Surface, string> = {\n dashboard: 'dashboard',\n homepage: 'homepage',\n chart_group: 'chart group',\n};\n\nconst DRIFT_WARNING =\n 'The block was edited in Kizen since your last push. Overwriting discards those edits.';\n\nconst isCreateChoice = (choice: PushChoice): boolean => choice.args.includes('--create');\n\nfunction orderTargetChoices(choices: PushChoice[], matchedId: string | null): PushChoice[] {\n const matched = choices.filter((choice) => choice.value === matchedId);\n const creates = choices.filter(isCreateChoice);\n const rest = choices.filter((choice) => choice.value !== matchedId && !isCreateChoice(choice));\n\n return matched.length > 0 ? [...matched, ...rest, ...creates] : [...creates, ...rest];\n}\n\nfunction targetItem(choice: PushChoice, matchedId: string | null): SelectItem {\n if (isCreateChoice(choice)) {\n return { key: choice.value, label: choice.label };\n }\n\n if (choice.value === matchedId) {\n return { key: choice.value, label: `Update \"${choice.label}\" (last pushed here)` };\n }\n\n const description = choice.isFromThisPlugin ? 'pushed from this plugin' : choice.pushKey;\n\n return {\n key: choice.value,\n label: `Update \"${choice.label}\"`,\n ...(description ? { description } : {}),\n };\n}\n\nfunction dashboardItem(row: TargetRow): SelectItem {\n const label =\n row.dashletsCount === null ? row.name : `${row.name} (${String(row.dashletsCount)} dashlets)`;\n\n if (row.canEdit === false) {\n return { key: row.id, label, description: 'no edit access', disabled: true };\n }\n\n const description = [row.employeeAccess, row.hidden ? 'hidden' : null]\n .filter((part) => part !== null && part !== '')\n .join(' · ');\n\n return { key: row.id, label, ...(description === '' ? {} : { description }) };\n}\n\nfunction withTarget(\n options: PushCommandOptions,\n dashboardId: string,\n choice: PushChoice,\n): PushCommandOptions {\n const next: PushCommandOptions = { ...options, dashboard: dashboardId };\n\n delete next.dashlet;\n delete next.create;\n\n return isCreateChoice(choice) ? { ...next, create: true } : { ...next, dashlet: choice.value };\n}\n\nfunction createPushFlow(\n apiName: string | undefined,\n deps: PushDeps,\n setPhase: Setter<Phase>,\n setSession: Setter<Session>,\n): {\n start: (options: PushCommandOptions) => void;\n pickProfile: (phase: Extract<Phase, { type: 'profile-select' }>, choice: PushChoice) => void;\n pickBlock: (phase: Extract<Phase, { type: 'block-select' }>, choice: PushChoice) => void;\n pickSurface: (phase: Extract<Phase, { type: 'surface-select' }>, surface: Surface) => void;\n pickObject: (\n phase: Extract<Phase, { type: 'object-select' }>,\n object: TargetCustomObject,\n ) => void;\n pickDashboard: (phase: Extract<Phase, { type: 'dashboard-select' }>, row: TargetRow) => void;\n pickTarget: (phase: Extract<Phase, { type: 'target-select' }>, choice: PushChoice) => void;\n acceptDrift: (phase: Extract<Phase, { type: 'confirm'; kind: 'drift' }>) => void;\n acceptPush: (phase: Extract<Phase, { type: 'confirm'; kind: 'push' }>) => void;\n cancel: () => void;\n} {\n const fail = (view: ErrorView): void => {\n deps.setExitCode(1);\n setPhase({ type: 'error', view });\n };\n\n const guard = (task: () => Promise<void>): void => {\n task().catch((error: unknown) => {\n fail(apiFailure(error));\n });\n };\n\n const apply = async (context: PushContext, plan: PushPlan): Promise<void> => {\n setPhase({ type: 'applying', plan });\n\n const step = await applyPlan(context, plan, deps);\n\n if (!step.ok) {\n fail(step);\n\n return;\n }\n\n setPhase({ type: 'done', plan, applied: step.value });\n };\n\n const plan = async (\n context: PushContext,\n target: ResolvedTarget,\n options: PushCommandOptions,\n ): Promise<void> => {\n setPhase({ type: 'loading', label: 'Preparing the push…' });\n\n const step = await buildPlan(context, target, options, deps);\n\n if (!step.ok) {\n if (step.code === 'drift_detected') {\n setPhase({\n type: 'confirm',\n kind: 'drift',\n message: step.message,\n target,\n options,\n context,\n });\n\n return;\n }\n\n fail(step);\n\n return;\n }\n\n if (options.dryRun) {\n setPhase({ type: 'done', plan: step.value, applied: null });\n\n return;\n }\n\n if (options.yes) {\n const gate = headlessWriteGate(options, context.credentials.environment);\n\n if (gate.ok && gate.value.kind === 'apply') {\n await apply(context, step.value);\n\n return;\n }\n }\n\n setPhase({ type: 'confirm', kind: 'push', plan: step.value, options, context });\n };\n\n const resolve = async (\n context: PushContext,\n options: PushCommandOptions,\n back: Phase | null,\n ): Promise<void> => {\n setPhase({ type: 'loading', label: 'Resolving the target…' });\n\n const step = await resolveTarget(context, options);\n\n if (step.ok) {\n await plan(context, step.value, options);\n\n return;\n }\n\n const dashboardId = options.dashboard ?? context.entry?.dashboardId;\n const pickable =\n (step.code === 'needs_choice' && step.choice === 'target') ||\n step.code === 'remembered_target_missing';\n\n if (pickable && step.choices && step.choices.length > 0 && dashboardId !== undefined) {\n setPhase({\n type: 'target-select',\n dashboardId,\n title: 'Choose a block to update, or create a new one',\n message: step.message,\n choices: orderTargetChoices(step.choices, null),\n matchedId: null,\n back,\n options,\n context,\n });\n\n return;\n }\n\n fail(step);\n };\n\n const prepare = async (\n options: PushCommandOptions,\n credentials: Credentials,\n block: ResolvedBlock,\n ): Promise<void> => {\n const key = pushMapKeyOf({ credentials, block });\n let pushMap = await deps.readPushMap(deps.cwd);\n\n if (options.forget && (await forgetRemembered({ credentials, block, pushMap }, deps))) {\n pushMap = removePushMapEntry(pushMap, key);\n setSession((session) => ({\n ...session,\n notices: [...session.notices, `Forgot the remembered target for ${block.block.api_name}.`],\n }));\n }\n\n const context: PushContext = {\n client: deps.createClient(credentials),\n credentials,\n block,\n pushMap,\n entry: findPushMapEntry(pushMap, key),\n };\n\n if (options.dashboard !== undefined || context.entry) {\n await resolve(context, options, null);\n\n return;\n }\n\n setPhase({ type: 'surface-select', options, context });\n };\n\n const packageBlock = async (\n options: PushCommandOptions,\n credentials: Credentials,\n name: string | undefined,\n ): Promise<void> => {\n setPhase({ type: 'packaging' });\n\n const step = await resolveBlock(name, deps);\n\n if (!step.ok) {\n if (step.choice === 'block' && step.choices) {\n setPhase({ type: 'block-select', options, credentials, choices: step.choices });\n\n return;\n }\n\n fail(step);\n\n return;\n }\n\n setSession((session) => ({ ...session, warnings: step.value.warnings }));\n await prepare(options, credentials, step.value);\n };\n\n const loadCredentials = async (options: PushCommandOptions): Promise<void> => {\n setPhase({ type: 'loading', label: 'Loading credentials…' });\n\n const step = await resolveCredentials(options, deps);\n\n if (!step.ok) {\n if (step.choice === 'profile' && step.choices) {\n setPhase({ type: 'profile-select', options, choices: step.choices });\n\n return;\n }\n\n fail(step);\n\n return;\n }\n\n const { credentials } = step.value;\n\n setSession((session) => ({ ...session, credentials }));\n await packageBlock(options, credentials, apiName);\n };\n\n const listDashboards = async (\n { options, context }: Resolving,\n surface: Surface,\n object: TargetCustomObject | null,\n back: Phase,\n ): Promise<void> => {\n const noun = SURFACE_NOUNS[surface];\n\n setPhase({ type: 'loading', label: `Loading ${noun}s…` });\n\n const summaries = await context.client.listDashboards(\n surfaceToDashboardType(surface),\n object?.id,\n );\n const rows = summaries.map((summary) => toTargetRow(summary, surface));\n const { environment, businessId } = context.credentials;\n\n if (rows.length === 0) {\n fail({\n message: `No ${noun}s found${object ? ` on ${object.objectName}` : ''} for business ${businessId} (${environment}).`,\n });\n\n return;\n }\n\n setPhase({\n type: 'dashboard-select',\n surface,\n objectId: object?.id ?? null,\n title: object ? `Choose a chart group on ${object.objectName}` : `Choose a ${noun}`,\n rows,\n back,\n options,\n context,\n });\n };\n\n return {\n start: (options) => {\n guard(() => loadCredentials(options));\n },\n pickProfile: (phase, choice) => {\n guard(() => loadCredentials({ ...phase.options, profile: choice.value }));\n },\n pickBlock: (phase, choice) => {\n guard(() => packageBlock(phase.options, phase.credentials, choice.value));\n },\n pickSurface: (phase, surface) => {\n guard(async () => {\n if (surface !== 'chart_group') {\n await listDashboards(phase, surface, null, phase);\n\n return;\n }\n\n setPhase({ type: 'loading', label: 'Loading custom objects…' });\n\n const objects = await listPushableObjects(phase.context.client);\n\n if (objects.length === 0) {\n fail({ message: 'No custom objects found, so there are no chart groups to push to.' });\n\n return;\n }\n\n setPhase({\n type: 'object-select',\n objects,\n back: phase,\n options: phase.options,\n context: phase.context,\n });\n });\n },\n pickObject: (phase, object) => {\n guard(() => listDashboards(phase, 'chart_group', object, phase));\n },\n pickDashboard: (phase, row) => {\n guard(async () => {\n const { context } = phase;\n const options: PushCommandOptions = { ...phase.options, dashboard: row.id };\n\n if (options.dashlet !== undefined || options.create) {\n await resolve(context, options, phase);\n\n return;\n }\n\n setPhase({ type: 'loading', label: `Loading \"${row.name}\"…` });\n\n const dashboard = await context.client.getDashboard(row.id);\n const match = matchPushTarget({\n dashboardId: dashboard.id,\n dashlets: dashboard.dashlets,\n pluginApiName: context.block.pluginApiName,\n blockApiName: context.block.block.api_name,\n entry: context.entry,\n });\n const matchedId = match.kind === 'map' || match.kind === 'name' ? match.dashlet.id : null;\n\n setPhase({\n type: 'target-select',\n dashboardId: dashboard.id,\n title: `Choose what to push to on \"${dashboard.name}\"`,\n message: null,\n choices: orderTargetChoices(buildTargetChoices(dashboard, context.block), matchedId),\n matchedId,\n back: phase,\n options,\n context,\n });\n });\n },\n pickTarget: (phase, choice) => {\n guard(() =>\n resolve(phase.context, withTarget(phase.options, phase.dashboardId, choice), phase),\n );\n },\n acceptDrift: (phase) => {\n guard(() => plan(phase.context, phase.target, { ...phase.options, force: true }));\n },\n acceptPush: (phase) => {\n guard(() => apply(phase.context, phase.plan));\n },\n cancel: () => {\n fail({ message: 'Cancelled.' });\n },\n };\n}\n\ninterface ConfirmPromptProps {\n prompt: string;\n strict: boolean;\n onAccept: () => void;\n onCancel: () => void;\n}\n\nconst ConfirmPrompt: FC<ConfirmPromptProps> = ({ prompt, strict, onAccept, onCancel }) => {\n useInput((input, key) => {\n if (key.ctrl) {\n return;\n }\n\n const answer = input.toLowerCase();\n\n if (answer === 'y' || (!strict && key.return)) {\n onAccept();\n } else if (strict || answer === 'n' || key.escape) {\n onCancel();\n }\n });\n\n return <Text bold>{prompt}</Text>;\n};\n\nconst Lines: FC<{ lines: readonly string[]; color?: 'yellow' | 'red' }> = ({ lines, color }) => (\n <Box flexDirection=\"column\">\n {lines.map((line, index) => (\n <Text key={`${String(index)}-${line}`} {...(color && { color })}>\n {line}\n </Text>\n ))}\n </Box>\n);\n\nconst PlanSummary: FC<{ plan: PushPlan }> = ({ plan }) => (\n <Box flexDirection=\"column\">\n <Lines lines={formatSummaryLines(plan.summary)} />\n <Text>URL: {plan.url}</Text>\n </Box>\n);\n\nconst Working: FC<{ label: string }> = ({ label }) => (\n <Box gap={1}>\n <Spinner />\n <Text dimColor>{label}</Text>\n </Box>\n);\n\nconst ErrorFrame: FC<{ view: ErrorView }> = ({ view }) => (\n <Box flexDirection=\"column\" gap={1}>\n <Box gap={1}>\n <Text color=\"red\">✗</Text>\n <Text color=\"red\">\n {view.issues && view.issues.length > 0 ? formatValidationIssues(view.issues) : view.message}\n </Text>\n </Box>\n {view.hint !== undefined && <Text dimColor>Hint: {view.hint}</Text>}\n {view.choices && view.choices.length > 0 && (\n <Box flexDirection=\"column\">\n <Text>Choices:</Text>\n <Lines lines={view.choices.map((choice) => ` ${choice.label}`)} />\n </Box>\n )}\n </Box>\n);\n\nconst DoneFrame: FC<{ plan: PushPlan; applied: AppliedPush | null }> = ({ plan, applied }) => {\n const refresh = buildBrowserRefresh(plan.dashboard.id);\n\n if (applied === null) {\n return (\n <Box flexDirection=\"column\" gap={1}>\n <Text color=\"yellow\">Dry run: nothing was written.</Text>\n <PlanSummary plan={plan} />\n {plan.warnings.length > 0 && (\n <Lines lines={plan.warnings.map((warning) => `Warning: ${warning}`)} color=\"yellow\" />\n )}\n <Box flexDirection=\"column\">\n <Text bold>\n {plan.method} {plan.path}\n </Text>\n <Text>{JSON.stringify(plan.body, null, 2)}</Text>\n </Box>\n </Box>\n );\n }\n\n return (\n <Box flexDirection=\"column\" gap={1}>\n <Box gap={1}>\n <Text color=\"green\">✓</Text>\n <Text bold>\n {plan.action === 'create' ? 'Created' : 'Updated'} {plan.summary.blockName} on \"\n {plan.dashboard.name}\"\n </Text>\n </Box>\n <Box flexDirection=\"column\">\n <Text>URL: {plan.url}</Text>\n {refresh && <Text dimColor>Refresh an open tab: {refresh.script}</Text>}\n </Box>\n {applied.warnings.length > 0 && (\n <Lines lines={applied.warnings.map((warning) => `Warning: ${warning}`)} color=\"yellow\" />\n )}\n </Box>\n );\n};\n\nexport const PushUI: FC<PushUIProps> = ({ apiName, options, deps }) => {\n const app = useApp();\n const [phase, setPhase] = useState<Phase>({ type: 'loading', label: 'Loading credentials…' });\n const [session, setSession] = useState<Session>({\n credentials: null,\n warnings: [],\n notices: [],\n });\n const [flow] = useState(() => createPushFlow(apiName, deps, setPhase, setSession));\n const [initialOptions] = useState(options);\n\n useEffect(() => {\n flow.start(initialOptions);\n }, [flow, initialOptions]);\n\n useEffect(() => {\n if (phase.type === 'done' || phase.type === 'error') {\n app.exit();\n }\n }, [phase, app]);\n\n useInput((input, key) => {\n if (key.ctrl && input === 'c' && phase.type !== 'done' && phase.type !== 'error') {\n deps.setExitCode(130);\n app.exit();\n }\n });\n\n const frame = (children: ReactNode): ReactNode => (\n <Box flexDirection=\"column\" paddingY={1} paddingX={2} gap={1}>\n <AppHeader />\n {session.credentials && (\n <Text dimColor>\n Environment: {session.credentials.environment} · Business:{' '}\n {session.credentials.businessId}\n </Text>\n )}\n {session.warnings.length > 0 && (\n <Text dimColor>{formatValidationIssues(session.warnings)}</Text>\n )}\n {session.notices.length > 0 && <Lines lines={session.notices} />}\n {children}\n </Box>\n );\n\n switch (phase.type) {\n case 'loading':\n return frame(<Working label={phase.label} />);\n case 'packaging':\n return frame(<Working label=\"Packaging blocks…\" />);\n case 'applying':\n return frame(\n <Working\n label={`Pushing ${phase.plan.summary.blockName} to \"${phase.plan.dashboard.name}\"…`}\n />,\n );\n case 'profile-select':\n return frame(\n <SelectList\n key=\"profile\"\n title=\"Credential profile\"\n items={phase.choices.map((choice) => ({ key: choice.value, label: choice.label }))}\n onSelect={(_item, index) => {\n const choice = phase.choices[index];\n\n if (choice) {\n flow.pickProfile(phase, choice);\n }\n }}\n onCancel={flow.cancel}\n />,\n );\n case 'block-select':\n return frame(\n <SelectList\n key=\"block\"\n title=\"Block to push\"\n items={phase.choices.map((choice) => ({ key: choice.value, label: choice.label }))}\n onSelect={(_item, index) => {\n const choice = phase.choices[index];\n\n if (choice) {\n flow.pickBlock(phase, choice);\n }\n }}\n onCancel={flow.cancel}\n />,\n );\n case 'surface-select':\n return frame(\n <SelectList\n key=\"surface\"\n title=\"Where should the block go?\"\n items={SURFACE_ITEMS}\n onSelect={(_item, index) => {\n const item = SURFACE_ITEMS[index];\n\n if (item) {\n flow.pickSurface(phase, item.key);\n }\n }}\n onCancel={flow.cancel}\n />,\n );\n case 'object-select':\n return frame(\n <SelectList\n key=\"object\"\n title=\"Custom object\"\n items={phase.objects.map((object) => ({ key: object.id, label: object.objectName }))}\n onSelect={(_item, index) => {\n const object = phase.objects[index];\n\n if (object) {\n flow.pickObject(phase, object);\n }\n }}\n onCancel={() => {\n setPhase(phase.back);\n }}\n hint=\"↑/↓ to move, Enter to select, Esc to go back\"\n />,\n );\n case 'dashboard-select':\n return frame(\n <SelectList\n key={`dashboards-${phase.surface}-${phase.objectId ?? ''}`}\n title={phase.title}\n items={phase.rows.map(dashboardItem)}\n onSelect={(_item, index) => {\n const row = phase.rows[index];\n\n if (row) {\n flow.pickDashboard(phase, row);\n }\n }}\n onCancel={() => {\n setPhase(phase.back);\n }}\n hint=\"↑/↓ to move, Enter to select, Esc to go back\"\n />,\n );\n case 'target-select': {\n const { back } = phase;\n\n return frame(\n <>\n {phase.message !== null && <Text color=\"yellow\">{phase.message}</Text>}\n <SelectList\n key={`targets-${phase.dashboardId}`}\n title={phase.title}\n items={phase.choices.map((choice) => targetItem(choice, phase.matchedId))}\n onSelect={(_item, index) => {\n const choice = phase.choices[index];\n\n if (choice) {\n flow.pickTarget(phase, choice);\n }\n }}\n onCancel={\n back\n ? () => {\n setPhase(back);\n }\n : flow.cancel\n }\n {...(back && { hint: '↑/↓ to move, Enter to select, Esc to go back' })}\n />\n </>,\n );\n }\n\n case 'confirm':\n if (phase.kind === 'drift') {\n return frame(\n <Box flexDirection=\"column\" gap={1}>\n <Text color=\"yellow\">{DRIFT_WARNING}</Text>\n <Text dimColor>{phase.message}</Text>\n <ConfirmPrompt\n key=\"drift\"\n prompt=\"Type y to overwrite (y/N)\"\n strict\n onAccept={() => {\n flow.acceptDrift(phase);\n }}\n onCancel={flow.cancel}\n />\n </Box>,\n );\n }\n\n return frame(\n <Box flexDirection=\"column\" gap={1}>\n <PlanSummary plan={phase.plan} />\n {phase.plan.warnings.length > 0 && (\n <Lines\n lines={phase.plan.warnings.map((warning) => `Warning: ${warning}`)}\n color=\"yellow\"\n />\n )}\n {phase.plan.summary.isProduction && (\n <Text color=\"red\" bold>\n PRODUCTION\n </Text>\n )}\n <ConfirmPrompt\n key=\"push\"\n prompt={\n phase.plan.summary.isProduction ? 'Type y to push to production (y/N)' : 'Push? (Y/n)'\n }\n strict={phase.plan.summary.isProduction}\n onAccept={() => {\n flow.acceptPush(phase);\n }}\n onCancel={flow.cancel}\n />\n </Box>,\n );\n case 'done':\n return frame(<DoneFrame plan={phase.plan} applied={phase.applied} />);\n case 'error':\n return frame(<ErrorFrame view={phase.view} />);\n }\n};\n","import type { FC } from 'react';\nimport { Box, Text } from 'ink';\nimport { Logo } from './Logo.js';\n\ninterface AppHeaderProps {\n marginBottom?: number;\n}\n\nexport const AppHeader: FC<AppHeaderProps> = ({ marginBottom = 0 }) => (\n <>\n <Logo />\n <Box flexDirection=\"column\" marginTop={1} marginBottom={marginBottom}>\n <Text bold color=\"cyan\">\n Kizen App Development Toolkit\n </Text>\n </Box>\n </>\n);\n","import type { FC } from 'react';\nimport { Box, Text } from 'ink';\n\nconst LOGO_LINES = [\n ' :::::::: ',\n ' :::::: ::::::::::: ',\n ' :::::: :::::::::: ',\n ' :::::: :::::: ::::::: ',\n ' ::::: :::::: ::::::::::::::::: ',\n ' ::::: ::::: ::::::::::::::::::: ',\n ' ::::: ::::: :::::: ::::: ',\n ':::: ::::: ::: ::::: :: ',\n '::::: :::::: :::::::::: ',\n '::::: :::::: ::::::::::: ',\n ' ::::: ::: ::::::: ',\n ' ::::::: ::: ::::: ',\n ' ::::::::::: :::::: :::::',\n ' :::::::::: :::::: :::::',\n ' :: ::::: ::: ::::: ::::',\n ' ::::: :::::: ::::: ::::: ::: ',\n ' ::::::::::::::::::: ::::: ::::: ',\n ' ::::::::::::::::: ::::: ::::: ',\n ' ::::::::: :::::: :::::: ',\n ' :::::::::: :::::: ',\n ' ::::::::::: :::::: ',\n ' :::::::: ',\n];\n\nexport const Logo: FC = () => (\n <Box flexDirection=\"column\">\n {LOGO_LINES.map((line, i) => (\n <Text key={i} color=\"cyan\">\n {line}\n </Text>\n ))}\n </Box>\n);\n","import type { FC } from 'react';\nimport { useMemo, useState } from 'react';\nimport { Box, Text, useInput } from 'ink';\nimport { moveCursor, visibleWindow } from '../lib/moveCursor.js';\n\nexport interface SelectItem {\n key: string;\n label: string;\n description?: string;\n disabled?: boolean;\n}\n\nexport interface SelectListProps {\n title: string;\n items: readonly SelectItem[];\n onSelect: (item: SelectItem, index: number) => void;\n onCancel?: () => void;\n hint?: string;\n initialIndex?: number;\n windowSize?: number;\n isActive?: boolean;\n}\n\nconst DEFAULT_HINT = '↑/↓ to move, Enter to select, Esc to cancel';\nconst DEFAULT_WINDOW_SIZE = 10;\n\nconst initialCursor = (items: readonly SelectItem[], initialIndex: number): number => {\n const clamped = moveCursor(initialIndex, items.length, 0);\n\n if (items[clamped]?.disabled !== true) {\n return clamped;\n }\n\n const firstEnabled = items.findIndex((item) => item.disabled !== true);\n\n return firstEnabled === -1 ? clamped : firstEnabled;\n};\n\nexport const SelectList: FC<SelectListProps> = ({\n title,\n items,\n onSelect,\n onCancel,\n hint = DEFAULT_HINT,\n initialIndex = 0,\n windowSize = DEFAULT_WINDOW_SIZE,\n isActive = true,\n}) => {\n const [cursorState, setCursorState] = useState(() => initialCursor(items, initialIndex));\n const disabled = useMemo(() => items.map((item) => item.disabled === true), [items]);\n const cursor = moveCursor(cursorState, items.length, 0);\n const pageSize = Math.max(1, Math.floor(windowSize));\n\n useInput(\n (input, key) => {\n const move = (delta: number): void => {\n setCursorState(moveCursor(cursor, items.length, delta, { disabled }));\n };\n\n if (key.upArrow || input === 'k') {\n move(-1);\n } else if (key.downArrow || input === 'j') {\n move(1);\n } else if (key.pageUp) {\n move(-pageSize);\n } else if (key.pageDown) {\n move(pageSize);\n } else if (key.return) {\n const item = items[cursor];\n\n if (item !== undefined && item.disabled !== true) {\n onSelect(item, cursor);\n }\n } else if (key.escape) {\n onCancel?.();\n }\n },\n { isActive },\n );\n\n const { start, end } = visibleWindow(cursor, items.length, pageSize);\n const above = start;\n const below = items.length - end;\n\n return (\n <Box flexDirection=\"column\" gap={1}>\n <Text bold>{title}</Text>\n <Box flexDirection=\"column\">\n {above > 0 && <Text dimColor>{` ↑ ${String(above)} more`}</Text>}\n {items.slice(start, end).map((item, offset) => {\n const index = start + offset;\n const selected = index === cursor;\n const itemDisabled = item.disabled === true;\n const highlight = selected && !itemDisabled;\n\n return (\n <Box key={item.key} gap={2}>\n <Text {...(highlight && { color: 'cyan' as const })} dimColor={itemDisabled}>\n {selected ? '❯' : ' '}\n </Text>\n <Text\n bold={highlight}\n dimColor={itemDisabled}\n {...(highlight && { color: 'cyan' as const })}\n >\n {item.label}\n </Text>\n {item.description !== undefined && <Text dimColor>{item.description}</Text>}\n </Box>\n );\n })}\n {below > 0 && <Text dimColor>{` ↓ ${String(below)} more`}</Text>}\n </Box>\n <Text dimColor>{hint}</Text>\n </Box>\n );\n};\n","export interface MoveCursorOptions {\n disabled?: readonly boolean[];\n}\n\nexport interface VisibleWindow {\n start: number;\n end: number;\n}\n\nconst clamp = (value: number, min: number, max: number): number =>\n Math.min(Math.max(value, min), max);\n\nexport function moveCursor(\n cursor: number,\n length: number,\n delta: number,\n options: MoveCursorOptions = {},\n): number {\n if (length <= 0) {\n return 0;\n }\n\n const current = clamp(Math.trunc(cursor) || 0, 0, length - 1);\n const isEnabled = (index: number): boolean => options.disabled?.[index] !== true;\n\n if (delta === 0) {\n return current;\n }\n\n const step = delta > 0 ? 1 : -1;\n\n if (Math.abs(delta) === 1) {\n for (let offset = 1; offset <= length; offset++) {\n const index = (((current + step * offset) % length) + length) % length;\n\n if (isEnabled(index)) {\n return index;\n }\n }\n\n return current;\n }\n\n const target = clamp(current + Math.trunc(delta), 0, length - 1);\n\n for (let index = target; index >= 0 && index < length; index += step) {\n if (isEnabled(index)) {\n return index;\n }\n }\n\n for (let index = target - step; index >= 0 && index < length; index -= step) {\n if (isEnabled(index)) {\n return index;\n }\n }\n\n return current;\n}\n\nexport function visibleWindow(cursor: number, length: number, size = 10): VisibleWindow {\n if (length <= 0) {\n return { start: 0, end: 0 };\n }\n\n const rows = Math.max(1, Math.floor(size));\n\n if (length <= rows) {\n return { start: 0, end: length };\n }\n\n const current = clamp(Math.trunc(cursor) || 0, 0, length - 1);\n const start = clamp(current - Math.floor(rows / 2), 0, length - rows);\n\n return { start, end: start + rows };\n}\n","import type { FC } from 'react';\nimport { useEffect, useState } from 'react';\nimport { Text } from 'ink';\n\nexport const SPINNER_FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];\n\nexport const Spinner: FC = () => {\n const [frame, setFrame] = useState(0);\n\n useEffect(() => {\n const id = setInterval(() => {\n setFrame((prev) => (prev + 1) % SPINNER_FRAMES.length);\n }, 80);\n\n return () => {\n clearInterval(id);\n };\n }, []);\n\n return <Text color=\"cyan\">{SPINNER_FRAMES[frame] ?? '⠋'}</Text>;\n};\n","import { createElement } from 'react';\nimport { render } from 'ink';\nimport type { Command } from 'commander';\nimport { BuildUI } from '../ui/BuildUI.js';\nimport { ensureGitignore } from '../lib/gitignore.js';\n\nexport function buildCommand(program: Command): void {\n program\n .command('build')\n .description('Bundle the plugin app into .kizenapp directory')\n .action(async () => {\n const pluginDir = process.cwd();\n const outputDir = `${pluginDir}/.kizenapp`;\n\n ensureGitignore(pluginDir);\n\n const { waitUntilExit } = render(createElement(BuildUI, { outputDir, pluginDir }));\n\n await waitUntilExit();\n });\n}\n","import type { FC } from 'react';\nimport { useEffect, useState } from 'react';\nimport { Box, Text, useApp } from 'ink';\nimport { PluginValidationError } from '@kizenapps/packager';\nimport type { ValidationIssue } from '@kizenapps/packager';\nimport { runBuild } from '../lib/runBuild.js';\nimport type { BuildStepName } from '../lib/runBuild.js';\nimport { formatBytes } from '../../shared/lib/formatBytes.js';\nimport { AppHeader } from './AppHeader.js';\nimport { Spinner } from './Spinner.js';\nimport { ValidationIssues } from './ValidationIssues.js';\n\ntype BuildStep = BuildStepName | 'done';\n\ninterface BuildUIProps {\n outputDir: string;\n pluginDir: string;\n}\n\nconst STEPS: BuildStepName[] = [\n 'creating-dir',\n 'reading-files',\n 'validating',\n 'minifying',\n 'packaging',\n 'writing-bundle',\n];\n\nconst STEP_LABELS: Record<BuildStepName, string> = {\n 'creating-dir': 'Creating .kizenapp directory',\n 'reading-files': 'Reading plugin files',\n validating: 'Validating plugin app',\n minifying: 'Minifying scripts',\n packaging: 'Packaging plugin',\n 'writing-bundle': 'Writing bundle.json',\n};\n\nexport const BuildUI: FC<BuildUIProps> = ({ outputDir, pluginDir }) => {\n const app = useApp();\n const [step, setStep] = useState<BuildStep>('creating-dir');\n const [failed, setFailed] = useState(false);\n const [issues, setIssues] = useState<ValidationIssue[] | null>(null);\n const [errorMessage, setErrorMessage] = useState<string | null>(null);\n const [bundleSize, setBundleSize] = useState<number | null>(null);\n\n useEffect(() => {\n void runBuild(pluginDir, outputDir, setStep)\n .then(({ bundleSize: size }) => {\n setBundleSize(size);\n setStep('done');\n })\n .catch((err: unknown) => {\n if (err instanceof PluginValidationError) {\n setIssues(err.issues);\n } else {\n setErrorMessage(err instanceof Error ? err.message : String(err));\n }\n\n // Leave `step` on the step that was running so the ✗ lands on it.\n setFailed(true);\n process.exitCode = 1;\n });\n }, [outputDir, pluginDir]);\n\n // Exit only once the terminal frame has been committed and written to the\n // terminal. Calling app.exit() in the same tick as the state updates would\n // unmount ink before it paints the done/error frame, leaving the spinner as\n // the last thing on screen.\n useEffect(() => {\n if (step === 'done' || failed) {\n app.exit();\n }\n }, [step, failed, app]);\n\n const currentIndex = STEPS.indexOf(step as BuildStepName);\n const isDone = step === 'done';\n\n return (\n <Box flexDirection=\"column\" paddingY={1} paddingX={2}>\n <AppHeader marginBottom={1} />\n\n <Box flexDirection=\"column\" gap={0}>\n {STEPS.map((s, i) => {\n const isActive = step === s;\n const isStepDone = isDone || currentIndex > i;\n const isFailed = failed && i === currentIndex;\n\n return (\n <Box key={s} gap={1}>\n {isFailed ? (\n <Text color=\"red\">✗ {STEP_LABELS[s]}</Text>\n ) : isStepDone ? (\n <Text color=\"green\">✓ {STEP_LABELS[s]}</Text>\n ) : isActive ? (\n <>\n <Spinner />\n <Text>{STEP_LABELS[s]}</Text>\n </>\n ) : (\n <Text dimColor> {STEP_LABELS[s]}</Text>\n )}\n </Box>\n );\n })}\n\n {isDone && bundleSize !== null && (\n <Box marginTop={1} gap={1}>\n <Text color=\"green\">✓ bundle — {formatBytes(bundleSize)}</Text>\n </Box>\n )}\n\n {issues !== null && <ValidationIssues issues={issues} />}\n\n {errorMessage !== null && (\n <Box marginTop={1} borderStyle=\"single\" borderColor=\"red\" paddingX={1}>\n <Text color=\"red\">{errorMessage}</Text>\n </Box>\n )}\n </Box>\n </Box>\n );\n};\n","export function formatBytes(n: number): string {\n if (n < 1024) {\n return `${String(n)} B`;\n }\n\n if (n < 1024 * 1024) {\n return `${(n / 1024).toFixed(1)} KB`;\n }\n\n return `${(n / (1024 * 1024)).toFixed(2)} MB`;\n}\n","import type { FC } from 'react';\nimport { Box, Text } from 'ink';\nimport type { ValidationIssue } from '@kizenapps/packager';\n\nconst groupIssuesByPath = (issues: ValidationIssue[]): Map<string, ValidationIssue[]> => {\n const groups = new Map<string, ValidationIssue[]>();\n\n for (const issue of issues) {\n const key = issue.path ?? issue.pluginApiName ?? 'general';\n const group = groups.get(key) ?? [];\n\n group.push(issue);\n groups.set(key, group);\n }\n\n return groups;\n};\n\ninterface ValidationIssuesProps {\n issues: ValidationIssue[];\n}\n\nexport const ValidationIssues: FC<ValidationIssuesProps> = ({ issues }) => {\n // The build only throws on error-severity issues, but `issues` also carries\n // any warnings; the header must count errors only, not the whole array.\n const errorCount = issues.filter((issue) => issue.severity === 'error').length;\n\n return (\n <Box flexDirection=\"column\" marginTop={1}>\n <Text color=\"red\">\n ✗ {errorCount} validation {errorCount === 1 ? 'error' : 'errors'}\n </Text>\n\n {[...groupIssuesByPath(issues)].map(([path, group]) => (\n <Box key={path} flexDirection=\"column\" marginTop={1}>\n <Text bold>{path}</Text>\n\n {group.map((issue, i) => (\n <Box key={`${issue.rule}-${String(i)}`} paddingLeft={2}>\n <Text color={issue.severity === 'error' ? 'red' : 'yellow'}>\n {issue.severity === 'error' ? '✗' : '⚠'} {issue.message}{' '}\n <Text dimColor>({issue.rule})</Text>\n </Text>\n </Box>\n ))}\n </Box>\n ))}\n </Box>\n );\n};\n","import { createElement } from 'react';\nimport { render } from 'ink';\nimport type { Command } from 'commander';\nimport { CreateUI } from '../ui/CreateUI.js';\nimport { loadGlobalCredentials } from '../lib/credentials.js';\nimport { createPlugin, precheckTargetDir } from '../lib/createPlugin.js';\nimport { runHeadlessCreate } from '../lib/createHeadless.js';\nimport type { CreateOptions } from '../lib/createHeadless.js';\nimport { ARTIFACT_TYPES } from '../lib/createArtifacts.js';\nimport { ENVIRONMENTS } from '../../shared/lib/credentials.js';\n\nexport function createCommand(program: Command): void {\n program\n .command('create')\n .description('Scaffold a new Kizen plugin project')\n .option('-n, --name <name>', 'plugin display name (implies a non-interactive run)')\n .option('-a, --api-name <name>', 'plugin api_name (inferred from --name when omitted)')\n .option('-d, --description <text>', 'plugin description')\n .option('-l, --external-link <url>', 'external link shown on the plugin listing')\n .option('-b, --business-id <id>', 'developer business id (defaults to saved credentials)')\n .option(\n '-e, --environment <env>',\n `environment the business id belongs to: ${ENVIRONMENTS.join(', ')} (defaults to saved credentials)`,\n )\n .option(\n '--artifacts <list>',\n `comma-separated artifact types, or \"all\" / \"none\" (default: all). Types: ${ARTIFACT_TYPES.join(', ')}`,\n )\n .action(async (options: CreateOptions) => {\n const parentDir = process.cwd();\n const globalCreds = await loadGlobalCredentials();\n const defaultBusinessId = globalCreds?.businessId ?? '';\n const defaultEnvironment = globalCreds?.environment ?? 'go';\n\n const suppliedFlags = Object.values(options).some((value) => value !== undefined);\n\n const isNonInteractive = !process.stdin.isTTY || !process.stdout.isTTY || suppliedFlags;\n\n if (isNonInteractive) {\n await runHeadlessCreate(\n options,\n { businessId: defaultBusinessId, environment: defaultEnvironment },\n parentDir,\n {\n precheckTargetDir,\n createPlugin,\n writeStdout: (text) => {\n process.stdout.write(text);\n },\n writeStderr: (text) => {\n process.stderr.write(text);\n },\n setExitCode: (code) => {\n process.exitCode = code;\n },\n },\n );\n\n return;\n }\n\n const { waitUntilExit } = render(\n createElement(CreateUI, { parentDir, defaultBusinessId, defaultEnvironment }),\n { exitOnCtrlC: false },\n );\n\n await waitUntilExit();\n });\n}\n","import type { FC } from 'react';\nimport { useCallback, useState } from 'react';\nimport { Box, Text, useApp, useInput } from 'ink';\nimport { join } from 'node:path';\nimport {\n buildManifest,\n createPlugin,\n findAvailableSubDir,\n precheckTargetDir,\n} from '../lib/createPlugin.js';\nimport type { PrecheckResult } from '../lib/createPlugin.js';\nimport {\n emptyValues,\n FIELD_LABELS,\n FIELDS,\n inferApiName,\n normalizeFieldValue,\n REQUIRED_FIELDS,\n toggleArtifactSelection,\n validateField,\n} from '../lib/createForm.js';\nimport type { FieldValues } from '../lib/createForm.js';\nimport { ARTIFACT_LABELS, ARTIFACT_TYPES } from '../lib/createArtifacts.js';\nimport type { ArtifactType } from '../lib/createArtifacts.js';\nimport type { Environment } from '../../shared/lib/credentials.js';\nimport { AppHeader } from './AppHeader.js';\n\ntype Mode = 'in-place' | 'sub-dir';\n\ntype Phase =\n | { type: 'target-select'; cursor: 0 | 1 }\n | { type: 'precheck-error'; targetDir: string; reason: PrecheckResult }\n | { type: 'field-entry'; field: number; values: FieldValues; fieldError?: string }\n | {\n type: 'artifact-select';\n values: FieldValues;\n cursor: number;\n selected: readonly ArtifactType[];\n }\n | { type: 'resolving-target' }\n | { type: 'confirm'; values: FieldValues; artifacts: readonly ArtifactType[] }\n | { type: 'writing' }\n | { type: 'done'; targetDir: string }\n | { type: 'error'; message: string };\n\ninterface CreateUIProps {\n parentDir: string;\n defaultBusinessId: string;\n defaultEnvironment: Environment;\n}\n\nconst Hint: FC<{ text: string }> = ({ text }) => <Text dimColor>{text}</Text>;\n\nexport const CreateUI: FC<CreateUIProps> = ({\n parentDir,\n defaultBusinessId,\n defaultEnvironment,\n}) => {\n const app = useApp();\n const [phase, setPhase] = useState<Phase>({ type: 'target-select', cursor: 0 });\n const [mode, setMode] = useState<Mode>('in-place');\n const [values, setValues] = useState<FieldValues>(() => emptyValues(defaultBusinessId));\n const [artifacts, setArtifacts] = useState<readonly ArtifactType[]>(() => [...ARTIFACT_TYPES]);\n const [inputBuffer, setInputBuffer] = useState('');\n const [targetDir, setTargetDir] = useState<string>(parentDir);\n\n const enterFieldEntry = useCallback((nextMode: Mode, initialValues: FieldValues): void => {\n setMode(nextMode);\n\n setInputBuffer(initialValues.name);\n\n setPhase({ type: 'field-entry', field: 0, values: initialValues });\n }, []);\n\n const runPrecheck = useCallback(\n async (dir: string): Promise<void> => {\n const result = await precheckTargetDir(dir);\n\n if (result !== 'ok') {\n setPhase({ type: 'precheck-error', targetDir: dir, reason: result });\n\n return;\n }\n\n setTargetDir(dir);\n\n enterFieldEntry('in-place', values);\n },\n [values, enterFieldEntry],\n );\n\n const resolveSubDirAndConfirm = useCallback(\n async (finalValues: FieldValues, artifacts: readonly ArtifactType[]): Promise<void> => {\n try {\n const dir = await findAvailableSubDir(parentDir, finalValues.apiName);\n\n setTargetDir(dir);\n\n setPhase({ type: 'confirm', values: finalValues, artifacts });\n } catch (err) {\n setPhase({\n type: 'error',\n message: err instanceof Error ? err.message : String(err),\n });\n }\n },\n [parentDir],\n );\n\n const runWrite = useCallback(\n async (\n finalValues: FieldValues,\n dir: string,\n artifacts: readonly ArtifactType[],\n ): Promise<void> => {\n try {\n await createPlugin({\n targetDir: dir,\n name: finalValues.name,\n apiName: finalValues.apiName,\n externalLink: finalValues.externalLink,\n description: finalValues.description,\n developerBusinessId: finalValues.developerBusinessId,\n developerEnvironment: defaultEnvironment,\n artifacts,\n });\n\n setPhase({ type: 'done', targetDir: dir });\n } catch (err) {\n setPhase({\n type: 'error',\n message: err instanceof Error ? err.message : String(err),\n });\n }\n },\n [defaultEnvironment],\n );\n\n useInput((input, key) => {\n if (key.ctrl && input === 'c') {\n app.exit();\n\n return;\n }\n\n if (phase.type === 'target-select') {\n if (key.upArrow) {\n setPhase({ type: 'target-select', cursor: 0 });\n } else if (key.downArrow) {\n setPhase({ type: 'target-select', cursor: 1 });\n } else if (key.return) {\n if (phase.cursor === 0) {\n void runPrecheck(parentDir);\n } else {\n enterFieldEntry('sub-dir', values);\n }\n } else if (key.escape) {\n app.exit();\n }\n\n return;\n }\n\n if (phase.type === 'precheck-error') {\n if (key.return || key.escape) {\n app.exit();\n }\n\n return;\n }\n\n if (phase.type === 'field-entry') {\n const { field, values: current } = phase;\n const fieldName = FIELDS[field];\n\n if (!fieldName) {\n return;\n }\n\n if (key.escape) {\n app.exit();\n\n return;\n }\n\n if (key.backspace || key.delete) {\n setInputBuffer((prev) => prev.slice(0, -1));\n\n return;\n }\n\n if (key.upArrow && field > 0) {\n const updated = { ...current, [fieldName]: inputBuffer };\n const prevField = field - 1;\n const prevName = FIELDS[prevField];\n\n setPhase({ type: 'field-entry', field: prevField, values: updated });\n\n setValues(updated);\n\n setInputBuffer(prevName ? updated[prevName] : '');\n\n return;\n }\n\n if (key.return || key.tab || key.downArrow) {\n const fieldError = validateField(fieldName, inputBuffer);\n\n if (fieldError !== undefined) {\n setPhase({ type: 'field-entry', field, values: current, fieldError });\n\n return;\n }\n\n const valueToStore = normalizeFieldValue(fieldName, inputBuffer);\n const updated = { ...current, [fieldName]: valueToStore };\n\n setValues(updated);\n\n const nextField = field + 1;\n\n if (nextField >= FIELDS.length) {\n setInputBuffer('');\n\n setPhase({\n type: 'artifact-select',\n values: updated,\n cursor: 0,\n selected: artifacts,\n });\n } else {\n const nextName = FIELDS[nextField];\n const existing = nextName ? updated[nextName] : '';\n const nextBuffer =\n nextName === 'apiName' && !existing ? inferApiName(updated.name) : existing;\n\n setPhase({ type: 'field-entry', field: nextField, values: updated });\n\n setInputBuffer(nextBuffer);\n }\n\n return;\n }\n\n if (input && !key.ctrl && !key.meta) {\n setInputBuffer((prev) => prev + input);\n }\n\n return;\n }\n\n if (phase.type === 'artifact-select') {\n const { cursor, selected, values: current } = phase;\n\n if (key.escape) {\n const lastField = FIELDS.length - 1;\n const lastName = FIELDS[lastField];\n\n setPhase({ type: 'field-entry', field: lastField, values: current });\n\n setInputBuffer(lastName ? current[lastName] : '');\n\n return;\n }\n\n if (key.upArrow) {\n setPhase({ ...phase, cursor: Math.max(0, cursor - 1) });\n\n return;\n }\n\n if (key.downArrow) {\n setPhase({ ...phase, cursor: Math.min(ARTIFACT_TYPES.length - 1, cursor + 1) });\n\n return;\n }\n\n if (input === ' ') {\n const type = ARTIFACT_TYPES[cursor];\n\n if (type) {\n const next = toggleArtifactSelection(selected, type);\n\n setArtifacts(next);\n\n setPhase({ ...phase, selected: next });\n }\n\n return;\n }\n\n if (input === 'a') {\n setArtifacts([...ARTIFACT_TYPES]);\n\n setPhase({ ...phase, selected: [...ARTIFACT_TYPES] });\n\n return;\n }\n\n if (input === 'n') {\n setArtifacts([]);\n\n setPhase({ ...phase, selected: [] });\n\n return;\n }\n\n if (key.return) {\n if (mode === 'sub-dir') {\n setPhase({ type: 'resolving-target' });\n\n void resolveSubDirAndConfirm(current, selected);\n } else {\n setPhase({ type: 'confirm', values: current, artifacts: selected });\n }\n }\n\n return;\n }\n\n if (phase.type === 'confirm') {\n if (key.escape) {\n setPhase({\n type: 'artifact-select',\n values: phase.values,\n cursor: 0,\n selected: phase.artifacts,\n });\n\n return;\n }\n\n if (key.return) {\n setPhase({ type: 'writing' });\n\n void runWrite(phase.values, targetDir, phase.artifacts);\n }\n\n return;\n }\n\n if (phase.type === 'done' || phase.type === 'error') {\n if (key.return || key.escape) {\n app.exit();\n }\n }\n });\n\n if (phase.type === 'target-select') {\n const options = [\n { label: 'Use current directory', desc: parentDir },\n { label: 'Create new sub-directory', desc: `${parentDir}/<inferred from API name>` },\n ];\n\n return (\n <Box flexDirection=\"column\" paddingY={1} paddingX={2} gap={1}>\n <AppHeader />\n <Box flexDirection=\"column\" gap={0}>\n <Text bold>Where should the new plugin live?</Text>\n {options.map((opt, i) => {\n const selected = phase.cursor === i;\n\n return (\n <Box key={opt.label} gap={2}>\n <Text {...(selected && { color: 'cyan' as const })}>{selected ? '❯' : ' '}</Text>\n <Text bold={selected} {...(selected && { color: 'cyan' as const })}>\n {opt.label}\n </Text>\n <Text dimColor>{opt.desc}</Text>\n </Box>\n );\n })}\n </Box>\n <Hint text=\"↑↓ to move · Enter to select · Esc to cancel\" />\n </Box>\n );\n }\n\n if (phase.type === 'precheck-error') {\n const { targetDir: dir, reason } = phase;\n const conflict = reason === 'has-manifest' ? 'kizen.json' : '.kizenapp/';\n\n return (\n <Box flexDirection=\"column\" paddingY={1} paddingX={2} gap={1}>\n <AppHeader />\n <Text color=\"red\" bold>\n Cannot create plugin\n </Text>\n <Box flexDirection=\"column\" gap={0}>\n <Text>\n {dir} already contains <Text bold>{conflict}</Text>.\n </Text>\n <Text dimColor>\n Remove the conflicting file/directory or choose a different target to avoid overwriting\n an existing plugin.\n </Text>\n </Box>\n <Hint text=\"Enter or Esc to exit\" />\n </Box>\n );\n }\n\n if (phase.type === 'field-entry') {\n const { field: activeField, fieldError } = phase;\n const targetLine =\n mode === 'sub-dir'\n ? `Target: sub-directory of ${parentDir} (inferred from API name)`\n : `Target: ${targetDir}`;\n\n return (\n <Box flexDirection=\"column\" paddingY={1} paddingX={2} gap={1}>\n <AppHeader />\n <Box flexDirection=\"column\" gap={0}>\n <Text bold>Plugin details</Text>\n <Text dimColor>{targetLine}</Text>\n </Box>\n {fieldError !== undefined && <Text color=\"red\">Error: {fieldError}</Text>}\n <Box flexDirection=\"column\" gap={0}>\n {FIELDS.map((name, i) => {\n const isActive = activeField === i;\n const displayValue = isActive ? inputBuffer : values[name];\n const isRequired = REQUIRED_FIELDS.includes(name);\n const label = `${FIELD_LABELS[name]}${isRequired ? '' : ' (optional)'}`;\n\n return (\n <Box key={name} gap={2}>\n <Box width={24}>\n <Text bold={isActive} {...(isActive && { color: 'cyan' as const })}>\n {label}\n </Text>\n </Box>\n <Text {...(isActive && { color: 'cyan' as const })}>{'>'}</Text>\n <Text>{displayValue}</Text>\n {isActive && <Text color=\"cyan\">{'█'}</Text>}\n </Box>\n );\n })}\n </Box>\n <Hint text=\"Enter/Tab/↓ next · ↑ previous · Backspace delete · Esc cancel\" />\n </Box>\n );\n }\n\n if (phase.type === 'artifact-select') {\n const { cursor, selected } = phase;\n\n return (\n <Box flexDirection=\"column\" paddingY={1} paddingX={2} gap={1}>\n <AppHeader />\n <Box flexDirection=\"column\" gap={0}>\n <Text bold>Which artifacts should we scaffold?</Text>\n <Text dimColor>Each one gets a directory with a config.json and a script that runs.</Text>\n </Box>\n <Box flexDirection=\"column\" gap={0}>\n {ARTIFACT_TYPES.map((type, i) => {\n const active = cursor === i;\n const checked = selected.includes(type);\n\n return (\n <Box key={type} gap={1}>\n <Text {...(active && { color: 'cyan' as const })}>{active ? '❯' : ' '}</Text>\n <Text {...(checked && { color: 'green' as const })}>{checked ? '◉' : '◯'}</Text>\n <Text bold={active} {...(active && { color: 'cyan' as const })}>\n {ARTIFACT_LABELS[type]}\n </Text>\n </Box>\n );\n })}\n </Box>\n <Hint text=\"↑↓ move · Space toggle · a all · n none · Enter continue · Esc back\" />\n </Box>\n );\n }\n\n if (phase.type === 'confirm') {\n const manifest = buildManifest({\n targetDir,\n name: phase.values.name,\n apiName: phase.values.apiName,\n externalLink: phase.values.externalLink,\n description: phase.values.description,\n developerBusinessId: phase.values.developerBusinessId,\n developerEnvironment: defaultEnvironment,\n });\n\n return (\n <Box flexDirection=\"column\" paddingY={1} paddingX={2} gap={1}>\n <AppHeader />\n <Box flexDirection=\"column\" gap={0}>\n <Text bold>Ready to create</Text>\n <Text dimColor>Target: {targetDir}</Text>\n </Box>\n <Box flexDirection=\"column\" gap={0}>\n <Text bold>kizen.json preview</Text>\n <Text>{JSON.stringify(manifest, null, 2)}</Text>\n </Box>\n <Box flexDirection=\"column\" gap={0}>\n <Text bold>Artifacts</Text>\n {phase.artifacts.length === 0 ? (\n <Text dimColor>{' '}none (src/ will hold only thumbnail.png)</Text>\n ) : (\n phase.artifacts.map((type) => (\n <Text key={type} dimColor>\n {' '}\n {ARTIFACT_LABELS[type]}\n </Text>\n ))\n )}\n </Box>\n <Box flexDirection=\"column\" gap={0}>\n <Text dimColor>Also creates:</Text>\n <Text dimColor>\n {' '}\n {join(targetDir, 'src/')}\n </Text>\n <Text dimColor>\n {' '}\n {join(targetDir, 'src/thumbnail.png')} (generated placeholder)\n </Text>\n <Text dimColor>\n {' '}\n {join(targetDir, 'releaseNotes/')}\n </Text>\n <Text dimColor>\n {' '}\n {join(targetDir, '.gitignore')} (adds .kizenapp/)\n </Text>\n </Box>\n <Hint text=\"Enter to create · Esc to go back\" />\n </Box>\n );\n }\n\n if (phase.type === 'resolving-target') {\n return (\n <Box paddingY={1} paddingX={2}>\n <Text dimColor>Finding available sub-directory…</Text>\n </Box>\n );\n }\n\n if (phase.type === 'writing') {\n return (\n <Box paddingY={1} paddingX={2}>\n <Text dimColor>Creating plugin…</Text>\n </Box>\n );\n }\n\n if (phase.type === 'done') {\n return (\n <Box flexDirection=\"column\" paddingY={1} paddingX={2} gap={1}>\n <AppHeader />\n <Text color=\"green\" bold>\n Plugin created at {phase.targetDir}\n </Text>\n <Box flexDirection=\"column\" gap={0}>\n <Text dimColor>Next steps:</Text>\n <Text>\n {' '}cd {phase.targetDir}\n </Text>\n <Text>{' '}npx --yes @kizenapps/cli dev</Text>\n <Text dimColor>{' '}Replace src/thumbnail.png with real artwork before publishing.</Text>\n </Box>\n <Hint text=\"Enter or Esc to exit\" />\n </Box>\n );\n }\n\n // error\n return (\n <Box flexDirection=\"column\" paddingY={1} paddingX={2} gap={1}>\n <AppHeader />\n <Text color=\"red\" bold>\n Failed to create plugin\n </Text>\n <Text>{phase.message}</Text>\n <Hint text=\"Enter or Esc to exit\" />\n </Box>\n );\n};\n","import { access, mkdir, writeFile } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\nimport { ensureGitignore } from './gitignore.js';\nimport { scaffoldArtifactFiles } from './createArtifacts.js';\nimport type { ArtifactType, ScaffoldedFile } from './createArtifacts.js';\nimport { claudeFiles, copilotFiles } from './createCopilotFiles.js';\nimport { thumbnailBytes } from './createThumbnail.js';\nimport type { Environment } from '../../shared/lib/credentials.js';\n\nconst THUMBNAIL_PATH = 'src/thumbnail.png';\n\nconst PROD_ENVIRONMENTS: readonly Environment[] = ['go', 'fmo'];\n\nexport interface CreatePluginInput {\n targetDir: string;\n name: string;\n apiName: string;\n externalLink: string;\n description: string;\n developerBusinessId: string;\n developerEnvironment: Environment;\n artifacts?: readonly ArtifactType[];\n}\n\nexport type PrecheckResult = 'ok' | 'has-manifest' | 'has-kizenapp';\n\nasync function pathExists(path: string): Promise<boolean> {\n try {\n await access(path);\n\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function precheckTargetDir(dir: string): Promise<PrecheckResult> {\n if (await pathExists(join(dir, 'kizen.json'))) {\n return 'has-manifest';\n }\n\n if (await pathExists(join(dir, '.kizenapp'))) {\n return 'has-kizenapp';\n }\n\n return 'ok';\n}\n\nexport async function findAvailableSubDir(parentDir: string, baseName: string): Promise<string> {\n const base = join(parentDir, baseName);\n\n if (!(await pathExists(base))) {\n return base;\n }\n\n for (let i = 1; i < 1000; i++) {\n const candidate = join(parentDir, `${baseName}-${String(i)}`);\n\n if (!(await pathExists(candidate))) {\n return candidate;\n }\n }\n\n throw new Error(`Could not find an available directory name for \"${baseName}\"`);\n}\n\nexport function buildManifest(input: CreatePluginInput): Record<string, unknown> {\n const businessId = input.developerBusinessId.trim();\n\n const targetEnvironments =\n businessId !== '' && !PROD_ENVIRONMENTS.includes(input.developerEnvironment)\n ? [input.developerEnvironment]\n : ['prod'];\n\n return {\n name: input.name,\n version: '1.0.0',\n published: true,\n api_name: input.apiName,\n external_link: input.externalLink,\n description: input.description,\n entry: 'src/',\n engine: '1.0.0',\n release_notes_directory: 'releaseNotes/',\n release_environments: targetEnvironments,\n config_template: {},\n base_config: {},\n ...(businessId ? { developer_business_id: { [input.developerEnvironment]: businessId } } : {}),\n };\n}\n\nasync function writeScaffoldedFiles(\n targetDir: string,\n scaffolded: readonly ScaffoldedFile[],\n): Promise<void> {\n const files = scaffolded.map((file) => ({\n fullPath: join(targetDir, ...file.path.split('/')),\n content: file.content,\n }));\n\n const directories = new Set(files.map((file) => dirname(file.fullPath)));\n\n await Promise.all([...directories].map((dir) => mkdir(dir, { recursive: true })));\n\n await Promise.all(files.map((file) => writeFile(file.fullPath, file.content, 'utf-8')));\n}\n\nexport async function createPlugin(input: CreatePluginInput): Promise<void> {\n await mkdir(input.targetDir, { recursive: true });\n\n const manifest = buildManifest(input);\n\n await writeFile(\n join(input.targetDir, 'kizen.json'),\n JSON.stringify(manifest, null, 2) + '\\n',\n 'utf-8',\n );\n\n await mkdir(join(input.targetDir, 'src'), { recursive: true });\n\n await mkdir(join(input.targetDir, 'releaseNotes'), { recursive: true });\n\n await Promise.all([\n writeScaffoldedFiles(input.targetDir, scaffoldArtifactFiles(input.artifacts ?? [])),\n writeScaffoldedFiles(input.targetDir, copilotFiles()),\n writeScaffoldedFiles(input.targetDir, claudeFiles()),\n writeFile(join(input.targetDir, ...THUMBNAIL_PATH.split('/')), thumbnailBytes(input.apiName)),\n ]);\n\n ensureGitignore(input.targetDir);\n}\n","{\n \"name\": \"Hello Frame\",\n \"api_name\": \"hello_frame\",\n \"title\": \"Hello Frame\",\n \"default_position\": \"bottom-right\",\n \"minimized_style\": \"circle\",\n \"height\": 320,\n \"width\": 280\n}\n","this.outputUI(`\n <div class=\"hello-frame\">\n <h2 class=\"hello-frame__title\">Hello from a floating frame</h2>\n <p class=\"hello-frame__body\">Edit src/floatingFrames/helloFrame/script.js to change this.</p>\n </div>\n`);\n",".hello-frame {\n padding: 16px;\n font-family: system-ui, sans-serif;\n}\n\n.hello-frame__title {\n margin: 0 0 8px;\n font-size: 16px;\n}\n\n.hello-frame__body {\n margin: 0;\n color: #555;\n}\n","{\n \"name\": \"Hello Block\",\n \"api_name\": \"hello_block\",\n \"types\": [\"dashboards\"]\n}\n","this.outputUI(`\n <div class=\"hello-block\">\n <h2 class=\"hello-block__title\">Hello from a block</h2>\n <p class=\"hello-block__body\">Edit src/blocks/helloBlock/script.js to change this.</p>\n </div>\n`);\n",".hello-block {\n padding: 16px;\n font-family: system-ui, sans-serif;\n background: #f8fafc;\n border-radius: 6px;\n}\n\n.hello-block__title {\n margin: 0 0 8px;\n font-size: 16px;\n}\n\n.hello-block__body {\n margin: 0;\n color: #555;\n}\n","{\n \"icon\": \"phone\",\n \"color\": \"#0ea5e9\",\n \"tooltip\": \"Hello adornment\",\n \"field_type\": \"phonenumber\"\n}\n","this.showToast('Hello from a data adornment.', { variant: 'success' });\n","{\n \"name\": \"Hello Page\",\n \"api_name\": \"hello_page\"\n}\n","this.outputUI(`\n <div class=\"hello-page\">\n <p class=\"hello-page__loading\">Loading…</p>\n </div>\n`);\n\nthis.runEventScript('greet');\n",".hello-page {\n padding: 24px;\n font-family: system-ui, sans-serif;\n}\n\n.hello-page__title {\n margin: 0 0 8px;\n font-size: 20px;\n}\n\n.hello-page__body {\n margin: 0 0 16px;\n color: #555;\n}\n\n.hello-page__loading {\n margin: 0;\n color: #94a3b8;\n}\n\n.hello-page__actions {\n display: flex;\n gap: 8px;\n}\n\n.hello-page__button {\n padding: 6px 12px;\n font: inherit;\n color: #0f172a;\n background: #e2e8f0;\n border: 0;\n border-radius: 4px;\n cursor: pointer;\n}\n\n.hello-page__button:hover {\n background: #cbd5e1;\n}\n","const tone = this.args?.formData?.tone?.[0] ?? 'plain';\n\nconst greeting = tone === 'cheer' ? 'Hello, and good to see you!' : 'Hello from a routable page.';\n\nthis.outputUI(`\n <div class=\"hello-page\">\n <h1 class=\"hello-page__title\">${greeting}</h1>\n <p class=\"hello-page__body\">\n This markup came from eventScripts/greet.js. Either button re-runs it and\n repaints the page with a different greeting.\n </p>\n <div class=\"hello-page__actions\">\n <form data-script=\"greet\">\n <input type=\"hidden\" name=\"tone\" value=\"plain\" />\n <button class=\"hello-page__button\" type=\"submit\">Plain</button>\n </form>\n <form data-script=\"greet\">\n <input type=\"hidden\" name=\"tone\" value=\"cheer\" />\n <button class=\"hello-page__button\" type=\"submit\">Cheerful</button>\n </form>\n </div>\n </div>\n`);\n","{\n \"api_name\": \"hello_toolbar_item\",\n \"label\": \"Hello Toolbar Item\",\n \"icon\": \"star\",\n \"color\": \"#0ea5e9\"\n}\n","this.showToast('Hello from a toolbar item.', { variant: 'success' });\n","{\n \"api_name\": \"hello_object_settings_item\",\n \"label\": \"Hello Object Settings\"\n}\n","this.showToast('Hello from an object settings item.', { variant: 'success' });\n","{\n \"name\": \"Hello Action\",\n \"api_name\": \"hello_action\",\n \"hint_object_name\": \"client_client\"\n}\n","this.showToast('Hello from a JS action.', { variant: 'success' });\n","import helloFrameConfig from '../templates/artifacts/floatingFrames/helloFrame/config.json?raw';\nimport helloFrameScript from '../templates/artifacts/floatingFrames/helloFrame/script.js?raw';\nimport helloFrameStyles from '../templates/artifacts/floatingFrames/helloFrame/styles.css?raw';\nimport helloBlockConfig from '../templates/artifacts/blocks/helloBlock/config.json?raw';\nimport helloBlockScript from '../templates/artifacts/blocks/helloBlock/script.js?raw';\nimport helloBlockStyles from '../templates/artifacts/blocks/helloBlock/styles.css?raw';\nimport helloAdornmentConfig from '../templates/artifacts/dataAdornments/helloAdornment/config.json?raw';\nimport helloAdornmentScript from '../templates/artifacts/dataAdornments/helloAdornment/script.js?raw';\nimport helloPageConfig from '../templates/artifacts/pages/helloPage/config.json?raw';\nimport helloPageScript from '../templates/artifacts/pages/helloPage/script.js?raw';\nimport helloPageStyles from '../templates/artifacts/pages/helloPage/styles.css?raw';\nimport helloPageGreet from '../templates/artifacts/pages/helloPage/eventScripts/greet.js?raw';\nimport helloToolbarItemConfig from '../templates/artifacts/toolbarItems/helloToolbarItem/config.json?raw';\nimport helloToolbarItemScript from '../templates/artifacts/toolbarItems/helloToolbarItem/script.js?raw';\nimport helloObjectSettingsItemConfig from '../templates/artifacts/objectSettingsItems/helloObjectSettingsItem/config.json?raw';\nimport helloObjectSettingsItemScript from '../templates/artifacts/objectSettingsItems/helloObjectSettingsItem/script.js?raw';\nimport helloActionConfig from '../templates/artifacts/actions/helloAction/config.json?raw';\nimport helloActionScript from '../templates/artifacts/actions/helloAction/script.js?raw';\n\nexport const ARTIFACT_TYPES = [\n 'floatingFrame',\n 'block',\n 'dataAdornment',\n 'page',\n 'toolbarItem',\n 'objectSettingsItem',\n 'jsAction',\n] as const;\n\nexport type ArtifactType = (typeof ARTIFACT_TYPES)[number];\n\nexport const ARTIFACT_LABELS: Record<ArtifactType, string> = {\n floatingFrame: 'Floating frame',\n block: 'Block',\n dataAdornment: 'Data adornment',\n page: 'Routable page',\n toolbarItem: 'Toolbar item',\n objectSettingsItem: 'Object settings item',\n jsAction: 'JS action',\n};\n\nexport interface ScaffoldedFile {\n path: string;\n content: string;\n}\n\ninterface ArtifactTemplate {\n directory: string;\n component: string;\n files: Readonly<Record<string, string>>;\n}\n\nconst TEMPLATES: Record<ArtifactType, ArtifactTemplate> = {\n floatingFrame: {\n directory: 'floatingFrames',\n component: 'helloFrame',\n files: {\n 'config.json': helloFrameConfig,\n 'script.js': helloFrameScript,\n 'styles.css': helloFrameStyles,\n },\n },\n\n block: {\n directory: 'blocks',\n component: 'helloBlock',\n files: {\n 'config.json': helloBlockConfig,\n 'script.js': helloBlockScript,\n 'styles.css': helloBlockStyles,\n },\n },\n\n dataAdornment: {\n directory: 'dataAdornments',\n component: 'helloAdornment',\n files: {\n 'config.json': helloAdornmentConfig,\n 'script.js': helloAdornmentScript,\n },\n },\n\n page: {\n directory: 'pages',\n component: 'helloPage',\n files: {\n 'config.json': helloPageConfig,\n 'script.js': helloPageScript,\n 'styles.css': helloPageStyles,\n 'eventScripts/greet.js': helloPageGreet,\n },\n },\n\n toolbarItem: {\n directory: 'toolbarItems',\n component: 'helloToolbarItem',\n files: {\n 'config.json': helloToolbarItemConfig,\n 'script.js': helloToolbarItemScript,\n },\n },\n\n objectSettingsItem: {\n directory: 'objectSettingsItems',\n component: 'helloObjectSettingsItem',\n files: {\n 'config.json': helloObjectSettingsItemConfig,\n 'script.js': helloObjectSettingsItemScript,\n },\n },\n\n jsAction: {\n directory: 'actions',\n component: 'helloAction',\n files: {\n 'config.json': helloActionConfig,\n 'script.js': helloActionScript,\n },\n },\n};\n\nexport function artifactFiles(type: ArtifactType, entryDir = 'src'): ScaffoldedFile[] {\n const { directory, component, files } = TEMPLATES[type];\n\n return Object.entries(files).map(([relativePath, content]) => ({\n path: `${entryDir}/${directory}/${component}/${relativePath}`,\n content,\n }));\n}\n\nexport function scaffoldArtifactFiles(\n types: readonly ArtifactType[],\n entryDir = 'src',\n): ScaffoldedFile[] {\n return [...new Set(types)].flatMap((type) => artifactFiles(type, entryDir));\n}\n","import { deflateSync } from 'node:zlib';\n\nexport const THUMBNAIL_SIZE = 512;\n\nconst BODY_HALF_SIZE = 150;\n\nconst BODY_CORNER_RADIUS = 26;\n\nconst KNOB_RADIUS = 46;\n\nconst KNOB_OFFSET_RATIO = 0.6;\n\nconst NECK_HALF_WIDTH = KNOB_RADIUS * 0.55;\n\nconst SATURATION = 0.55;\n\nconst LIGHTNESS = 0.47;\n\nexport interface ThumbnailStyle {\n hue: number;\n quarterTurns: 0 | 1 | 2 | 3;\n}\n\nfunction fnv1a(text: string): number {\n let hash = 0x811c9dc5;\n\n for (let i = 0; i < text.length; i += 1) {\n hash ^= text.charCodeAt(i);\n\n hash = (hash + ((hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24))) >>> 0;\n }\n\n return hash;\n}\n\nexport function thumbnailStyle(apiName: string): ThumbnailStyle {\n const hash = fnv1a(apiName);\n\n return {\n hue: hash % 360,\n quarterTurns: ((hash >>> 16) % 4) as 0 | 1 | 2 | 3,\n };\n}\n\nfunction hslToRgb(hue: number, saturation: number, lightness: number): [number, number, number] {\n const chroma = (1 - Math.abs(2 * lightness - 1)) * saturation;\n const sector = hue / 60;\n const secondary = chroma * (1 - Math.abs((sector % 2) - 1));\n const match = lightness - chroma / 2;\n\n const [r, g, b] =\n sector < 1\n ? [chroma, secondary, 0]\n : sector < 2\n ? [secondary, chroma, 0]\n : sector < 3\n ? [0, chroma, secondary]\n : sector < 4\n ? [0, secondary, chroma]\n : sector < 5\n ? [secondary, 0, chroma]\n : [chroma, 0, secondary];\n\n return [\n Math.round((r + match) * 255),\n Math.round((g + match) * 255),\n Math.round((b + match) * 255),\n ];\n}\n\nfunction roundedBoxDistance(\n x: number,\n y: number,\n halfW: number,\n halfH: number,\n radius: number,\n): number {\n const qx = Math.abs(x) - halfW + radius;\n const qy = Math.abs(y) - halfH + radius;\n\n return Math.hypot(Math.max(qx, 0), Math.max(qy, 0)) + Math.min(Math.max(qx, qy), 0) - radius;\n}\n\nfunction circleDistance(x: number, y: number, cx: number, cy: number, radius: number): number {\n return Math.hypot(x - cx, y - cy) - radius;\n}\n\nfunction puzzlePieceDistance(x: number, y: number): number {\n const s = BODY_HALF_SIZE;\n const k = KNOB_RADIUS;\n const offset = k * KNOB_OFFSET_RATIO;\n const neckHalf = NECK_HALF_WIDTH;\n\n let d = roundedBoxDistance(x, y, s, s, BODY_CORNER_RADIUS);\n\n const topKnob = Math.min(\n circleDistance(x, y, 0, -s - offset, k),\n roundedBoxDistance(x, y + s + offset / 2, neckHalf, offset / 2 + 1, 0),\n );\n\n const rightKnob = Math.min(\n circleDistance(x, y, s + offset, 0, k),\n roundedBoxDistance(x - s - offset / 2, y, offset / 2 + 1, neckHalf, 0),\n );\n\n d = Math.min(d, topKnob, rightKnob);\n\n const bottomSocket = Math.min(\n circleDistance(x, y, 0, s - offset, k),\n roundedBoxDistance(x, y - s + offset / 2, neckHalf, offset / 2 + 1, 0),\n );\n\n const leftSocket = Math.min(\n circleDistance(x, y, -s + offset, 0, k),\n roundedBoxDistance(x + s - offset / 2, y, offset / 2 + 1, neckHalf, 0),\n );\n\n return Math.max(d, -bottomSocket, -leftSocket);\n}\n\nfunction renderPixels(style: ThumbnailStyle): Uint8Array {\n const size = THUMBNAIL_SIZE;\n const pixels = new Uint8Array(size * size * 4);\n const [r, g, b] = hslToRgb(style.hue, SATURATION, LIGHTNESS);\n\n const knobExtension = KNOB_RADIUS * (1 + KNOB_OFFSET_RATIO);\n const centre = (size - 1) / 2;\n const shift = knobExtension / 2;\n\n for (let py = 0; py < size; py += 1) {\n for (let px = 0; px < size; px += 1) {\n let x = px - centre;\n let y = py - centre;\n\n for (let turn = 0; turn < style.quarterTurns; turn += 1) {\n [x, y] = [-y, x];\n }\n\n const d = puzzlePieceDistance(x + shift, y - shift);\n\n const coverage = Math.min(1, Math.max(0, 0.5 - d));\n\n if (coverage <= 0) {\n continue;\n }\n\n const i = (py * size + px) * 4;\n\n pixels[i] = r;\n pixels[i + 1] = g;\n pixels[i + 2] = b;\n pixels[i + 3] = Math.round(coverage * 255);\n }\n }\n\n return pixels;\n}\n\nconst CRC_TABLE = new Uint32Array(256).map((_, n) => {\n let c = n;\n\n for (let k = 0; k < 8; k += 1) {\n c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;\n }\n\n return c >>> 0;\n});\n\nfunction crc32(bytes: Uint8Array): number {\n let crc = 0xffffffff;\n\n for (const byte of bytes) {\n crc = (CRC_TABLE[(crc ^ byte) & 0xff] ?? 0) ^ (crc >>> 8);\n }\n\n return (crc ^ 0xffffffff) >>> 0;\n}\n\nfunction pngChunk(type: string, data: Uint8Array): Buffer {\n const typeBytes = Buffer.from(type, 'latin1');\n const length = Buffer.alloc(4);\n\n length.writeUInt32BE(data.length);\n\n const crc = Buffer.alloc(4);\n\n crc.writeUInt32BE(crc32(Buffer.concat([typeBytes, data])));\n\n return Buffer.concat([length, typeBytes, data, crc]);\n}\n\nconst PNG_SIGNATURE = Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]);\n\nexport function encodePng(width: number, height: number, rgba: Uint8Array): Buffer {\n if (rgba.length !== width * height * 4) {\n throw new Error(\n `encodePng: expected ${String(width * height * 4)} bytes of RGBA for ${String(width)}x${String(height)}, got ${String(rgba.length)}`,\n );\n }\n\n const ihdr = Buffer.alloc(13);\n\n ihdr.writeUInt32BE(width, 0);\n ihdr.writeUInt32BE(height, 4);\n ihdr[8] = 8;\n ihdr[9] = 6;\n\n const stride = width * 4;\n const raw = Buffer.alloc((stride + 1) * height);\n\n for (let y = 0; y < height; y += 1) {\n raw.set(rgba.subarray(y * stride, (y + 1) * stride), y * (stride + 1) + 1);\n }\n\n return Buffer.concat([\n PNG_SIGNATURE,\n pngChunk('IHDR', ihdr),\n pngChunk('IDAT', deflateSync(raw, { level: 9 })),\n pngChunk('IEND', new Uint8Array(0)),\n ]);\n}\n\nexport function thumbnailBytes(apiName: string): Buffer {\n return encodePng(THUMBNAIL_SIZE, THUMBNAIL_SIZE, renderPixels(thumbnailStyle(apiName)));\n}\n","import { ARTIFACT_TYPES } from './createArtifacts.js';\nimport type { ArtifactType } from './createArtifacts.js';\n\nexport const FIELDS = [\n 'name',\n 'apiName',\n 'externalLink',\n 'description',\n 'developerBusinessId',\n] as const;\n\nexport type FieldName = (typeof FIELDS)[number];\n\nexport const FIELD_LABELS: Record<FieldName, string> = {\n name: 'Name',\n apiName: 'API name',\n externalLink: 'External link',\n description: 'Description',\n developerBusinessId: 'Business ID',\n};\n\nexport const REQUIRED_FIELDS: readonly FieldName[] = ['name', 'apiName', 'description'];\n\nexport type FieldValues = Record<FieldName, string>;\n\nexport const API_NAME_PATTERN = /^[a-z_][a-z0-9_]+$/;\n\nexport const API_NAME_HINT =\n 'must start with a letter or underscore and contain only lowercase letters, numbers, or underscores (minimum 2 characters)';\n\nexport function inferApiName(name: string): string {\n return name\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '_')\n .replace(/^_+|_+$/g, '');\n}\n\nexport function emptyValues(defaultBusinessId: string): FieldValues {\n return {\n name: '',\n apiName: '',\n externalLink: '',\n description: '',\n developerBusinessId: defaultBusinessId,\n };\n}\n\nexport function validateField(fieldName: FieldName, inputBuffer: string): string | undefined {\n const value = inputBuffer.trim();\n\n if (REQUIRED_FIELDS.includes(fieldName) && !value) {\n return `${FIELD_LABELS[fieldName]} is required`;\n }\n\n if (fieldName === 'apiName' && !API_NAME_PATTERN.test(value)) {\n return `${FIELD_LABELS[fieldName]} ${API_NAME_HINT}`;\n }\n\n return undefined;\n}\n\nexport function normalizeFieldValue(fieldName: FieldName, inputBuffer: string): string {\n return fieldName === 'description' ? inputBuffer : inputBuffer.trim();\n}\n\nexport function toggleArtifactSelection(\n selected: readonly ArtifactType[],\n type: ArtifactType,\n): ArtifactType[] {\n const next = new Set(selected);\n\n if (next.has(type)) {\n next.delete(type);\n } else {\n next.add(type);\n }\n\n return ARTIFACT_TYPES.filter((candidate) => next.has(candidate));\n}\n","import { ARTIFACT_TYPES } from './createArtifacts.js';\nimport type { ArtifactType } from './createArtifacts.js';\nimport { API_NAME_HINT, API_NAME_PATTERN, inferApiName } from './createForm.js';\nimport type { CreatePluginInput, PrecheckResult } from './createPlugin.js';\nimport { ENVIRONMENTS } from '../../shared/lib/credentials.js';\nimport type { Environment } from '../../shared/lib/credentials.js';\n\nexport const PLACEHOLDER_DESCRIPTION = 'A hello-world Kizen plugin.';\n\nexport interface CreateOptions {\n name?: string;\n apiName?: string;\n description?: string;\n externalLink?: string;\n businessId?: string;\n environment?: string;\n artifacts?: string;\n}\n\nexport interface HeadlessDefaults {\n businessId: string;\n environment: Environment;\n}\n\nexport function parseArtifactSelection(raw: string | undefined): ArtifactType[] {\n if (raw === undefined || raw.trim() === '' || raw.trim() === 'all') {\n return [...ARTIFACT_TYPES];\n }\n\n if (raw.trim() === 'none') {\n return [];\n }\n\n const requested = raw\n .split(',')\n .map((part) => part.trim())\n .filter((part) => part !== '');\n\n const unknown = requested.filter((part) => !ARTIFACT_TYPES.includes(part as ArtifactType));\n\n if (unknown.length > 0) {\n throw new Error(\n `Unknown artifact type(s): ${unknown.join(', ')}. Valid types: ${ARTIFACT_TYPES.join(', ')}, or \"all\" / \"none\".`,\n );\n }\n\n return [...new Set(requested as ArtifactType[])];\n}\n\nexport function resolveHeadlessInput(\n options: CreateOptions,\n defaults: HeadlessDefaults,\n targetDir: string,\n): CreatePluginInput {\n const name = options.name?.trim() ?? '';\n\n if (name === '') {\n throw new Error('--name is required for a non-interactive run.');\n }\n\n const apiName = (options.apiName?.trim() ?? '') || inferApiName(name);\n\n if (!API_NAME_PATTERN.test(apiName)) {\n throw new Error(`api_name \"${apiName}\" is invalid: ${API_NAME_HINT}. Pass --api-name.`);\n }\n\n const description = options.description?.trim();\n\n const developerBusinessId = options.businessId?.trim() ?? defaults.businessId;\n const developerEnvironment = resolveEnvironment(options, defaults);\n\n return {\n targetDir,\n name,\n apiName,\n externalLink: options.externalLink?.trim() ?? '',\n description:\n description === undefined || description === '' ? PLACEHOLDER_DESCRIPTION : description,\n developerBusinessId,\n developerEnvironment,\n artifacts: parseArtifactSelection(options.artifacts),\n };\n}\n\nfunction isEnvironment(value: string): value is Environment {\n return (ENVIRONMENTS as readonly string[]).includes(value);\n}\n\nfunction resolveEnvironment(options: CreateOptions, defaults: HeadlessDefaults): Environment {\n const requested = options.environment?.trim();\n\n if (requested !== undefined && requested !== '') {\n if (!isEnvironment(requested)) {\n throw new Error(\n `Unknown environment \"${requested}\". Valid environments: ${ENVIRONMENTS.join(', ')}.`,\n );\n }\n\n return requested;\n }\n\n if (options.businessId !== undefined && defaults.businessId === '') {\n throw new Error(\n '--environment is required alongside --business-id when no credentials are saved, so the id is keyed to the environment that issued it.',\n );\n }\n\n return defaults.environment;\n}\n\nexport interface HeadlessDeps {\n precheckTargetDir: (dir: string) => Promise<PrecheckResult>;\n createPlugin: (input: CreatePluginInput) => Promise<void>;\n writeStdout: (text: string) => void;\n writeStderr: (text: string) => void;\n setExitCode: (code: number) => void;\n}\n\nexport async function runHeadlessCreate(\n options: CreateOptions,\n defaults: HeadlessDefaults,\n targetDir: string,\n deps: HeadlessDeps,\n): Promise<void> {\n let input: CreatePluginInput;\n\n try {\n input = resolveHeadlessInput(options, defaults, targetDir);\n } catch (err) {\n deps.writeStderr(`Error: ${err instanceof Error ? err.message : String(err)}\\n`);\n\n deps.setExitCode(1);\n\n return;\n }\n\n const precheck = await deps.precheckTargetDir(targetDir);\n\n if (precheck !== 'ok') {\n const conflict = precheck === 'has-manifest' ? 'kizen.json' : '.kizenapp/';\n\n deps.writeStderr(\n `Error: ${targetDir} already contains ${conflict}. Refusing to overwrite an existing plugin.\\n`,\n );\n\n deps.setExitCode(1);\n\n return;\n }\n\n try {\n await deps.createPlugin(input);\n } catch (err) {\n deps.writeStderr(`Error: ${err instanceof Error ? err.message : String(err)}\\n`);\n\n deps.setExitCode(1);\n\n return;\n }\n\n const artifactSummary =\n input.artifacts && input.artifacts.length > 0 ? input.artifacts.join(', ') : 'none';\n\n deps.writeStdout(`Created plugin ${input.apiName} at ${targetDir}\\n`);\n\n deps.writeStdout(`Artifacts: ${artifactSummary}\\n`);\n\n deps.writeStdout(\n 'Thumbnail: src/thumbnail.png (generated placeholder; replace it before publishing)\\n',\n );\n\n if (input.developerBusinessId.trim() === '') {\n deps.writeStderr(\n 'Warning: no developer_business_id configured, so this plugin cannot be preview-published yet.\\n',\n );\n }\n}\n","import { createElement } from 'react';\nimport { render } from 'ink';\nimport type { Command } from 'commander';\nimport { DevUI } from '../ui/DevUI.js';\nimport { CredentialSetupUI } from '../ui/CredentialSetupUI.js';\nimport type { CredentialMode, CredentialSetupResult } from '../ui/CredentialSetupUI.js';\nimport {\n loadCredentialProfile,\n loadCredentialsFromFile,\n loadGlobalCredentials,\n} from '../lib/credentials.js';\nimport type { Credentials } from '../lib/credentials.js';\nimport { loadConfig, saveConfig } from '../lib/config.js';\nimport { ensureGitignore } from '../lib/gitignore.js';\n\nasync function runSetupUI(initialMode?: CredentialMode): Promise<CredentialSetupResult> {\n return new Promise((resolve) => {\n let unmountFn: (() => void) | null = null;\n const handleComplete = (result: CredentialSetupResult): void => {\n unmountFn?.();\n\n resolve(result);\n };\n\n const { unmount } = render(\n createElement(CredentialSetupUI, {\n ...(initialMode !== undefined && { initialMode }),\n onComplete: handleComplete,\n }),\n { exitOnCtrlC: false },\n );\n\n unmountFn = unmount;\n });\n}\n\nexport function devCommand(program: Command): void {\n program\n .command('dev')\n .description('Start the plugin viewer dev server')\n .option('-p, --port <port>', 'port to listen on', '3121')\n .option('-c, --credentials <path>', 'path to a credentials JSON file')\n .option('-d, --debug', 'Enable CDP lifecycle logs in the TUI')\n .option('-v, --verbose', 'Log every CDP event and handled error (implies --debug)')\n .option('--no-viewer', \"Don't auto-launch the viewer on startup (press [v] to launch manually)\")\n .option('--no-cache', 'Disable the network proxy cache (always fetch upstream)')\n .action(\n async (options: {\n port: string;\n credentials?: string;\n debug?: boolean;\n verbose?: boolean;\n viewer?: boolean;\n cache?: boolean;\n }) => {\n const port = parseInt(options.port, 10);\n const pluginDir = process.cwd();\n const outputDir = `${pluginDir}/.kizenapp`;\n\n ensureGitignore(pluginDir);\n\n let credentials: Credentials | null = null;\n let credentialMode: CredentialMode | undefined;\n let activeCredentialProfile: string | undefined;\n const { lastPath } = await loadConfig(outputDir);\n\n if (options.credentials) {\n credentials = await loadCredentialsFromFile(options.credentials);\n } else {\n const config = await loadConfig(outputDir);\n\n if (config.credentialMode === 'local') {\n credentialMode = 'local';\n } else if (config.credentialMode === 'global') {\n credentialMode = 'global';\n\n activeCredentialProfile = config.activeCredentialProfile;\n\n // Load silently — only show TUI if the file was deleted since last run\n if (activeCredentialProfile) {\n credentials = await loadCredentialProfile(activeCredentialProfile);\n\n if (!credentials) {\n // Named profile file missing, fall back to default\n credentials = await loadGlobalCredentials();\n\n activeCredentialProfile = undefined;\n }\n } else {\n credentials = await loadGlobalCredentials();\n }\n\n if (!credentials) {\n const result = await runSetupUI('global');\n\n credentials = result.credentials;\n\n activeCredentialProfile = result.profileName;\n }\n } else {\n // First run — show full mode selection TUI\n const result = await runSetupUI();\n\n credentials = result.credentials;\n\n credentialMode = result.mode;\n\n activeCredentialProfile = result.profileName;\n\n const profile = result.profileName;\n\n await saveConfig(outputDir, {\n credentialMode: result.mode,\n ...(profile !== undefined && { activeCredentialProfile: profile }),\n });\n }\n }\n\n const verbose = options.verbose === true;\n const debug = verbose || options.debug === true;\n const autoViewer = options.viewer !== false;\n const cacheEnabled = options.cache !== false;\n\n const { waitUntilExit } = render(\n createElement(DevUI, {\n port,\n pluginDir,\n outputDir,\n credentials,\n ...(credentialMode !== undefined && { credentialMode }),\n ...(activeCredentialProfile !== undefined && { activeCredentialProfile }),\n ...(lastPath !== undefined && { lastPath }),\n debug,\n verbose,\n autoViewer,\n cacheEnabled,\n }),\n { exitOnCtrlC: false },\n );\n\n await waitUntilExit();\n },\n );\n}\n","import type { FC } from 'react';\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport { Box, Text, useInput } from 'ink';\nimport { PluginValidationError } from '@kizenapps/packager';\nimport type { ValidationIssue } from '@kizenapps/packager';\nimport { watch } from 'node:fs';\nimport type { FSWatcher } from 'node:fs';\nimport { createServer } from 'node:http';\nimport type { Server } from 'node:http';\nimport { join } from 'node:path';\nimport { type WebSocket, WebSocketServer } from 'ws';\nimport {\n createRequestHandler,\n fileExists,\n getViewerPath,\n type ProxyLogEntry,\n proxyLogEntryToString,\n} from '../server/requestHandler.js';\nimport { launchChromeViewer, type ChromeViewerHandle } from '../chrome/launcher.js';\nimport { runBuild } from '../lib/runBuild.js';\nimport type { Credentials } from '../lib/credentials.js';\nimport { saveConfig } from '../lib/config.js';\nimport { LOG_LIMIT, LOG_DISPLAY, FILE_WATCH_DEBOUNCE_MS } from '../lib/constants.js';\nimport { formatBytes } from '../../shared/lib/formatBytes.js';\nimport { useLogHistory } from '../hooks/useLogHistory.js';\nimport { CredentialSetupUI } from './CredentialSetupUI.js';\nimport type { CredentialMode, CredentialSetupResult } from './CredentialSetupUI.js';\nimport { AppHeader } from './AppHeader.js';\nimport { Spinner } from './Spinner.js';\nimport { ValidationIssues } from './ValidationIssues.js';\n\ntype ServerStatus = 'starting' | 'running' | 'error';\ntype BuildStatus = 'pending' | 'building' | 'done' | 'error';\n\nconst SKIP_WATCH_PREFIXES = ['.kizenapp', '.git'];\n\ninterface DevUIProps {\n port: number;\n pluginDir: string;\n outputDir: string;\n credentials: Credentials | null;\n credentialMode?: CredentialMode;\n activeCredentialProfile?: string;\n lastPath?: string;\n debug?: boolean;\n verbose?: boolean;\n autoViewer?: boolean;\n cacheEnabled?: boolean;\n}\n\nexport const DevUI: FC<DevUIProps> = ({\n port,\n pluginDir,\n outputDir,\n credentials: initialCredentials,\n credentialMode: initialCredentialMode,\n activeCredentialProfile: initialActiveProfile,\n lastPath: initialLastPath,\n debug = false,\n verbose = false,\n autoViewer = true,\n cacheEnabled = true,\n}) => {\n const credentialsRef = useRef<Credentials | null>(initialCredentials);\n const activeProfileRef = useRef<string | undefined>(initialActiveProfile);\n const lastPathRef = useRef<string | undefined>(initialLastPath);\n const [credMode, setCredMode] = useState<'main' | 'editing'>('main');\n const [credentialMode, setCredentialMode] = useState<CredentialMode | undefined>(\n initialCredentialMode,\n );\n\n const [status, setStatus] = useState<ServerStatus>('starting');\n const [errorMessage, setErrorMessage] = useState<string | null>(null);\n const [serverLogHistory, appendServerLog] = useLogHistory(LOG_LIMIT);\n const [buildLogHistory, appendBuildLog] = useLogHistory(LOG_LIMIT);\n const [cdpLogHistory, appendCdpLog] = useLogHistory(LOG_LIMIT);\n const [proxyLogHistory, setProxyLogHistory] = useState<string[]>([]);\n const [buildStatus, setBuildStatus] = useState<BuildStatus>('pending');\n const [buildError, setBuildError] = useState<string | null>(null);\n const [buildIssues, setBuildIssues] = useState<ValidationIssue[] | null>(null);\n const [lastBuilt, setLastBuilt] = useState<Date | null>(null);\n const [lastBundleSize, setLastBundleSize] = useState<number | null>(null);\n const [wsClientCount, setWsClientCount] = useState(0);\n const [proxyCacheSize, setProxyCacheSize] = useState(0);\n const [proxyCacheHits, setProxyCacheHits] = useState(0);\n const [proxyCacheMisses, setProxyCacheMisses] = useState(0);\n\n const buildingRef = useRef(false);\n const viewerLaunchedRef = useRef(false);\n const chromeHandleRef = useRef<ChromeViewerHandle | null>(null);\n const debounceTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const wsClientsRef = useRef<Set<WebSocket>>(new Set());\n const pendingMessagesRef = useRef<string[]>([]);\n\n const broadcast = useCallback((msg: object): void => {\n const json = JSON.stringify(msg);\n\n if (wsClientsRef.current.size === 0) {\n pendingMessagesRef.current = [...pendingMessagesRef.current, json].slice(-LOG_LIMIT);\n\n return;\n }\n\n let pruned = false;\n\n for (const client of wsClientsRef.current) {\n if (client.readyState !== 1) {\n continue;\n }\n\n try {\n client.send(json);\n } catch {\n // Socket died between readyState check and send — drop it so one\n // dead client can't break the loop and silently disconnect the rest.\n wsClientsRef.current.delete(client);\n pruned = true;\n }\n }\n\n if (pruned) {\n setWsClientCount(wsClientsRef.current.size);\n }\n }, []);\n\n const createServerLog = appendServerLog;\n\n const launchChromeViewerCb = useCallback(() => {\n chromeHandleRef.current?.kill();\n\n chromeHandleRef.current = null;\n\n void launchChromeViewer({\n port,\n userDataDir: join(outputDir, '.chrome'),\n broadcast,\n onWarn: (msg) => {\n appendServerLog(`⚠ ${msg}`);\n },\n ...(lastPathRef.current !== undefined && { path: lastPathRef.current }),\n ...(debug && { debugLog: appendCdpLog }),\n ...(verbose && { verbose: true }),\n }).then((handle) => {\n chromeHandleRef.current = handle;\n });\n }, [port, outputDir, broadcast, debug, verbose, appendCdpLog, appendServerLog]);\n\n useEffect(() => {\n const onExit = (): void => {\n chromeHandleRef.current?.kill();\n };\n\n process.on('exit', onExit);\n\n return () => {\n process.off('exit', onExit);\n };\n }, []);\n\n useInput(\n (input, key) => {\n if (input === 'q' || (key.ctrl && input === 'c')) {\n process.exit(0);\n }\n\n if (input === 'c') {\n setCredMode('editing');\n }\n\n if (input === 'v') {\n launchChromeViewerCb();\n }\n },\n { isActive: credMode === 'main' },\n );\n\n useEffect(() => {\n if (status !== 'running' || viewerLaunchedRef.current || !autoViewer) {\n return;\n }\n\n viewerLaunchedRef.current = true;\n\n launchChromeViewerCb();\n }, [status, autoViewer, launchChromeViewerCb]);\n\n const handleCredentialsDone = useCallback(\n (result: CredentialSetupResult): void => {\n credentialsRef.current = result.credentials;\n\n activeProfileRef.current = result.profileName;\n\n setCredMode('main');\n\n setCredentialMode(result.mode);\n\n const profile = result.profileName;\n\n void saveConfig(outputDir, {\n credentialMode: result.mode,\n ...(profile !== undefined && { activeCredentialProfile: profile }),\n });\n\n broadcast({ type: 'credentials-updated', credentials: result.credentials });\n },\n [outputDir, broadcast],\n );\n\n const createProxyLog = useCallback(\n (entry: ProxyLogEntry): void => {\n setProxyLogHistory((h) =>\n [...h, `${new Date().toLocaleTimeString()}: ${proxyLogEntryToString(entry)}`].slice(\n -LOG_LIMIT,\n ),\n );\n\n if (entry.kind === 'request') {\n if (entry.fromCache) {\n setProxyCacheHits((n) => n + 1);\n } else {\n setProxyCacheMisses((n) => n + 1);\n }\n }\n\n broadcast({ type: 'proxy-log', entry });\n },\n [broadcast],\n );\n\n const createBuildLog = useCallback(\n (message: string): void => {\n appendBuildLog(message);\n\n broadcast({ type: 'log', message });\n },\n [appendBuildLog, broadcast],\n );\n\n const triggerBuild = useCallback(() => {\n if (buildingRef.current) {\n return;\n }\n\n buildingRef.current = true;\n setBuildStatus('building');\n setBuildError(null);\n setBuildIssues(null);\n createBuildLog('Build started');\n\n void runBuild(pluginDir, outputDir)\n .then(({ bundleSize }) => {\n createBuildLog(`Build finished — bundle: ${formatBytes(bundleSize)}`);\n setBuildStatus('done');\n setLastBuilt(new Date());\n setLastBundleSize(bundleSize);\n createBuildLog('Notifying viewers to reload');\n broadcast({ type: 'rebuild' });\n })\n .catch((err: unknown) => {\n if (err instanceof PluginValidationError) {\n setBuildIssues(err.issues);\n setBuildError(null);\n } else {\n setBuildError(err instanceof Error ? err.message : String(err));\n setBuildIssues(null);\n }\n\n setBuildStatus('error');\n })\n .finally(() => {\n buildingRef.current = false;\n });\n }, [pluginDir, outputDir, createBuildLog, broadcast]);\n\n useEffect(() => {\n triggerBuild();\n\n const watcher: FSWatcher = watch(pluginDir, { recursive: true }, (_, filename) => {\n if (!filename) {\n return;\n }\n\n const normalized = filename.replace(/\\\\/g, '/');\n\n if (SKIP_WATCH_PREFIXES.some((prefix) => normalized.startsWith(prefix))) {\n return;\n }\n\n createBuildLog(`File change detected: ${filename}`);\n\n if (debounceTimerRef.current !== null) {\n clearTimeout(debounceTimerRef.current);\n }\n\n debounceTimerRef.current = setTimeout(triggerBuild, FILE_WATCH_DEBOUNCE_MS);\n });\n\n // fs.watch silently dies on e.g. macOS inode-limit pressure — surface it so\n // developers know rebuilds have stopped rather than wondering why their\n // edits aren't reflected in the viewer.\n watcher.on('error', (err: Error) => {\n createBuildLog(`File watcher error — rebuilds have stopped: ${err.message}`);\n });\n\n return () => {\n watcher.close();\n\n if (debounceTimerRef.current !== null) {\n clearTimeout(debounceTimerRef.current);\n }\n };\n }, [pluginDir, triggerBuild, createBuildLog]);\n\n useEffect(() => {\n const viewerPath = getViewerPath();\n\n void fileExists(join(viewerPath, 'index.html')).then((viewerBuilt) => {\n if (!viewerBuilt) {\n setErrorMessage(\"Viewer not built. Run 'pnpm build:viewer' first.\");\n setStatus('error');\n\n return;\n }\n\n const handler = createRequestHandler(\n viewerPath,\n createServerLog,\n createProxyLog,\n credentialsRef,\n activeProfileRef,\n outputDir,\n broadcast,\n setProxyCacheSize,\n lastPathRef,\n pluginDir,\n cacheEnabled,\n );\n const server: Server = createServer(handler);\n const wss = new WebSocketServer({ server });\n\n wss.on('connection', (ws: WebSocket) => {\n for (const json of pendingMessagesRef.current) {\n if (ws.readyState === 1) {\n ws.send(json);\n }\n }\n\n pendingMessagesRef.current = [];\n createServerLog('Viewer connected for live reload');\n wsClientsRef.current.add(ws);\n setWsClientCount(wsClientsRef.current.size);\n\n ws.on('close', () => {\n wsClientsRef.current.delete(ws);\n setWsClientCount(wsClientsRef.current.size);\n });\n });\n\n server.listen(port, '127.0.0.1', () => {\n setStatus('running');\n createServerLog(`Server started on 127.0.0.1:${String(port)}`);\n });\n\n server.on('error', (err: Error) => {\n setErrorMessage(err.message);\n setStatus('error');\n });\n\n return () => {\n wss.close();\n server.close();\n };\n });\n }, [port, createServerLog, createProxyLog, broadcast, outputDir, pluginDir, cacheEnabled]);\n\n if (credMode === 'editing') {\n return (\n <CredentialSetupUI\n {...(credentialMode !== undefined && { initialMode: credentialMode })}\n showProfileManager={credentialMode === 'global'}\n onComplete={handleCredentialsDone}\n onCancel={() => {\n setCredMode('main');\n }}\n />\n );\n }\n\n const elapsedSeconds =\n lastBuilt !== null ? Math.round((Date.now() - lastBuilt.getTime()) / 1000) : null;\n\n const elapsedLabel =\n elapsedSeconds === null\n ? ''\n : elapsedSeconds < 5\n ? ' (just now)'\n : ` (${String(elapsedSeconds)}s ago)`;\n\n const buildErrorCount = buildIssues?.filter((issue) => issue.severity === 'error').length ?? 0;\n\n return (\n <Box flexDirection=\"column\" paddingY={1} paddingX={2}>\n <AppHeader marginBottom={1} />\n\n {/* Build panel */}\n <Box flexDirection=\"column\">\n <Box gap={2} marginBottom={0}>\n <Text bold dimColor>\n App Build\n </Text>\n {buildStatus === 'pending' && <Text dimColor>waiting…</Text>}\n {buildStatus === 'building' && (\n <Box gap={1}>\n <Spinner />\n <Text>Building plugin package…</Text>\n </Box>\n )}\n {buildStatus === 'done' && (\n <Box gap={1}>\n <Text color=\"green\">✓ Built</Text>\n {lastBuilt !== null && (\n <Text dimColor>\n at {lastBuilt.toLocaleTimeString()}\n {elapsedLabel}\n </Text>\n )}\n {lastBundleSize !== null && (\n <Text dimColor>· bundle: {formatBytes(lastBundleSize)}</Text>\n )}\n </Box>\n )}\n {buildStatus === 'error' &&\n (buildIssues !== null ? (\n <Text color=\"red\">\n ✗ {buildErrorCount} validation {buildErrorCount === 1 ? 'error' : 'errors'}\n </Text>\n ) : (\n <Text color=\"red\">✗ {buildError ?? 'unknown error'}</Text>\n ))}\n </Box>\n {buildIssues !== null && <ValidationIssues issues={buildIssues} />}\n <Box\n flexDirection=\"column\"\n height={LOG_DISPLAY + 2}\n borderStyle=\"single\"\n borderColor=\"gray\"\n overflow=\"hidden\"\n >\n {buildLogHistory.slice(-LOG_DISPLAY).map((log, index) => (\n <Text key={index} dimColor wrap=\"truncate\">\n {log}\n </Text>\n ))}\n </Box>\n </Box>\n\n {/* Server panel */}\n <Box marginTop={1} flexDirection=\"column\">\n <Box gap={2}>\n <Text bold dimColor>\n Web Server\n </Text>\n {status === 'starting' && <Text dimColor>starting…</Text>}\n {status === 'running' && (\n <Box gap={2}>\n <Text color=\"green\">✓ Running</Text>\n <Text dimColor>\n ● {wsClientCount} viewer{wsClientCount !== 1 ? 's' : ''}\n </Text>\n </Box>\n )}\n {status === 'error' && <Text color=\"red\">✗ {errorMessage ?? 'Server error'}</Text>}\n </Box>\n <Box\n flexDirection=\"column\"\n height={LOG_DISPLAY + 2}\n borderStyle=\"single\"\n borderColor=\"gray\"\n overflow=\"hidden\"\n >\n {serverLogHistory.slice(-LOG_DISPLAY).map((log, index) => (\n <Text key={index} dimColor wrap=\"truncate\">\n {log}\n </Text>\n ))}\n </Box>\n </Box>\n\n {/* Proxy panel */}\n <Box marginTop={1} flexDirection=\"column\">\n <Box gap={2}>\n <Text bold dimColor>\n Network Proxy\n </Text>\n <Text color=\"green\">✓ Active</Text>\n <Text dimColor>\n {cacheEnabled\n ? `● ${String(proxyCacheSize)} key${proxyCacheSize !== 1 ? 's' : ''} in the network cache · ${String(proxyCacheHits)} hit · ${String(proxyCacheMisses)} miss`\n : `● network cache disabled · ${String(proxyCacheMisses)} request${proxyCacheMisses !== 1 ? 's' : ''}`}\n </Text>\n </Box>\n <Box\n flexDirection=\"column\"\n height={LOG_DISPLAY + 2}\n borderStyle=\"single\"\n borderColor=\"gray\"\n overflow=\"hidden\"\n >\n {proxyLogHistory.length === 0 ? (\n <Text dimColor> No requests yet.</Text>\n ) : (\n proxyLogHistory.slice(-LOG_DISPLAY).map((log, i) => (\n <Text key={i} dimColor wrap=\"truncate\">\n {log}\n </Text>\n ))\n )}\n </Box>\n </Box>\n\n {debug && (\n <Box marginTop={1} flexDirection=\"column\">\n <Box gap={2}>\n <Text bold dimColor>\n CDP Debug\n </Text>\n <Text dimColor>● {cdpLogHistory.length} event(s)</Text>\n </Box>\n <Box\n flexDirection=\"column\"\n height={LOG_DISPLAY + 2}\n borderStyle=\"single\"\n borderColor=\"gray\"\n overflow=\"hidden\"\n >\n {cdpLogHistory.length === 0 ? (\n <Text dimColor> No CDP events yet.</Text>\n ) : (\n cdpLogHistory.slice(-LOG_DISPLAY).map((log, i) => (\n <Text key={i} dimColor wrap=\"truncate\">\n {log}\n </Text>\n ))\n )}\n </Box>\n </Box>\n )}\n\n {/* Footer */}\n <Box marginTop={1} gap={1}>\n <Text dimColor>[</Text>\n <Text>q</Text>\n <Text dimColor>] quit [</Text>\n <Text>c</Text>\n <Text dimColor>] credentials [</Text>\n <Text>v</Text>\n <Text dimColor>] {wsClientCount === 0 ? 'open viewer' : 'relaunch viewer'}</Text>\n </Box>\n </Box>\n );\n};\n","import { createReadStream, realpathSync } from 'node:fs';\nimport { access, readdir, readFile, realpath, stat } from 'node:fs/promises';\nimport type { IncomingMessage, ServerResponse } from 'node:http';\nimport { dirname, extname, join, resolve, sep } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport {\n createProxyCache,\n MAX_PROXY_BYTES,\n ProxyResponseTooLargeError,\n readBodyWithLimit,\n sanitizeUpstreamHeaders,\n} from '../lib/proxyCache.js';\nimport { MIME_TYPES } from '../lib/constants.js';\nimport type { Credentials } from '../lib/credentials.js';\nimport {\n listCredentialProfiles,\n loadCredentialProfile,\n loadGlobalCredentials,\n} from '../lib/credentials.js';\nimport { loadConfig, saveConfig } from '../lib/config.js';\nimport { resolveWizardBase } from '../lib/wizardUrl.js';\nimport { executePythonStep } from './pythonExecutor.js';\nimport { SKIP_DIRS } from '../lib/readFiles.js';\nimport { TEXT_EXTENSIONS } from '../../shared/lib/fileExtensions.js';\nimport { normalizeStepInputs } from '../../shared/lib/execution.js';\nimport {\n CRYPTO_ALG,\n CRYPTO_VERSION,\n deserializeEnvelope,\n encrypt,\n serializeEnvelope,\n} from '@kizenapps/packager';\n\nconst SOURCE_FILE_MAX_BYTES = 2 * 1024 * 1024;\n\nconst SKIP_FILES = new Set(['.DS_Store', '.gitignore']);\n\nfunction isLocalHost(host: string | undefined): boolean {\n if (host === undefined || host === '') {\n return false;\n }\n\n // Strip the port. This is a host header, so IPv6 would arrive as \"[::1]:port\"\n // — we don't serve ::1 (Node binds to 127.0.0.1), but the guard is permissive\n // enough to survive that even if the bind address changes later.\n const hostname = host.startsWith('[')\n ? host.slice(0, host.indexOf(']') + 1)\n : (host.split(':')[0] ?? '');\n\n return hostname === 'localhost' || hostname === '127.0.0.1' || hostname === '[::1]';\n}\n\nconst PROXY_ALLOWED_DOMAINS = ['kizen.com', 'kizen.dev'];\n\n/**\n * Guards the resolved encryption-API host. The wizard proxy forwards the\n * caller's Kizen credential headers, so a fat-fingered PLUGIN_WIZARD_URL* env\n * var must not be able to leak them to an arbitrary origin. Allows a\n * locally-running wizard (any localhost/loopback) plus https on a Kizen domain.\n */\nfunction isAllowedWizardTarget(target: string): boolean {\n let url: URL;\n\n try {\n url = new URL(target);\n } catch {\n return false;\n }\n\n const hostname = url.hostname.toLowerCase();\n\n // URL.hostname returns IPv6 literals bracketed, e.g. '[::1]'.\n if (hostname === 'localhost' || hostname === '127.0.0.1' || hostname === '[::1]') {\n return true;\n }\n\n if (url.protocol !== 'https:') {\n return false;\n }\n\n return PROXY_ALLOWED_DOMAINS.some(\n (domain) => hostname === domain || hostname.endsWith('.' + domain),\n );\n}\n\nfunction isAllowedProxyTarget(target: string): boolean {\n let url: URL;\n\n try {\n url = new URL(target);\n } catch {\n return false;\n }\n\n if (url.protocol !== 'https:') {\n return false;\n }\n\n const hostname = url.hostname.toLowerCase();\n\n return PROXY_ALLOWED_DOMAINS.some(\n (domain) => hostname === domain || hostname.endsWith('.' + domain),\n );\n}\n\nfunction isLocalOrigin(origin: string | undefined): boolean {\n if (origin === undefined || origin === '') {\n return false;\n }\n\n try {\n const { hostname } = new URL(origin);\n\n return hostname === 'localhost' || hostname === '127.0.0.1' || hostname === '::1';\n } catch {\n return false;\n }\n}\n\nasync function resolveSafePath(realPluginDir: string, relParam: string): Promise<string | null> {\n if (relParam.includes('\\0')) {\n return null;\n }\n\n const rel = relParam.replace(/^\\/+/, '');\n const abs = resolve(realPluginDir, rel);\n\n // Syntactic .. traversal check — fails fast before touching the filesystem.\n if (abs !== realPluginDir && !abs.startsWith(realPluginDir + sep)) {\n return null;\n }\n\n // Symlink-aware check: a symlink inside the plugin dir can still escape it\n // (e.g. a link to ~/.ssh/id_rsa resolves to a path that passes the string\n // check above but reads arbitrary files). Realpath the target and re-verify.\n // If the target doesn't exist realpath throws — reject rather than guess.\n try {\n const realAbs = await realpath(abs);\n\n if (realAbs !== realPluginDir && !realAbs.startsWith(realPluginDir + sep)) {\n return null;\n }\n\n return realAbs;\n } catch {\n return null;\n }\n}\n\nfunction isInsideSkippedDir(pluginDir: string, abs: string): boolean {\n const rel = abs === pluginDir ? '' : abs.slice(pluginDir.length + 1);\n\n if (rel === '') {\n return false;\n }\n\n const segments = rel.split(sep);\n\n return segments.some((segment) => SKIP_DIRS.has(segment));\n}\n\nexport type { ProxyLogEntry } from '../../shared/lib/proxy.js';\nexport { proxyLogEntryToString } from '../../shared/lib/proxy.js';\nimport { type ProxyLogEntry } from '../../shared/lib/proxy.js';\n\nexport function getViewerPath(): string {\n const filename = fileURLToPath(import.meta.url);\n\n return join(dirname(filename), 'viewer');\n}\n\n/**\n * Calls to Kizen's `/external-integrations/proxy` endpoint wrap the third-party\n * API's status in the response body (`status_code`) and return HTTP 200 even\n * when the upstream call failed. Pull that real status out so the network log\n * can surface it instead of the misleading proxy status.\n */\nfunction extractUpstreamStatus(\n upstreamPath: string,\n headers: Record<string, string>,\n body: Buffer,\n): number | undefined {\n if (!upstreamPath.includes('/external-integrations/proxy')) {\n return undefined;\n }\n\n if (!headers['content-type']?.includes('application/json')) {\n return undefined;\n }\n\n try {\n const parsed = JSON.parse(body.toString('utf8')) as { status_code?: unknown };\n\n return typeof parsed.status_code === 'number' ? parsed.status_code : undefined;\n } catch {\n return undefined;\n }\n}\n\nexport async function fileExists(filePath: string): Promise<boolean> {\n try {\n await access(filePath);\n\n return true;\n } catch {\n return false;\n }\n}\n\nexport function createRequestHandler(\n viewerPath: string,\n createServerLog: (message: string) => void,\n createProxyLog: (entry: ProxyLogEntry) => void,\n credentialsRef: { current: Credentials | null },\n activeProfileRef: { current: string | undefined },\n outputDir: string,\n broadcast: (msg: object) => void,\n onProxyCacheChange: (size: number) => void,\n lastPathRef: { current: string | undefined },\n pluginDir: string,\n cacheEnabled: boolean,\n): (req: IncomingMessage, res: ServerResponse) => void {\n const proxyCache = createProxyCache({ onChange: onProxyCacheChange, enabled: cacheEnabled });\n // Resolve the plugin dir once so every source-path check compares against\n // the canonical path (handles macOS /var → /private/var, pnpm workspace\n // symlinks, etc.). Done synchronously at handler creation since pluginDir\n // is process.cwd() and must already exist.\n const realPluginDir = realpathSync(pluginDir);\n\n return (req, res) => {\n void (async () => {\n const url = req.url ?? '/';\n\n try {\n // Even though we bind to 127.0.0.1, a browser tab on\n // a malicious origin can point its DNS at our loopback address. The\n // Host header still carries the original hostname, so rejecting\n // anything that isn't localhost/127.0.0.1 closes the hole.\n if (!isLocalHost(req.headers.host)) {\n res.writeHead(403, { 'Content-Type': 'application/json; charset=utf-8' });\n res.end(JSON.stringify({ error: 'Forbidden' }));\n\n return;\n }\n\n const isWrite = req.method === 'POST' || req.method === 'PATCH' || req.method === 'DELETE';\n\n if (isWrite && !isLocalOrigin(req.headers.origin)) {\n res.writeHead(403, { 'Content-Type': 'application/json; charset=utf-8' });\n res.end(JSON.stringify({ error: 'Forbidden' }));\n\n return;\n }\n\n createServerLog(`Received request: ${url}`);\n\n if (url === '/api/credentials') {\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });\n\n res.end(\n JSON.stringify({\n credentials: credentialsRef.current ?? null,\n activeProfile: activeProfileRef.current ?? null,\n }),\n );\n\n return;\n }\n\n if (url === '/api/credential-profiles' && req.method === 'GET') {\n const profiles = await listCredentialProfiles();\n\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });\n\n res.end(JSON.stringify({ profiles, active: activeProfileRef.current }));\n\n return;\n }\n\n if (url === '/api/credentials/switch' && req.method === 'POST') {\n const chunks: Buffer[] = [];\n\n for await (const chunk of req) {\n chunks.push(chunk as Buffer);\n }\n\n const body = JSON.parse(Buffer.concat(chunks).toString('utf-8') || '{}') as {\n profile?: string;\n };\n const profileName = body.profile;\n const creds =\n profileName === undefined || profileName === ''\n ? await loadGlobalCredentials()\n : await loadCredentialProfile(profileName);\n\n if (creds !== null) {\n credentialsRef.current = creds;\n\n activeProfileRef.current = profileName ?? undefined;\n\n const active = activeProfileRef.current;\n const currentConfig = await loadConfig(outputDir);\n\n await saveConfig(outputDir, {\n ...currentConfig,\n credentialMode: 'global',\n ...(active !== undefined && { activeCredentialProfile: active }),\n });\n\n broadcast({\n type: 'credentials-updated',\n credentials: creds,\n activeProfile: activeProfileRef.current ?? null,\n });\n }\n\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });\n\n res.end(JSON.stringify({ ok: creds !== null }));\n\n return;\n }\n\n if (url === '/api/bundle') {\n const bundlePath = join(process.cwd(), '.kizenapp', 'bundle.json');\n\n try {\n const content = await readFile(bundlePath, 'utf-8');\n\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });\n\n res.end(content);\n } catch {\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });\n\n res.end('{}');\n }\n\n return;\n }\n\n if (url === '/api/last-path' && req.method === 'POST') {\n const chunks: Buffer[] = [];\n\n for await (const chunk of req) {\n chunks.push(chunk as Buffer);\n }\n\n const body = JSON.parse(Buffer.concat(chunks).toString('utf-8') || '{}') as {\n path?: string;\n };\n\n if (typeof body.path === 'string') {\n lastPathRef.current = body.path;\n\n const currentConfig = await loadConfig(outputDir);\n\n await saveConfig(outputDir, { ...currentConfig, lastPath: body.path });\n }\n\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });\n\n res.end('{\"ok\":true}');\n\n return;\n }\n\n if (url === '/api/encryption-target' && req.method === 'GET') {\n const config = await loadConfig(outputDir);\n // Default to 'prod' when unset. Anything that isn't an explicit 'dev'\n // (incl. a legacy 'auto' from before the heuristic was dropped) maps to\n // 'prod', so the API only ever returns a concrete target.\n const target = config.encryptionTarget === 'dev' ? 'dev' : 'prod';\n\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });\n res.end(JSON.stringify({ target }));\n\n return;\n }\n\n if (url === '/api/encryption-target' && req.method === 'POST') {\n const chunks: Buffer[] = [];\n\n for await (const chunk of req) {\n chunks.push(chunk as Buffer);\n }\n\n const parsed: unknown = JSON.parse(Buffer.concat(chunks).toString('utf-8') || '{}');\n const body: { target?: string } =\n parsed !== null && typeof parsed === 'object' ? (parsed as { target?: string }) : {};\n\n if (body.target !== 'dev' && body.target !== 'prod') {\n res.writeHead(400, { 'Content-Type': 'application/json; charset=utf-8' });\n res.end(JSON.stringify({ error: \"target must be one of: 'dev', 'prod'\" }));\n\n return;\n }\n\n const currentConfig = await loadConfig(outputDir);\n\n // body.target is narrowed to 'dev' | 'prod' by the guard above.\n await saveConfig(outputDir, { ...currentConfig, encryptionTarget: body.target });\n\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });\n res.end('{\"ok\":true}');\n\n return;\n }\n\n if (url === '/api/execute-step' && req.method === 'POST') {\n const chunks: Buffer[] = [];\n\n for await (const chunk of req) {\n chunks.push(chunk as Buffer);\n }\n\n const body = JSON.parse(Buffer.concat(chunks).toString('utf-8') || '{}') as {\n script?: string;\n scriptRuntime?: string;\n inputs?: Record<string, unknown>;\n secrets?: Record<string, string>;\n timeout?: number;\n };\n\n if (typeof body.script !== 'string') {\n res.writeHead(400, { 'Content-Type': 'application/json; charset=utf-8' });\n\n res.end(JSON.stringify({ error: 'Missing required field: script' }));\n\n return;\n }\n\n const stepParams: Parameters<typeof executePythonStep>[0] = {\n script: body.script,\n // Matches the production Kizen code-runner service's default runtime\n // (\"python-3-13\"). Only used when a caller omits a runtime; real\n // plugin steps send their own \"python-3-NN\" value.\n scriptRuntime: body.scriptRuntime ?? 'python-3-13',\n inputs: normalizeStepInputs(body.inputs),\n secrets: body.secrets ?? {},\n onInstallProgress: (event) => {\n if (event.kind === 'start') {\n broadcast({ type: 'venv-install-start' });\n } else if (event.kind === 'log') {\n broadcast({\n type: 'venv-install-log',\n line: event.line,\n stream: event.stream,\n });\n } else if (event.kind === 'complete') {\n broadcast({ type: 'venv-install-complete' });\n } else {\n broadcast({ type: 'venv-install-error', message: event.message });\n }\n },\n };\n\n if (typeof body.timeout === 'number' && body.timeout > 0) {\n // Cap at 5 minutes so a runaway request can't hang the Python\n // runner indefinitely. Default (30s) still applies if omitted.\n stepParams.timeout = Math.min(body.timeout, 5 * 60 * 1000);\n }\n\n const result = await executePythonStep(stepParams);\n\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });\n\n res.end(JSON.stringify(result));\n\n return;\n }\n\n if (url === '/api/proxy-cache/clear') {\n proxyCache.clear();\n\n createProxyLog({ kind: 'info', message: 'Proxy cache cleared' });\n\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });\n\n res.end('{\"ok\":true}');\n\n return;\n }\n\n if (url === '/api/local/encrypt' && req.method === 'POST') {\n const chunks: Buffer[] = [];\n\n for await (const chunk of req) {\n chunks.push(chunk as Buffer);\n }\n\n const body = JSON.parse(Buffer.concat(chunks).toString('utf-8') || '{}') as {\n publicKeyPem?: string;\n value?: string;\n };\n\n if (typeof body.publicKeyPem !== 'string' || typeof body.value !== 'string') {\n res.writeHead(400, { 'Content-Type': 'application/json; charset=utf-8' });\n res.end(JSON.stringify({ error: 'Missing required fields: publicKeyPem, value' }));\n\n return;\n }\n\n try {\n const envelope = encrypt(body.value, body.publicKeyPem);\n const serialized = serializeEnvelope(envelope);\n\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });\n res.end(JSON.stringify(serialized));\n } catch (err) {\n res.writeHead(400, { 'Content-Type': 'application/json; charset=utf-8' });\n res.end(JSON.stringify({ error: (err as Error).message }));\n }\n\n return;\n }\n\n if (url === '/api/local/validate' && req.method === 'POST') {\n const chunks: Buffer[] = [];\n\n for await (const chunk of req) {\n chunks.push(chunk as Buffer);\n }\n\n const body = JSON.parse(Buffer.concat(chunks).toString('utf-8') || '{}') as {\n value?: string;\n };\n\n if (typeof body.value !== 'string') {\n res.writeHead(400, { 'Content-Type': 'application/json; charset=utf-8' });\n res.end(JSON.stringify({ error: 'Missing required field: value' }));\n\n return;\n }\n\n interface CheckResult {\n label: string;\n expected: string;\n actual: string;\n pass: boolean;\n }\n\n let envelope: ReturnType<typeof deserializeEnvelope> | undefined;\n let parseError: string | undefined;\n\n try {\n envelope = deserializeEnvelope(body.value);\n } catch (err) {\n parseError = (err as Error).message;\n }\n\n if (parseError !== undefined || envelope === undefined) {\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });\n res.end(JSON.stringify({ valid: false, checks: [], error: parseError }));\n\n return;\n }\n\n const bufLen = (b64: string): number => Buffer.from(b64, 'base64').length;\n\n const checks: CheckResult[] = [\n {\n label: 'Version',\n expected: String(CRYPTO_VERSION),\n actual: String(envelope.v),\n pass: (envelope.v as number) === CRYPTO_VERSION,\n },\n {\n label: 'Algorithm',\n expected: CRYPTO_ALG,\n actual: envelope.alg,\n pass: (envelope.alg as string) === CRYPTO_ALG,\n },\n {\n label: 'Wrapped key',\n expected: '384 bytes (RSA-3072)',\n actual: `${String(bufLen(envelope.k))} bytes`,\n pass: bufLen(envelope.k) === 384,\n },\n {\n label: 'IV',\n expected: '12 bytes',\n actual: `${String(bufLen(envelope.iv))} bytes`,\n pass: bufLen(envelope.iv) === 12,\n },\n {\n label: 'Auth tag',\n expected: '16 bytes',\n actual: `${String(bufLen(envelope.tag))} bytes`,\n pass: bufLen(envelope.tag) === 16,\n },\n {\n label: 'Ciphertext',\n expected: '≥ 1 byte',\n actual: `${String(bufLen(envelope.ct))} bytes`,\n pass: bufLen(envelope.ct) >= 1,\n },\n ];\n\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });\n res.end(JSON.stringify({ valid: checks.every((c) => c.pass), checks }));\n\n return;\n }\n\n if (url.startsWith('/api/wizard')) {\n // The viewer sends the saved dev/prod target here; we map it to a known\n // host. A duplicated header arrives as an array — take the first value.\n // Default to 'prod' when absent/invalid: prod is the product-wide\n // default (almost every plugin ships to production), and only an\n // explicit 'dev' routes to the dev keys.\n const rawTarget = req.headers['x-encryption-target'];\n const targetHeader = Array.isArray(rawTarget) ? rawTarget[0] : rawTarget;\n const target: 'dev' | 'prod' = targetHeader === 'dev' ? 'dev' : 'prod';\n const wizardBase = resolveWizardBase(target);\n\n // The credential headers below are forwarded to wizardBase — refuse to\n // forward them anywhere but a known host.\n if (!isAllowedWizardTarget(wizardBase)) {\n res.writeHead(500, { 'Content-Type': 'application/json; charset=utf-8' });\n res.end(\n JSON.stringify({\n error: `Encryption API host is not allowed: ${wizardBase}`,\n }),\n );\n\n return;\n }\n\n const upstreamPath = url.slice('/api/wizard'.length) || '/';\n const upstreamUrl = `${wizardBase}${upstreamPath}`;\n const method = req.method ?? 'GET';\n\n const chunks: Buffer[] = [];\n\n for await (const chunk of req) {\n chunks.push(chunk as Buffer);\n }\n\n const {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n host: _wizardHost,\n // Internal control header — don't forward it upstream.\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n 'x-encryption-target': _encTarget,\n ...wizardForwardHeaders\n } = req.headers;\n\n const body = chunks.length > 0 ? Buffer.concat(chunks) : undefined;\n const resolvedBody = body && body.length > 0 ? body : undefined;\n\n let upstream: Response;\n\n try {\n upstream = await fetch(upstreamUrl, {\n method,\n headers: wizardForwardHeaders as Record<string, string>,\n ...(resolvedBody !== undefined && { body: resolvedBody }),\n });\n } catch (err) {\n const message =\n (err as NodeJS.ErrnoException).code === 'ECONNREFUSED'\n ? `plugin-wizard is not running at ${wizardBase}`\n : `Failed to reach plugin-wizard: ${(err as Error).message}`;\n\n res.writeHead(503, { 'Content-Type': 'application/json; charset=utf-8' });\n res.end(JSON.stringify({ error: message }));\n\n return;\n }\n\n const wizardResponseHeaders = sanitizeUpstreamHeaders(\n Object.fromEntries(upstream.headers),\n );\n const wizardBody = await upstream.arrayBuffer();\n\n res.writeHead(upstream.status, wizardResponseHeaders);\n res.end(Buffer.from(wizardBody));\n\n return;\n }\n\n if (url.startsWith('/api/proxy')) {\n const proxyTarget = req.headers['x-proxy-target'];\n\n if (typeof proxyTarget !== 'string') {\n res.writeHead(400);\n\n res.end('Missing x-proxy-target header');\n\n return;\n }\n\n if (!isAllowedProxyTarget(proxyTarget)) {\n res.writeHead(400);\n\n res.end('Invalid proxy target');\n\n return;\n }\n\n const upstreamPath = url.slice('/api/proxy'.length) || '/';\n const upstreamUrl = `${proxyTarget}${upstreamPath}`;\n const method = req.method ?? 'GET';\n\n const chunks: Buffer[] = [];\n\n for await (const chunk of req) {\n chunks.push(chunk as Buffer);\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const { host, 'x-proxy-target': _drop, ...forwardHeaders } = req.headers;\n\n if (method === 'GET') {\n const cacheKey = `GET::${upstreamUrl}`;\n const { response: cached, fromCache } = await proxyCache.get(cacheKey, () =>\n fetch(upstreamUrl, {\n method: 'GET',\n headers: forwardHeaders as Record<string, string>,\n }),\n );\n\n createProxyLog({\n kind: 'request',\n method: 'GET',\n status: cached.status,\n upstreamStatus: extractUpstreamStatus(upstreamPath, cached.headers, cached.body),\n fromCache,\n url: upstreamPath,\n });\n\n res.writeHead(cached.status, cached.headers);\n\n res.end(cached.body);\n\n return;\n }\n\n const body = chunks.length > 0 ? Buffer.concat(chunks) : undefined;\n const resolvedBody = body && body.length > 0 ? body : undefined;\n const upstream = await fetch(upstreamUrl, {\n method,\n headers: forwardHeaders as Record<string, string>,\n ...(resolvedBody !== undefined && { body: resolvedBody }),\n });\n const responseHeaders = sanitizeUpstreamHeaders(Object.fromEntries(upstream.headers));\n const responseBody = await readBodyWithLimit(upstream, MAX_PROXY_BYTES);\n\n createProxyLog({\n kind: 'request',\n method,\n status: upstream.status,\n upstreamStatus: extractUpstreamStatus(upstreamPath, responseHeaders, responseBody),\n fromCache: false,\n url: upstreamPath,\n });\n\n res.writeHead(upstream.status, responseHeaders);\n\n res.end(responseBody);\n\n return;\n }\n\n if (url.startsWith('/api/source/tree') && req.method === 'GET') {\n const query = new URL(url, 'http://localhost').searchParams;\n const relParam = query.get('path') ?? '';\n const abs = await resolveSafePath(realPluginDir, relParam);\n\n if (abs === null) {\n res.writeHead(403, { 'Content-Type': 'application/json; charset=utf-8' });\n res.end(JSON.stringify({ error: 'Invalid path' }));\n\n return;\n }\n\n if (isInsideSkippedDir(realPluginDir, abs)) {\n res.writeHead(403, { 'Content-Type': 'application/json; charset=utf-8' });\n res.end(JSON.stringify({ error: 'Path is excluded' }));\n\n return;\n }\n\n try {\n const dirEntries = await readdir(abs, { withFileTypes: true });\n const entries = await Promise.all(\n dirEntries\n .filter((entry) => {\n if (entry.isDirectory()) {\n return !SKIP_DIRS.has(entry.name);\n }\n\n if (entry.isFile()) {\n return !SKIP_FILES.has(entry.name);\n }\n\n return false;\n })\n .map(async (entry) => {\n const kind = entry.isDirectory() ? ('dir' as const) : ('file' as const);\n const result: { name: string; kind: 'dir' | 'file'; size?: number } = {\n name: entry.name,\n kind,\n };\n\n if (kind === 'file') {\n try {\n const stats = await stat(join(abs, entry.name));\n\n result.size = stats.size;\n } catch {\n // Ignore stat failures — file may have been deleted mid-scan.\n }\n }\n\n return result;\n }),\n );\n\n entries.sort((a, b) => {\n if (a.kind !== b.kind) {\n return a.kind === 'dir' ? -1 : 1;\n }\n\n return a.name.localeCompare(b.name);\n });\n\n const normalizedPath = abs === realPluginDir ? '' : abs.slice(realPluginDir.length + 1);\n\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });\n res.end(JSON.stringify({ path: normalizedPath, entries }));\n } catch (err) {\n const detail = err instanceof Error ? err.message : String(err);\n\n createServerLog(`source/tree failed (${relParam}): ${detail}`);\n\n res.writeHead(404, { 'Content-Type': 'application/json; charset=utf-8' });\n res.end(JSON.stringify({ error: 'Not found' }));\n }\n\n return;\n }\n\n if (url.startsWith('/api/source/file') && req.method === 'GET') {\n const query = new URL(url, 'http://localhost').searchParams;\n const relParam = query.get('path') ?? '';\n\n if (relParam === '') {\n res.writeHead(400, { 'Content-Type': 'application/json; charset=utf-8' });\n res.end(JSON.stringify({ error: 'Missing path' }));\n\n return;\n }\n\n const abs = await resolveSafePath(realPluginDir, relParam);\n\n if (abs === null) {\n res.writeHead(403, { 'Content-Type': 'application/json; charset=utf-8' });\n res.end(JSON.stringify({ error: 'Invalid path' }));\n\n return;\n }\n\n if (isInsideSkippedDir(realPluginDir, abs)) {\n res.writeHead(403, { 'Content-Type': 'application/json; charset=utf-8' });\n res.end(JSON.stringify({ error: 'Path is excluded' }));\n\n return;\n }\n\n try {\n const stats = await stat(abs);\n\n if (!stats.isFile()) {\n res.writeHead(400, { 'Content-Type': 'application/json; charset=utf-8' });\n res.end(JSON.stringify({ error: 'Not a file' }));\n\n return;\n }\n\n if (stats.size > SOURCE_FILE_MAX_BYTES) {\n res.writeHead(413, { 'Content-Type': 'application/json; charset=utf-8' });\n res.end(JSON.stringify({ error: 'File too large', size: stats.size }));\n\n return;\n }\n\n const ext = extname(abs).toLowerCase();\n const explicitMime = MIME_TYPES[ext];\n const isKnownText = TEXT_EXTENSIONS.has(ext);\n const contentType =\n explicitMime ??\n (isKnownText ? 'text/plain; charset=utf-8' : 'application/octet-stream');\n\n res.writeHead(200, {\n 'Content-Type': contentType,\n 'Content-Length': String(stats.size),\n });\n createReadStream(abs).pipe(res);\n } catch (err) {\n const detail = err instanceof Error ? err.message : String(err);\n\n createServerLog(`source/file failed (${relParam}): ${detail}`);\n\n res.writeHead(404, { 'Content-Type': 'application/json; charset=utf-8' });\n res.end(JSON.stringify({ error: 'Not found' }));\n }\n\n return;\n }\n\n const rawPath = url === '/' ? '/index.html' : url;\n const filePath = join(viewerPath, rawPath);\n const resolvedPath = (await fileExists(filePath))\n ? filePath\n : join(viewerPath, 'index.html');\n const ext = extname(resolvedPath);\n const mimeType = MIME_TYPES[ext] ?? 'application/octet-stream';\n\n res.writeHead(200, { 'Content-Type': mimeType });\n\n createReadStream(resolvedPath).pipe(res);\n } catch (err) {\n if (url.startsWith('/api/proxy')) {\n const upstreamPath = url.slice('/api/proxy'.length) || '/';\n const method = req.method ?? 'GET';\n\n if (err instanceof ProxyResponseTooLargeError) {\n createProxyLog({\n kind: 'info',\n message: `${method} ${upstreamPath} → 502 (response exceeded ${String(err.limit)} bytes)`,\n });\n } else {\n createProxyLog({\n kind: 'request',\n method,\n status: 502,\n fromCache: false,\n url: upstreamPath,\n });\n }\n } else {\n createProxyLog({\n kind: 'info',\n message: `Error handling ${url}: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n\n if (!res.headersSent) {\n res.writeHead(502);\n\n res.end('Bad Gateway');\n }\n }\n })();\n };\n}\n","export interface CachedResponse {\n status: number;\n headers: Record<string, string>;\n body: Buffer;\n}\n\n// Headers we refuse to pass through from upstream to the browser.\n// - set-cookie: would set Kizen cookies on the localhost origin.\n// - access-control-*: would let upstream relax CORS on our responses.\n// - strict-transport-security: shouldn't govern localhost.\n// - content-security-policy(-report-only), x-frame-options: upstream policy\n// doesn't apply to the local viewer and can conflict with our own CSP.\n// content-encoding / content-length are dropped because fetch auto-decompresses\n// the body; the original sizes/encoding no longer match what we forward.\nconst STRIPPED_RESPONSE_HEADERS = new Set([\n 'set-cookie',\n 'strict-transport-security',\n 'content-security-policy',\n 'content-security-policy-report-only',\n 'x-frame-options',\n 'content-encoding',\n 'content-length',\n]);\n\nexport function sanitizeUpstreamHeaders(headers: Record<string, string>): Record<string, string> {\n const filtered: Record<string, string> = {};\n\n for (const [key, value] of Object.entries(headers)) {\n const lower = key.toLowerCase();\n\n if (STRIPPED_RESPONSE_HEADERS.has(lower) || lower.startsWith('access-control-')) {\n continue;\n }\n\n filtered[key] = value;\n }\n\n return filtered;\n}\n\nexport const MAX_PROXY_BYTES = 10 * 1024 * 1024;\n\n// 60s TTL keeps dev-session queries de-duplicated without masking server-side\n// changes for long. 200 entries caps worst-case memory at ~2GB if every entry\n// were maxed out, which it won't be — typical Kizen JSON responses are <100KB.\nconst CACHE_TTL_MS = 60_000;\nconst CACHE_MAX_ENTRIES = 200;\n\nexport class ProxyResponseTooLargeError extends Error {\n readonly bytesRead: number;\n readonly limit: number;\n\n constructor(bytesRead: number, limit: number) {\n super(`Upstream response exceeded ${String(limit)} bytes (read ${String(bytesRead)}).`);\n this.name = 'ProxyResponseTooLargeError';\n this.bytesRead = bytesRead;\n this.limit = limit;\n }\n}\n\nexport async function readBodyWithLimit(response: Response, limit: number): Promise<Buffer> {\n const body = response.body;\n\n if (body === null) {\n return Buffer.alloc(0);\n }\n\n const chunks: Uint8Array[] = [];\n let total = 0;\n\n for await (const chunk of body as AsyncIterable<Uint8Array>) {\n total += chunk.length;\n\n if (total > limit) {\n throw new ProxyResponseTooLargeError(total, limit);\n }\n\n chunks.push(chunk);\n }\n\n return Buffer.concat(chunks);\n}\n\nexport interface ProxyCache {\n get(\n key: string,\n fetcher: () => Promise<Response>,\n ): Promise<{ response: CachedResponse; fromCache: boolean }>;\n clear(): void;\n}\n\nexport interface ProxyCacheOptions {\n onChange?: (size: number) => void;\n // When false, the cache becomes a pass-through: every request hits upstream\n // and nothing is stored. Used by `appbuilder dev --no-cache`.\n enabled?: boolean;\n}\n\ninterface CacheEntry {\n insertedAt: number;\n promise: Promise<CachedResponse>;\n}\n\nasync function toCachedResponse(response: Response): Promise<CachedResponse> {\n const headers = sanitizeUpstreamHeaders(Object.fromEntries(response.headers));\n const body = await readBodyWithLimit(response, MAX_PROXY_BYTES);\n\n return { status: response.status, headers, body };\n}\n\nexport function createProxyCache(options: ProxyCacheOptions = {}): ProxyCache {\n const { onChange, enabled = true } = options;\n\n if (!enabled) {\n return {\n async get(_key, fetcher) {\n const response = await toCachedResponse(await fetcher());\n\n return { response, fromCache: false };\n },\n clear() {\n // Nothing is stored, so there is nothing to clear.\n },\n };\n }\n\n const cache = new Map<string, CacheEntry>();\n const emitChange = (): void => {\n onChange?.(cache.size);\n };\n\n const evict = (key: string): void => {\n if (cache.delete(key)) {\n emitChange();\n }\n };\n\n return {\n get(\n key: string,\n fetcher: () => Promise<Response>,\n ): Promise<{ response: CachedResponse; fromCache: boolean }> {\n const existing = cache.get(key);\n\n if (existing !== undefined) {\n if (Date.now() - existing.insertedAt < CACHE_TTL_MS) {\n return existing.promise.then((response) => ({ response, fromCache: true }));\n }\n\n // Stale — drop and refetch.\n evict(key);\n }\n\n // Map iteration order is insertion order, so the first key is the oldest.\n // Evicting before insert keeps size strictly ≤ CACHE_MAX_ENTRIES.\n if (cache.size >= CACHE_MAX_ENTRIES) {\n const oldest = cache.keys().next().value;\n\n if (oldest !== undefined) {\n evict(oldest);\n }\n }\n\n const pending = fetcher()\n .then(toCachedResponse)\n .catch((error: unknown) => {\n evict(key);\n throw error;\n });\n\n cache.set(key, { insertedAt: Date.now(), promise: pending });\n\n emitChange();\n\n return pending.then((response) => {\n // Only 2xx responses stay cached; everything else is served once and\n // evicted so the next request re-fetches.\n if (response.status < 200 || response.status >= 300) {\n evict(key);\n }\n\n return { response, fromCache: false };\n });\n },\n\n clear(): void {\n cache.clear();\n\n emitChange();\n },\n };\n}\n","/** Maximum number of log entries retained per log channel. */\nexport const LOG_LIMIT = 50;\n\n/** Number of log lines visible in each TUI log panel. */\nexport const LOG_DISPLAY = 8;\n\n/** Debounce delay for file-watcher triggered rebuilds (ms). */\nexport const FILE_WATCH_DEBOUNCE_MS = 150;\n\nexport const MIME_TYPES: Readonly<Record<string, string>> = {\n '.html': 'text/html; charset=utf-8',\n '.js': 'application/javascript; charset=utf-8',\n '.mjs': 'application/javascript; charset=utf-8',\n '.css': 'text/css; charset=utf-8',\n '.png': 'image/png',\n '.jpg': 'image/jpeg',\n '.svg': 'image/svg+xml',\n '.ico': 'image/x-icon',\n '.json': 'application/json; charset=utf-8',\n '.woff': 'font/woff',\n '.woff2': 'font/woff2',\n '.ttf': 'font/ttf',\n '.map': 'application/json',\n};\n","/**\n * Shared helper for resolving the encryption API (plugin-wizard) base URL.\n * Imported by both the dev server request handler and the `encrypt` CLI command\n * so the host defaults and env-var names live in one place. KZN-16467.\n */\n\nexport const ENCRYPTION_API_DEFAULTS = {\n prod: 'https://plugin-wizard.kizen.com', // deployed prod encryption service\n dev: 'https://plugin-wizard.kizen.dev', // deployed dev encryption service\n localDev: 'http://localhost:9823', // local plugin-wizard (APPBUILDER_LOCAL_DEV)\n} as const;\n\n/**\n * Resolves the base URL for the encryption API (plugin-wizard) public-key\n * endpoint. Precedence for the `dev` target:\n * 1. `PLUGIN_WIZARD_URL` — forces a single host for ALL targets.\n * 2. `PLUGIN_WIZARD_URL_DEV` — explicit dev URL.\n * 3. `APPBUILDER_LOCAL_DEV` — any non-empty value → localhost:9823.\n * 4. Hardcoded default — deployed dev service.\n * Prod follows the same pattern minus step 3.\n */\nexport function resolveWizardBase(target: 'dev' | 'prod'): string {\n const forced = process.env.PLUGIN_WIZARD_URL;\n\n if (forced !== undefined && forced !== '') {\n return forced;\n }\n\n if (target === 'prod') {\n // `||` (not `??`) so an empty-string env var falls back to the default,\n // matching the PLUGIN_WIZARD_URL / *_DEV branches above and below.\n return process.env.PLUGIN_WIZARD_URL_PROD || ENCRYPTION_API_DEFAULTS.prod;\n }\n\n if (process.env.PLUGIN_WIZARD_URL_DEV !== undefined && process.env.PLUGIN_WIZARD_URL_DEV !== '') {\n return process.env.PLUGIN_WIZARD_URL_DEV;\n }\n\n if (process.env.APPBUILDER_LOCAL_DEV !== undefined && process.env.APPBUILDER_LOCAL_DEV !== '') {\n return ENCRYPTION_API_DEFAULTS.localDev;\n }\n\n return ENCRYPTION_API_DEFAULTS.dev;\n}\n","import { spawn } from 'node:child_process';\nimport { writeFile, rm, mkdtemp, access } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { tmpdir } from 'node:os';\nimport requirementsTxt from './python-requirements.txt';\nimport { parseRequirementsFile, resolvePythonBinary } from '../lib/pythonRuntime.js';\nimport {\n type ExecutionResult,\n type HttpRequests,\n type StepInputValue,\n} from '../../shared/lib/execution.js';\nexport type {\n ExecutionResult,\n HttpRequests,\n HttpRequestEntry,\n} from '../../shared/lib/execution.js';\n\nconst WRAPPER_SCRIPT = `\nimport sys, json, os, traceback\n\n# --- Inputs proxy (attribute access) ---\nclass _InputsProxy:\n def __init__(self, data):\n object.__setattr__(self, '_data', data)\n\n def __getattr__(self, name):\n if name.startswith('_'):\n raise AttributeError(name)\n return self._data.get(name)\n\n def __repr__(self):\n return repr(self._data)\n\n def __str__(self):\n return str(self._data)\n\n def __bool__(self):\n return bool(self._data)\n\ninputs = _InputsProxy(json.loads(os.environ.get('__KIZEN_INPUTS__', '{}')))\n\n# --- Secrets ---\nsecrets = json.loads(os.environ.get('__KIZEN_SECRETS__', '{}'))\n\n# --- Outputs proxy ---\nclass _OutputsProxy:\n def __init__(self):\n object.__setattr__(self, '_values', {})\n object.__setattr__(self, '_logs', [])\n\n def __setattr__(self, name, value):\n if name.startswith('_'):\n object.__setattr__(self, name, value)\n else:\n self._values[name] = value\n\n def __getattr__(self, name):\n if name.startswith('_'):\n raise AttributeError(name)\n return self._values.get(name)\n\n def log(self, message):\n self._logs.append(str(message))\n\noutputs = _OutputsProxy()\n\n# --- HTTP request capture (requests library only) ---\n_kizen_http_requests = []\n\ndef _kizen_install_http_capture():\n try:\n import requests\n except Exception:\n return\n import time, datetime\n\n _original_send = requests.Session.send\n\n def _kizen_send(self, request, **kwargs):\n submitted_at = datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%d %H:%M:%S')\n start = time.time()\n error_type = None\n response = None\n try:\n response = _original_send(self, request, **kwargs)\n return response\n except Exception as exc:\n error_type = type(exc).__name__\n raise\n finally:\n body = request.body\n if isinstance(body, bytes):\n try:\n body = body.decode('utf-8')\n except Exception:\n body = '<binary>'\n elif body is None:\n body = ''\n\n status = 0\n resp_headers = {}\n resp_body = ''\n if response is not None:\n status = response.status_code\n resp_headers = dict(response.headers)\n if kwargs.get('stream'):\n resp_body = '<streamed>'\n else:\n try:\n resp_body = response.text\n except Exception:\n resp_body = '<unreadable>'\n\n _kizen_http_requests.append({\n 'method': request.method or '',\n 'url': request.url or '',\n 'headers': dict(request.headers or {}),\n 'body': body,\n 'requestSubmittedAt': submitted_at,\n 'session': True,\n 'responseStatusCode': status,\n 'responseHeaders': resp_headers,\n 'responseBody': resp_body,\n 'requestErrorType': error_type,\n 'duration': time.time() - start,\n })\n\n requests.Session.send = _kizen_send\n\n_kizen_install_http_capture()\n\ndef _kizen_http_summary():\n if not _kizen_http_requests:\n return None\n return {\n 'count': len(_kizen_http_requests),\n 'notLogged': 0,\n 'requests': _kizen_http_requests,\n }\n\n# --- Execute user script ---\ntry:\n exec(open(os.environ['__KIZEN_SCRIPT_PATH__'], encoding='utf-8').read())\n result = {\n 'success': True,\n 'outputValues': outputs._values,\n 'logs': outputs._logs,\n 'error': None,\n 'httpRequests': _kizen_http_summary(),\n }\nexcept Exception:\n # Build a clean traceback that hides the wrapper internals.\n # Keep only frames from the user script (shown as File \"<string>\")\n # and re-label them with \"script.py\" for clarity.\n exc_type, exc_value, exc_tb = sys.exc_info()\n entries = traceback.extract_tb(exc_tb)\n user_entries = [e for e in entries if e.filename != __file__]\n for e in user_entries:\n if e.filename == '<string>':\n e.filename = 'script.py'\n lines = ['Traceback (most recent call last):\\\\n']\n lines += traceback.format_list(user_entries)\n lines += traceback.format_exception_only(exc_type, exc_value)\n result = {\n 'success': False,\n 'outputValues': outputs._values,\n 'logs': outputs._logs,\n 'error': ''.join(lines),\n 'httpRequests': _kizen_http_summary(),\n }\n\n# Write results between markers so we can extract them reliably\n# even if the user script wrote to stdout\nsys.stdout.write('\\\\n__KIZEN_RESULT_START__\\\\n')\nsys.stdout.write(json.dumps(result, ensure_ascii=False))\nsys.stdout.write('\\\\n__KIZEN_RESULT_END__\\\\n')\nsys.stdout.flush()\n`.trim();\n\nconst DEFAULT_TIMEOUT = 30_000;\n\nexport type VenvInstallEvent =\n | { kind: 'start' }\n | { kind: 'log'; line: string; stream: 'stdout' | 'stderr' }\n | { kind: 'complete' }\n | { kind: 'error'; message: string };\n\nexport type VenvInstallListener = (event: VenvInstallEvent) => void;\n\nexport interface ExecuteStepParams {\n script: string;\n scriptRuntime: string;\n inputs: Record<string, StepInputValue>;\n secrets: Record<string, string>;\n timeout?: number;\n onInstallProgress?: VenvInstallListener;\n}\n\nconst VENV_DIR = join(process.cwd(), '.kizenapp', 'venv');\n\n// The production Kizen code-runner service only ships python-3-12 and\n// python-3-13 runtime images. Reject any other runtime locally so a bad or\n// unsupported \"runtime\" in a step's config.json fails fast\nconst SUPPORTED_RUNTIMES = ['python-3-12', 'python-3-13'] as const;\n\nfunction isSupportedRuntime(runtime: string): boolean {\n return (SUPPORTED_RUNTIMES as readonly string[]).includes(runtime);\n}\n\n// ./python-requirements.txt is the single source of truth for packages.\n// Keep it in sync with the Python dependency set installed by the production\n// Kizen code-runner service, so local runs match deployed ones.\nconst VENV_PACKAGES = parseRequirementsFile(requirementsTxt);\n\nif (VENV_PACKAGES.length === 0) {\n throw new Error('python-requirements.txt bundled no packages — check the build output');\n}\n\nlet venvReady: Promise<string> | null = null;\n\n// The bundled requirements (psycopg 3.3 in particular) require Python >= 3.10,\n// matching the remote code-runner which only ships 3.12 / 3.13 images. A venv\n// built on an older interpreter fails `pip install` with a cryptic\n// \"No matching distribution found for psycopg[binary]<4.0,>=3.3\".\nconst MIN_PYTHON: readonly [number, number] = [3, 10];\n\nfunction meetsMinimum([major, minor]: [number, number]): boolean {\n return major > MIN_PYTHON[0] || (major === MIN_PYTHON[0] && minor >= MIN_PYTHON[1]);\n}\n\nfunction formatVersion(version: readonly [number, number]): string {\n return `${String(version[0])}.${String(version[1])}`;\n}\n\n// Probe an interpreter for its (major, minor) version. Resolves null if the\n// binary is missing or can't run, so callers can try the next candidate.\nfunction probePython(bin: string): Promise<[number, number] | null> {\n return new Promise((resolve) => {\n const proc = spawn(bin, ['-c', \"import sys; print('%d.%d' % sys.version_info[:2])\"], {\n stdio: ['ignore', 'pipe', 'ignore'],\n });\n\n let out = '';\n\n proc.stdout.on('data', (chunk: Buffer) => {\n out += chunk.toString('utf-8');\n });\n proc.on('error', () => {\n resolve(null);\n });\n proc.on('close', (code) => {\n const match = /(\\d+)\\.(\\d+)/.exec(out);\n\n if (code !== 0 || !match) {\n resolve(null);\n\n return;\n }\n\n resolve([Number(match[1]), Number(match[2])]);\n });\n });\n}\n\n// Pick a system interpreter new enough to install the bundled requirements.\n// Prefer the exact version the runtime asked for, then fall back to python3.\n// Throws a clear, actionable error when nothing usable is found.\nasync function findSystemPython(runtime: string): Promise<string> {\n const preferred = resolvePythonBinary(runtime);\n const candidates = preferred === 'python3' ? ['python3'] : [preferred, 'python3'];\n const tried: string[] = [];\n\n for (const bin of candidates) {\n const version = await probePython(bin);\n\n if (!version) {\n tried.push(`${bin}: not found`);\n\n continue;\n }\n\n if (meetsMinimum(version)) {\n return bin;\n }\n\n tried.push(`${bin}: ${formatVersion(version)} (too old)`);\n }\n\n throw new Error(\n `No Python >= ${formatVersion(MIN_PYTHON)} found for runtime \"${runtime}\". ` +\n `The local runner needs Python ${formatVersion(MIN_PYTHON)}+ to install the bundled ` +\n `packages (e.g. psycopg 3.3), matching the remote code-runner (3.12 / 3.13). ` +\n `Tried ${tried.join(', ')}. Install Python 3.12 or 3.13 and retry.`,\n );\n}\n\nfunction runCommand(\n bin: string,\n args: string[],\n onLine?: (line: string, stream: 'stdout' | 'stderr') => void,\n): Promise<void> {\n return new Promise((resolve, reject) => {\n const proc = spawn(bin, args, { stdio: ['ignore', 'pipe', 'pipe'] });\n\n const pipeLines = (source: NodeJS.ReadableStream, stream: 'stdout' | 'stderr'): string[] => {\n const captured: string[] = [];\n let buffer = '';\n\n source.on('data', (chunk: Buffer) => {\n buffer += chunk.toString('utf-8');\n\n let idx = buffer.indexOf('\\n');\n\n while (idx >= 0) {\n const line = buffer.slice(0, idx).replace(/\\r$/, '');\n\n buffer = buffer.slice(idx + 1);\n\n captured.push(line);\n onLine?.(line, stream);\n idx = buffer.indexOf('\\n');\n }\n });\n\n source.on('end', () => {\n if (buffer.length > 0) {\n const line = buffer.replace(/\\r$/, '');\n\n captured.push(line);\n onLine?.(line, stream);\n }\n });\n\n return captured;\n };\n\n const stderrCaptured = pipeLines(proc.stderr, 'stderr');\n\n pipeLines(proc.stdout, 'stdout');\n\n proc.on('error', reject);\n proc.on('close', (code) => {\n if (code === 0) {\n resolve();\n } else {\n const tail = stderrCaptured.slice(-10).join('\\n').trim();\n const detail = tail.length > 0 ? `: ${tail}` : '';\n\n reject(new Error(`${bin} exited with code ${String(code)}${detail}`));\n }\n });\n });\n}\n\n// Progress listeners for the in-flight venv build, so every caller awaiting the\n// same build receives its install output. Non-null only while a build is live,\n// so a cached-return call doesn't leak a listener that never fires.\nlet venvInstallListeners: Set<VenvInstallListener> | null = null;\n\nfunction ensureVenv(runtime: string, listener?: VenvInstallListener): Promise<string> {\n if (venvReady) {\n // Build already running or done. Attach to its progress if it's still live.\n if (listener) {\n venvInstallListeners?.add(listener);\n }\n\n return venvReady;\n }\n\n const listeners = new Set<VenvInstallListener>();\n\n if (listener) {\n listeners.add(listener);\n }\n\n venvInstallListeners = listeners;\n\n const emit = (event: VenvInstallEvent): void => {\n for (const l of listeners) {\n l(event);\n }\n };\n\n const venvPython = join(VENV_DIR, 'bin', 'python');\n\n venvReady = (async () => {\n try {\n // Reuse an existing venv only when its interpreter is new enough for the\n // bundled requirements; otherwise rebuild it. A stale venv (e.g. Python\n // 3.9) would otherwise fail `pip install` every time with a cryptic\n // \"No matching distribution\" error for psycopg 3.3.\n let reusable = false;\n\n try {\n await access(venvPython);\n\n const existing = await probePython(venvPython);\n\n reusable = existing !== null && meetsMinimum(existing);\n } catch {\n reusable = false;\n }\n\n if (!reusable) {\n // Clear any stale/half-built venv before recreating it. Best-effort:\n // rm of a missing dir is a no-op with force.\n await rm(VENV_DIR, { recursive: true, force: true }).catch(() => {\n /* ignore */\n });\n\n const systemPython = await findSystemPython(runtime);\n\n await runCommand(systemPython, ['-m', 'venv', VENV_DIR]);\n }\n\n emit({ kind: 'start' });\n\n await runCommand(\n venvPython,\n ['-m', 'pip', 'install', '--disable-pip-version-check', ...VENV_PACKAGES],\n (line, stream) => {\n emit({ kind: 'log', line, stream });\n },\n );\n\n emit({ kind: 'complete' });\n\n return venvPython;\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n\n emit({ kind: 'error', message });\n\n // Reset so the next call retries rather than returning the cached\n // rejection forever. Also nuke the venv dir: a half-built venv (a failed\n // `python -m venv` or an interpreter that's too old) would confuse the\n // reuse check on the next attempt. rm is best-effort — we rebuild either\n // way.\n venvReady = null;\n\n await rm(VENV_DIR, { recursive: true, force: true }).catch(() => {\n /* ignore */\n });\n\n throw err;\n } finally {\n venvInstallListeners = null;\n }\n })();\n\n return venvReady;\n}\n\nfunction parseResult(stdout: string): {\n userStdout: string;\n result: {\n success: boolean;\n outputValues: Record<string, unknown>;\n logs: string[];\n error: string | null;\n httpRequests: HttpRequests | null;\n } | null;\n} {\n const startMarker = '__KIZEN_RESULT_START__';\n const endMarker = '__KIZEN_RESULT_END__';\n const startIdx = stdout.indexOf(startMarker);\n const endIdx = stdout.indexOf(endMarker);\n\n if (startIdx === -1 || endIdx === -1) {\n return { userStdout: stdout, result: null };\n }\n\n const userStdout = stdout.slice(0, startIdx).trimEnd();\n const jsonStr = stdout.slice(startIdx + startMarker.length, endIdx).trim();\n\n try {\n const result = JSON.parse(jsonStr) as {\n success: boolean;\n outputValues: Record<string, unknown>;\n logs: string[];\n error: string | null;\n httpRequests: HttpRequests | null;\n };\n\n return { userStdout, result };\n } catch {\n return { userStdout: stdout, result: null };\n }\n}\n\nfunction failedExecutionResult(error: string): ExecutionResult {\n return {\n success: false,\n outputValues: {},\n logs: [],\n stdout: '',\n stderr: '',\n error,\n exitCode: 1,\n durationMs: 0,\n };\n}\n\nexport async function executePythonStep(params: ExecuteStepParams): Promise<ExecutionResult> {\n const timeout = params.timeout ?? DEFAULT_TIMEOUT;\n\n // Fail fast on a runtime the remote code-runner can't run, instead of\n // silently building a venv on whatever interpreter is handy.\n if (!isSupportedRuntime(params.scriptRuntime)) {\n return failedExecutionResult(\n `Unsupported runtime \"${params.scriptRuntime}\". Supported runtimes: ` +\n `${SUPPORTED_RUNTIMES.join(', ')}. Update the step's config.json \"runtime\" field ` +\n `(e.g. \"python 3.13\").`,\n );\n }\n\n const pythonBin = await ensureVenv(params.scriptRuntime, params.onInstallProgress);\n const start = Date.now();\n\n let tmpDir: string | undefined;\n\n try {\n tmpDir = await mkdtemp(join(tmpdir(), 'kizen-step-'));\n\n const wrapperPath = join(tmpDir, 'wrapper.py');\n const scriptPath = join(tmpDir, 'script.py');\n\n await Promise.all([\n writeFile(wrapperPath, WRAPPER_SCRIPT, 'utf-8'),\n writeFile(scriptPath, params.script, 'utf-8'),\n ]);\n\n const env: Record<string, string> = {\n ...(process.env as Record<string, string>),\n __KIZEN_INPUTS__: JSON.stringify(params.inputs),\n __KIZEN_SECRETS__: JSON.stringify(params.secrets),\n __KIZEN_SCRIPT_PATH__: scriptPath,\n };\n\n const { exitCode, stdout, stderr } = await new Promise<{\n exitCode: number;\n stdout: string;\n stderr: string;\n }>((resolve) => {\n const stdoutChunks: Buffer[] = [];\n const stderrChunks: Buffer[] = [];\n let settled = false;\n\n const proc = spawn(pythonBin, [wrapperPath], {\n env,\n cwd: tmpDir,\n stdio: ['ignore', 'pipe', 'pipe'],\n });\n\n const timer = setTimeout(() => {\n proc.kill('SIGKILL');\n }, timeout);\n\n proc.stdout.on('data', (chunk: Buffer) => {\n stdoutChunks.push(chunk);\n });\n\n proc.stderr.on('data', (chunk: Buffer) => {\n stderrChunks.push(chunk);\n });\n\n const finish = (code: number | null): void => {\n if (settled) {\n return;\n }\n\n settled = true;\n clearTimeout(timer);\n resolve({\n exitCode: code ?? 1,\n stdout: Buffer.concat(stdoutChunks).toString('utf-8'),\n stderr: Buffer.concat(stderrChunks).toString('utf-8'),\n });\n };\n\n proc.on('close', finish);\n proc.on('error', (err) => {\n if (settled) {\n return;\n }\n\n settled = true;\n clearTimeout(timer);\n resolve({\n exitCode: 1,\n stdout: '',\n stderr: err.message,\n });\n });\n });\n\n const durationMs = Date.now() - start;\n const { userStdout, result } = parseResult(stdout);\n\n if (result) {\n const base: ExecutionResult = {\n success: result.success,\n outputValues: result.outputValues,\n logs: result.logs,\n stdout: userStdout,\n stderr,\n exitCode,\n durationMs,\n };\n\n if (result.error !== null) {\n base.error = result.error;\n }\n\n if (result.httpRequests) {\n base.httpRequests = result.httpRequests;\n }\n\n return base;\n }\n\n // If we couldn't parse the result, the wrapper itself likely failed\n const base: ExecutionResult = {\n success: false,\n outputValues: {},\n logs: [],\n stdout: userStdout,\n stderr,\n exitCode,\n durationMs,\n };\n\n if (exitCode !== 0) {\n base.error = `Process exited with code ${String(exitCode)}`;\n }\n\n return base;\n } finally {\n if (tmpDir) {\n void rm(tmpDir, { recursive: true, force: true });\n }\n }\n}\n","awslambdaric\nbcrypt\nboto3\nfpdf2\nlxml\nmsgpack\nnumpy\noracledb\nparamiko\npsycopg[binary]>=3.3,<4.0\npyjwt[crypto]\npymysql[rsa,ed25519]\npypdf[full]\npython-dateutil\npytz\nrequests\nsqlalchemy>=2.0,<2.1\ntzdata\n","export function parseRequirementsFile(content: string): string[] {\n return content\n .split('\\n')\n .map((line) => line.trim().replace(/\\s+#.*$/, ''))\n .filter((line) => line.length > 0 && !line.startsWith('#'));\n}\n\nexport function resolvePythonBinary(runtime: string): string {\n const match = /^python-(\\d+)[.-](\\d+)$/.exec(runtime);\n const major = match?.[1];\n const minor = match?.[2];\n\n if (major !== undefined && minor !== undefined) {\n return `python${major}.${minor}`;\n }\n\n return 'python3';\n}\n","export interface HttpRequestEntry {\n method: string;\n url: string;\n headers: Record<string, string>;\n body: string;\n requestSubmittedAt: string;\n session: boolean;\n responseStatusCode: number;\n responseHeaders: Record<string, string>;\n responseBody: string;\n requestErrorType: string | null;\n duration: number;\n}\n\nexport interface HttpRequests {\n count: number;\n notLogged: number;\n requests: HttpRequestEntry[];\n}\n\nexport interface ExecutionResult {\n success: boolean;\n outputValues: Record<string, unknown>;\n logs: string[];\n stdout: string;\n stderr: string;\n error?: string;\n exitCode: number;\n durationMs: number;\n httpRequests?: HttpRequests;\n}\n\nexport type StepInputValue = string | null;\n\nexport function toStepInputValue(raw: string | null | undefined): StepInputValue {\n return raw === undefined || raw === null || raw.trim() === '' ? null : raw;\n}\n\nexport function buildStepInputs(\n names: string[],\n rawValues: Record<string, string>,\n): Record<string, StepInputValue> {\n return Object.fromEntries(names.map((name) => [name, toStepInputValue(rawValues[name])]));\n}\n\nfunction coerceStepInputValue(value: unknown): StepInputValue {\n if (value === null || value === undefined) {\n return null;\n }\n\n if (typeof value === 'string') {\n return toStepInputValue(value);\n }\n\n if (typeof value === 'number' || typeof value === 'boolean' || typeof value === 'bigint') {\n return String(value);\n }\n\n if (typeof value === 'function' || typeof value === 'symbol') {\n return null;\n }\n\n return JSON.stringify(value);\n}\n\nexport function normalizeStepInputs(\n inputs: Record<string, unknown> | undefined,\n): Record<string, StepInputValue> {\n if (!inputs) {\n return {};\n }\n\n return Object.fromEntries(\n Object.entries(inputs).map(([name, value]) => [name, coerceStepInputValue(value)]),\n );\n}\n","export const TEXT_EXTENSIONS = new Set([\n '.ts',\n '.tsx',\n '.js',\n '.jsx',\n '.mjs',\n '.cjs',\n '.json',\n '.md',\n '.mdx',\n '.yml',\n '.yaml',\n '.toml',\n '.css',\n '.scss',\n '.html',\n '.htm',\n '.xml',\n '.svg',\n '.txt',\n '.sh',\n '.py',\n '.env',\n '.gitignore',\n '.prettierrc',\n '.eslintrc',\n]);\n","export type ProxyLogEntry =\n | {\n kind: 'request';\n method: string;\n status: number;\n // For calls to Kizen's `/external-integrations/proxy` endpoint, the\n // third-party API's status is carried in the response body (`status_code`)\n // rather than the HTTP status. `status` is the proxy status; this is the\n // upstream one. Undefined for non-proxy calls.\n upstreamStatus?: number | undefined;\n fromCache: boolean;\n url: string;\n }\n | { kind: 'info'; message: string };\n\nexport function proxyLogEntryToString(entry: ProxyLogEntry): string {\n if (entry.kind === 'info') {\n return entry.message;\n }\n\n const cache = entry.fromCache ? ' [cache]' : '';\n const upstream =\n entry.upstreamStatus !== undefined ? ` (upstream ${String(entry.upstreamStatus)})` : '';\n\n return `${entry.method} ${entry.url} → ${String(entry.status)}${upstream}${cache}`;\n}\n","import { launch } from 'chrome-launcher';\nimport type { LaunchedChrome } from 'chrome-launcher';\nimport { createRequire } from 'node:module';\nimport { mkdirSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nconst CDP = createRequire(import.meta.url)('chrome-remote-interface') as (opts: {\n port: number;\n}) => Promise<CDPClient>;\n\ninterface CDPHeader {\n name: string;\n value: string;\n}\n\ninterface CDPFetchPausedEvent {\n requestId: string;\n request: { url: string };\n responseHeaders?: CDPHeader[];\n responseStatusCode?: number;\n}\n\ninterface CDPClient {\n Fetch: {\n enable: (opts: { patterns: { urlPattern: string; requestStage: string }[] }) => Promise<void>;\n getResponseBody: (opts: {\n requestId: string;\n }) => Promise<{ body: string; base64Encoded: boolean }>;\n fulfillRequest: (opts: {\n requestId: string;\n responseCode: number;\n responseHeaders: CDPHeader[];\n body?: string;\n base64Encoded?: boolean;\n }) => Promise<void>;\n continueRequest: (opts: { requestId: string }) => Promise<void>;\n };\n Network: {\n getAllCookies: () => Promise<{ cookies: CDPCookie[] }>;\n setCookie: (opts: CDPCookieSet) => Promise<void>;\n };\n Target: {\n setDiscoverTargets: (opts: { discover: boolean }) => Promise<void>;\n closeTarget: (opts: { targetId: string }) => Promise<void>;\n activateTarget: (opts: { targetId: string }) => Promise<void>;\n };\n Browser: {\n setDockTile: (opts: { image?: string; label?: string }) => Promise<void>;\n };\n send: (method: string, params?: object, sessionId?: string) => Promise<unknown>;\n on: (event: string, handler: (params: unknown, sessionId?: string) => void) => void;\n close: () => Promise<void>;\n}\n\ninterface CDPTargetCreatedEvent {\n targetInfo: {\n targetId: string;\n type: string;\n url: string;\n };\n}\n\ninterface CDPCookie {\n name: string;\n value: string;\n domain?: string;\n path?: string;\n secure?: boolean;\n httpOnly?: boolean;\n sameSite?: string;\n expirationDate?: number;\n}\n\ninterface CDPCookieSet {\n url: string;\n name: string;\n value: string;\n domain?: string;\n path?: string;\n secure?: boolean;\n httpOnly?: boolean;\n sameSite?: string;\n expires?: number;\n}\n\nconst CSP_HEADERS = new Set([\n 'content-security-policy',\n 'content-security-policy-report-only',\n 'x-frame-options',\n]);\n\nconst KIZEN_DOMAINS = ['kizen.dev', 'kizen.com'];\n\nfunction isKizenUrl(url: string): boolean {\n try {\n const { hostname } = new URL(url);\n\n return KIZEN_DOMAINS.some((d) => hostname === d || hostname.endsWith('.' + d));\n } catch {\n return false;\n }\n}\n\nasync function installDockIcon(client: CDPClient): Promise<void> {\n try {\n const iconPath = join(dirname(fileURLToPath(import.meta.url)), 'viewer', 'icon.png');\n const icon = await readFile(iconPath);\n\n await client.Browser.setDockTile({ image: icon.toString('base64') });\n } catch {\n // Non-critical: silently skip if icon is missing or platform doesn't support it\n }\n}\n\nexport interface ChromeViewerOptions {\n port: number;\n userDataDir: string;\n broadcast: (msg: object) => void;\n path?: string;\n debugLog?: (msg: string) => void;\n // Always-on channel for user-visible warnings (e.g. \"CDP unavailable,\n // running without interception\"). Unlike debugLog, not gated by --debug.\n onWarn?: (msg: string) => void;\n verbose?: boolean;\n}\n\nexport interface ChromeViewerHandle {\n kill: () => void;\n}\n\nexport async function launchChromeViewer(opts: ChromeViewerOptions): Promise<ChromeViewerHandle> {\n // chrome-launcher opens log files inside userDataDir before Chrome starts\n mkdirSync(opts.userDataDir, { recursive: true });\n\n const baseUrl = `http://localhost:${String(opts.port)}`;\n\n const chrome: LaunchedChrome = await launch({\n startingUrl: baseUrl,\n chromeFlags: [\n `--app=${baseUrl}`,\n '--no-first-run',\n '--no-default-browser-check',\n '--disable-extensions',\n '--disable-features=DeviceBoundSessions',\n ],\n userDataDir: opts.userDataDir,\n handleSIGINT: false,\n logLevel: 'silent',\n });\n\n const cdpPort = chrome.port;\n\n let client: CDPClient | null = null;\n let cookieTimer: ReturnType<typeof setInterval> | null = null;\n let mainTargetId: string | null = null;\n let reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n let reconnectAttempt = 0;\n let killed = false;\n\n const dbg = (msg: string): void => {\n opts.debugLog?.(msg);\n };\n\n const vb = (msg: string): void => {\n if (opts.verbose) {\n opts.debugLog?.(msg);\n }\n };\n\n const clearCookieTimer = (): void => {\n if (cookieTimer !== null) {\n clearInterval(cookieTimer);\n cookieTimer = null;\n }\n };\n\n const isNewTabUrl = (url: string): boolean =>\n url === 'chrome://new-tab-page/' || url === 'chrome://newtab/';\n\n const setupClient = async (c: CDPClient): Promise<void> => {\n // Fresh CDP session: reset per-connection state.\n clearCookieTimer();\n mainTargetId = null;\n\n await installDockIcon(c);\n\n // ── 1. Response interception: strip CSP + fix SameSite cookies ──────────────\n await c.Fetch.enable({\n patterns: KIZEN_DOMAINS.flatMap((d) => [\n { urlPattern: `*://${d}/*`, requestStage: 'Response' },\n { urlPattern: `*://*.${d}/*`, requestStage: 'Response' },\n ]),\n });\n\n c.on('Fetch.requestPaused', (rawParams: unknown) => {\n void (async () => {\n const params = rawParams as CDPFetchPausedEvent;\n const { requestId, request, responseHeaders, responseStatusCode } = params;\n const url = request.url;\n\n vb(`Fetch ${String(responseStatusCode ?? '?')} ${url}`);\n\n const filtered: CDPHeader[] = [];\n let rewroteSetCookie = false;\n\n for (const h of responseHeaders ?? []) {\n if (CSP_HEADERS.has(h.name.toLowerCase())) {\n continue;\n }\n\n if (h.name.toLowerCase() === 'set-cookie' && isKizenUrl(url)) {\n const patched = h.value\n .split('\\n')\n .map((cookie) => {\n if (!/SameSite=/i.test(cookie)) {\n return cookie + '; SameSite=None; Secure';\n }\n\n return cookie.replace(/SameSite=\\w+/i, 'SameSite=None');\n })\n .join('\\n');\n\n filtered.push({ name: h.name, value: patched });\n rewroteSetCookie = true;\n } else {\n filtered.push(h);\n }\n }\n\n if (rewroteSetCookie) {\n vb(` rewrote Set-Cookie SameSite on ${url}`);\n }\n\n try {\n const { body, base64Encoded } = await c.Fetch.getResponseBody({ requestId });\n\n await c.Fetch.fulfillRequest({\n requestId,\n responseCode: responseStatusCode ?? 200,\n responseHeaders: filtered,\n body,\n ...(base64Encoded && { base64Encoded: true }),\n });\n } catch (e) {\n vb(` fulfillRequest failed (${(e as Error).message}), falling through`);\n\n try {\n await c.Fetch.continueRequest({ requestId });\n } catch (e2) {\n vb(` continueRequest also failed (${(e2 as Error).message})`);\n }\n }\n })();\n });\n\n // ── 2. Periodic SameSite cookie patching ────────────────────────────────────\n cookieTimer = setInterval(() => {\n void (async () => {\n try {\n const { cookies } = await c.Network.getAllCookies();\n\n let patched = 0;\n\n for (const cookie of cookies) {\n if (!isKizenUrl(`https://${cookie.domain ?? ''}`)) {\n continue;\n }\n\n if (cookie.sameSite === 'None') {\n continue;\n }\n\n const raw = cookie.domain ?? '';\n const bare = raw.startsWith('.') ? raw.slice(1) : raw;\n\n await c.Network.setCookie({\n url: `https://${bare}`,\n name: cookie.name,\n value: cookie.value,\n domain: raw,\n path: cookie.path ?? '/',\n secure: true,\n ...(cookie.httpOnly !== undefined && { httpOnly: cookie.httpOnly }),\n ...(cookie.expirationDate !== undefined && {\n expires: cookie.expirationDate,\n }),\n sameSite: 'None',\n });\n\n patched++;\n }\n\n if (patched > 0) {\n vb(`cookie-patch cycle: updated ${String(patched)} cookie(s) to SameSite=None`);\n }\n } catch (e) {\n vb(`cookie-patch cycle failed: ${(e as Error).message}`);\n }\n })();\n }, 2000);\n\n // macOS dock clicks on --app= windows open a stray new-tab-page window\n // (Chromium excludes app windows from its \"is a browser window open?\" check).\n // activate the original app window, then close the intruder. setDiscoverTargets replays\n // existing targets so mainTargetId gets recaptured after a CDP reconnect.\n await c.Target.setDiscoverTargets({ discover: true });\n\n const handleTarget = (targetInfo: { targetId: string; type: string; url: string }): void => {\n if (targetInfo.type !== 'page') {\n return;\n }\n\n if (isNewTabUrl(targetInfo.url)) {\n dbg(`closed stray new-tab-page target ${targetInfo.targetId}`);\n\n if (mainTargetId !== null) {\n void c.Target.activateTarget({ targetId: mainTargetId }).catch(() => {\n /* ignore */\n });\n }\n\n void c.Target.closeTarget({ targetId: targetInfo.targetId }).catch(() => {\n /* ignore */\n });\n\n return;\n }\n\n if (mainTargetId === null) {\n mainTargetId = targetInfo.targetId;\n dbg(`captured main target ${targetInfo.targetId} (${targetInfo.url})`);\n }\n };\n\n c.on('Target.targetCreated', (rawParams: unknown) => {\n const { targetInfo } = rawParams as CDPTargetCreatedEvent;\n\n vb(`target +${targetInfo.type} ${targetInfo.targetId} ${targetInfo.url}`);\n handleTarget(targetInfo);\n });\n\n c.on('Target.targetInfoChanged', (rawParams: unknown) => {\n const { targetInfo } = rawParams as CDPTargetCreatedEvent;\n\n vb(`target ~${targetInfo.type} ${targetInfo.targetId} ${targetInfo.url}`);\n handleTarget(targetInfo);\n });\n\n // CDP's underlying WebSocket can drop (sleep/wake, transient failure) while\n // Chrome keeps running. Without reconnect, all interception silently stops.\n c.on('disconnect', () => {\n if (killed || client !== c) {\n return;\n }\n\n dbg('CDP disconnected');\n client = null;\n clearCookieTimer();\n scheduleReconnect();\n });\n };\n\n const scheduleReconnect = (): void => {\n if (killed || reconnectTimer !== null) {\n return;\n }\n\n const delay = Math.min(1000 * 2 ** reconnectAttempt, 10_000);\n const attemptNumber = reconnectAttempt + 1;\n\n reconnectAttempt++;\n\n dbg(`CDP reconnect scheduled in ${String(delay)}ms (attempt #${String(attemptNumber)})`);\n\n reconnectTimer = setTimeout(() => {\n reconnectTimer = null;\n\n void (async () => {\n let c: CDPClient;\n\n try {\n c = await CDP({ port: cdpPort });\n } catch {\n dbg(`CDP reconnect attempt #${String(attemptNumber)} failed`);\n scheduleReconnect();\n\n return;\n }\n\n if (killed) {\n try {\n await c.close();\n } catch {\n /* ignore */\n }\n\n return;\n }\n\n client = c;\n\n try {\n await setupClient(c);\n dbg(`CDP reconnected after ${String(attemptNumber)} attempt(s)`);\n reconnectAttempt = 0;\n } catch {\n if (client === c) {\n client = null;\n }\n\n try {\n await c.close();\n } catch {\n /* ignore */\n }\n\n dbg(`CDP reconnect attempt #${String(attemptNumber)} failed during setup`);\n scheduleReconnect();\n }\n })();\n }, delay);\n };\n\n // Initial CDP connection — Chrome may not be ready immediately. 30 × 300ms\n // (9s total) gives cold starts, slow disks, and Rosetta-translated Chromium\n // a reasonable window before we give up and run without interception.\n const MAX_CDP_ATTEMPTS = 30;\n const CDP_ATTEMPT_DELAY_MS = 300;\n\n for (let attempt = 0; attempt < MAX_CDP_ATTEMPTS; attempt++) {\n await new Promise<void>((r) => setTimeout(r, CDP_ATTEMPT_DELAY_MS));\n\n dbg(`CDP connect attempt ${String(attempt + 1)}/${String(MAX_CDP_ATTEMPTS)}`);\n\n try {\n const c = await CDP({ port: cdpPort });\n\n client = c;\n\n if (opts.path) {\n void c.send('Page.navigate', { url: `${baseUrl}${opts.path}` });\n }\n\n try {\n await setupClient(c);\n dbg('CDP connected');\n } catch {\n if (client === c) {\n client = null;\n }\n\n try {\n await c.close();\n } catch {\n /* ignore */\n }\n\n dbg('CDP setup failed after connect');\n }\n\n break;\n } catch {\n if (attempt === MAX_CDP_ATTEMPTS - 1) {\n // CDP never came up; window still opens, just no CSP rewrite or\n // SameSite cookie patching. Surface this via onWarn so it appears in\n // the TUI even when the user didn't pass --debug.\n const warning = `CDP unavailable after ${String(MAX_CDP_ATTEMPTS)} attempts — viewer running without interception (CSP/cookie rewrites disabled)`;\n\n dbg(warning);\n opts.onWarn?.(warning);\n\n return {\n kill: () => {\n chrome.kill();\n },\n };\n }\n }\n }\n\n if (!client) {\n return {\n kill: () => {\n chrome.kill();\n },\n };\n }\n\n const kill = (): void => {\n dbg('CDP kill requested — tearing down');\n killed = true;\n\n if (reconnectTimer !== null) {\n clearTimeout(reconnectTimer);\n reconnectTimer = null;\n }\n\n clearCookieTimer();\n\n if (client !== null) {\n try {\n void client.close();\n } catch {\n /* ignore */\n }\n\n client = null;\n }\n\n chrome.kill();\n };\n\n return { kill };\n}\n","import { useCallback, useState } from 'react';\n\nexport function useLogHistory(limit: number): [string[], (message: string) => void] {\n const [history, setHistory] = useState<string[]>([]);\n\n const append = useCallback(\n (message: string): void => {\n setHistory((h) => [...h, `${new Date().toLocaleTimeString()}: ${message}`].slice(-limit));\n },\n [limit],\n );\n\n return [history, append];\n}\n","import type { FC } from 'react';\nimport { useCallback, useEffect, useState } from 'react';\nimport { Box, Text, useInput } from 'ink';\nimport {\n DEFAULT_PROFILE_NAME,\n ENVIRONMENTS,\n GLOBAL_CREDENTIALS_PATH,\n listCredentialProfiles,\n loadCredentialProfile,\n loadGlobalCredentials,\n normalizeCredentialIds,\n saveCredentialProfile,\n} from '../lib/credentials.js';\nimport type { CredentialProfile, Credentials } from '../lib/credentials.js';\nimport { AppHeader } from './AppHeader.js';\n\ntype Mode = 'global' | 'local';\n\ntype Phase =\n | { type: 'mode-select'; cursor: 0 | 1 }\n | { type: 'profile-loading' }\n | { type: 'profile-select'; profiles: CredentialProfile[]; cursor: number }\n | {\n type: 'name-entry';\n nameBuffer: string;\n nameError?: string;\n existingProfiles: CredentialProfile[];\n }\n | { type: 'loading' }\n | { type: 'creds-entry'; field: number; values: Partial<Credentials>; envCursor: number }\n | { type: 'saving' }\n | { type: 'done' };\n\nconst FIELDS = ['apiKey', 'userId', 'businessId'] as const;\nconst FIELD_LABELS: Record<string, string> = {\n apiKey: 'API Key',\n userId: 'User ID',\n businessId: 'Business ID',\n};\n\nexport type CredentialMode = 'global' | 'local';\n\nexport interface CredentialSetupResult {\n mode: CredentialMode;\n credentials: Credentials | null;\n profileName?: string;\n}\n\ninterface CredentialSetupUIProps {\n initialMode?: CredentialMode;\n showProfileManager?: boolean;\n onComplete: (result: CredentialSetupResult) => void;\n onCancel?: () => void;\n}\n\nconst Hint: FC<{ text: string }> = ({ text }) => <Text dimColor>{text}</Text>;\n\nexport const CredentialSetupUI: FC<CredentialSetupUIProps> = ({\n initialMode,\n showProfileManager,\n onComplete,\n onCancel,\n}) => {\n const [phase, setPhase] = useState<Phase>(\n initialMode === 'global' && !showProfileManager\n ? { type: 'loading' }\n : initialMode === 'global' && showProfileManager\n ? { type: 'profile-loading' }\n : { type: 'mode-select', cursor: 0 },\n );\n const [inputBuffer, setInputBuffer] = useState('');\n const [error, setError] = useState<string | null>(null);\n const [activeProfileName, setActiveProfileName] = useState<string | undefined>(undefined);\n\n const handleModeChosen = useCallback(\n (mode: Mode) => {\n if (mode === 'local') {\n onComplete({ mode: 'local', credentials: null });\n\n return;\n }\n\n setPhase({ type: 'profile-loading' });\n },\n [onComplete],\n );\n\n const handleProfileChosen = useCallback(async (profile: CredentialProfile | null) => {\n if (profile === null) {\n // \"Add new profile\" selected\n setPhase({ type: 'profile-loading' });\n\n const profiles = await listCredentialProfiles();\n\n setPhase({ type: 'name-entry', nameBuffer: '', existingProfiles: profiles });\n\n return;\n }\n\n setActiveProfileName(profile.isDefault ? undefined : profile.name);\n\n setPhase({ type: 'loading' });\n\n const existing = profile.isDefault\n ? await loadGlobalCredentials()\n : await loadCredentialProfile(profile.name);\n const envCursor = existing ? Math.max(0, ENVIRONMENTS.indexOf(existing.environment)) : 0;\n\n setPhase({ type: 'creds-entry', field: 0, values: existing ?? {}, envCursor });\n }, []);\n\n const handleSave = useCallback(\n async (values: Partial<Credentials>, envCursor: number) => {\n const environment = ENVIRONMENTS[envCursor] ?? 'go';\n const credentials: Credentials = {\n ...normalizeCredentialIds(values),\n environment,\n };\n\n setPhase({ type: 'saving' });\n\n try {\n const profileName = activeProfileName ?? DEFAULT_PROFILE_NAME;\n\n await saveCredentialProfile(profileName, credentials);\n\n onComplete({\n mode: 'global',\n credentials,\n ...(activeProfileName !== undefined && { profileName: activeProfileName }),\n });\n } catch (err) {\n setError(err instanceof Error ? err.message : String(err));\n\n setPhase({ type: 'creds-entry', field: 0, values, envCursor });\n }\n },\n [onComplete, activeProfileName],\n );\n\n useInput((input, key) => {\n if (key.ctrl && input === 'c') {\n process.exit(0);\n }\n\n if (key.escape) {\n if (phase.type === 'creds-entry' || phase.type === 'name-entry') {\n // Go back to profile select if we came from there\n if (initialMode === 'global' && showProfileManager) {\n setPhase({ type: 'profile-loading' });\n\n void loadProfileList();\n\n return;\n }\n }\n\n onCancel?.();\n\n return;\n }\n\n if (phase.type === 'mode-select') {\n if (key.upArrow) {\n setPhase({ type: 'mode-select', cursor: 0 });\n } else if (key.downArrow) {\n setPhase({ type: 'mode-select', cursor: 1 });\n } else if (key.return) {\n const mode: Mode = phase.cursor === 0 ? 'global' : 'local';\n\n handleModeChosen(mode);\n }\n\n return;\n }\n\n if (phase.type === 'profile-select') {\n const { profiles, cursor } = phase;\n const addNewIdx = profiles.length;\n const totalItems = profiles.length + 1; // +1 for \"Add new\"\n\n if (key.upArrow) {\n setPhase({ ...phase, cursor: (cursor - 1 + totalItems) % totalItems });\n } else if (key.downArrow) {\n setPhase({ ...phase, cursor: (cursor + 1) % totalItems });\n } else if (key.return) {\n if (cursor === addNewIdx) {\n setPhase({ type: 'name-entry', nameBuffer: '', existingProfiles: profiles });\n } else {\n const selected = profiles[cursor] ?? profiles[0];\n\n if (selected) {\n void handleProfileChosen(selected);\n }\n }\n }\n\n return;\n }\n\n if (phase.type === 'name-entry') {\n const { nameBuffer, existingProfiles } = phase;\n\n if (key.backspace || key.delete) {\n setPhase({ type: 'name-entry', nameBuffer: nameBuffer.slice(0, -1), existingProfiles });\n } else if (key.return) {\n const trimmed = nameBuffer.trim();\n\n if (!trimmed) {\n setPhase({ ...phase, nameError: 'Name cannot be empty' });\n\n return;\n }\n\n if (trimmed === DEFAULT_PROFILE_NAME) {\n setPhase({ ...phase, nameError: `\"${DEFAULT_PROFILE_NAME}\" is reserved` });\n\n return;\n }\n\n if (existingProfiles.some((p) => p.name === trimmed)) {\n setPhase({ ...phase, nameError: `Profile \"${trimmed}\" already exists` });\n\n return;\n }\n\n // Valid name — proceed to empty creds-entry\n setActiveProfileName(trimmed);\n\n setPhase({ type: 'creds-entry', field: 0, values: {}, envCursor: 0 });\n\n setInputBuffer('');\n } else if (input && !key.ctrl && !key.meta) {\n setPhase({ type: 'name-entry', nameBuffer: nameBuffer + input, existingProfiles });\n }\n\n return;\n }\n\n if (phase.type === 'creds-entry') {\n const { field, values, envCursor } = phase;\n const isEnvField = field === FIELDS.length;\n\n if (isEnvField) {\n if (key.leftArrow) {\n setPhase({\n ...phase,\n envCursor: (envCursor - 1 + ENVIRONMENTS.length) % ENVIRONMENTS.length,\n });\n } else if (key.rightArrow) {\n setPhase({ ...phase, envCursor: (envCursor + 1) % ENVIRONMENTS.length });\n } else if (key.upArrow) {\n setPhase({ ...phase, field: field - 1 });\n\n setInputBuffer(values[FIELDS[field - 1] as keyof typeof values] ?? '');\n } else if (key.return) {\n void handleSave(values, envCursor);\n }\n\n return;\n }\n\n const fieldName = FIELDS[field];\n\n if (!fieldName) {\n return;\n }\n\n if (key.backspace || key.delete) {\n setInputBuffer((prev) => prev.slice(0, -1));\n } else if (key.upArrow && field > 0) {\n const updatedValues = { ...values, [fieldName]: inputBuffer };\n const prevField = field - 1;\n\n setPhase({ ...phase, field: prevField, values: updatedValues });\n\n setInputBuffer(updatedValues[FIELDS[prevField] as keyof typeof updatedValues] ?? '');\n } else if (key.return || key.tab || key.downArrow) {\n const updatedValues = { ...values, [fieldName]: inputBuffer };\n const nextField = field + 1;\n\n setPhase({ ...phase, field: nextField, values: updatedValues });\n\n if (nextField < FIELDS.length) {\n setInputBuffer(updatedValues[FIELDS[nextField] as keyof typeof updatedValues] ?? '');\n } else {\n setInputBuffer('');\n }\n } else if (input && !key.ctrl && !key.meta) {\n setInputBuffer((prev) => prev + input);\n }\n }\n });\n\n const loadProfileList = useCallback(async () => {\n const profiles = await listCredentialProfiles();\n\n setPhase({ type: 'profile-select', profiles, cursor: 0 });\n }, []);\n\n // Load profile list when entering profile-loading phase\n useEffect(() => {\n if (phase.type === 'profile-loading') {\n void loadProfileList();\n }\n }, [phase.type, loadProfileList]);\n\n // Handle initial mode without profile manager (existing behavior)\n useEffect(() => {\n if (initialMode === 'global' && !showProfileManager) {\n void (async () => {\n const existing = await loadGlobalCredentials();\n const envCursor = existing ? Math.max(0, ENVIRONMENTS.indexOf(existing.environment)) : 0;\n\n setPhase({ type: 'creds-entry', field: 0, values: existing ?? {}, envCursor });\n })();\n }\n }, []); // eslint-disable-line react-hooks/exhaustive-deps\n\n // Reset input buffer when switching to creds-entry\n useEffect(() => {\n if (phase.type === 'creds-entry' && phase.field === 0) {\n setInputBuffer(phase.values.apiKey ?? '');\n }\n }, [phase.type]); // eslint-disable-line react-hooks/exhaustive-deps\n\n if (phase.type === 'loading' || phase.type === 'saving' || phase.type === 'profile-loading') {\n const label =\n phase.type === 'saving'\n ? 'Saving credentials…'\n : phase.type === 'profile-loading'\n ? 'Loading profiles…'\n : 'Loading credentials…';\n\n return (\n <Box paddingY={1} paddingX={2}>\n <Text dimColor>{label}</Text>\n </Box>\n );\n }\n\n if (phase.type === 'done') {\n return null;\n }\n\n if (phase.type === 'mode-select') {\n const options: { label: string; desc: string; mode: Mode }[] = [\n { label: 'Global', desc: `~/.kizenappbuilder/credentials.json`, mode: 'global' },\n { label: 'Local', desc: 'Enter credentials in the browser dev tools', mode: 'local' },\n ];\n\n return (\n <Box flexDirection=\"column\" paddingY={1} paddingX={2} gap={1}>\n <AppHeader />\n <Box flexDirection=\"column\" gap={0}>\n <Text bold>Credential mode</Text>\n {options.map((opt, i) => {\n const selected = phase.cursor === i;\n\n return (\n <Box key={opt.mode} gap={2}>\n <Text {...(selected && { color: 'cyan' as const })}>{selected ? '❯' : ' '}</Text>\n <Text bold={selected} {...(selected && { color: 'cyan' as const })}>\n {opt.label}\n </Text>\n <Text dimColor>{opt.desc}</Text>\n </Box>\n );\n })}\n </Box>\n <Hint text=\"↑↓ to move · Enter to select · Ctrl+C to quit\" />\n </Box>\n );\n }\n\n if (phase.type === 'profile-select') {\n const { profiles, cursor } = phase;\n const addNewIdx = profiles.length;\n\n return (\n <Box flexDirection=\"column\" paddingY={1} paddingX={2} gap={1}>\n <AppHeader />\n <Box flexDirection=\"column\" gap={0}>\n <Text bold>Credential profiles</Text>\n {profiles.map((profile, i) => {\n const selected = cursor === i;\n\n return (\n <Box key={profile.name} gap={2}>\n <Text {...(selected && { color: 'cyan' as const })}>{selected ? '❯' : ' '}</Text>\n <Text bold={selected} {...(selected && { color: 'cyan' as const })}>\n {profile.isDefault ? 'Default' : profile.name}\n </Text>\n <Text dimColor>{profile.path}</Text>\n </Box>\n );\n })}\n <Box gap={2}>\n <Text {...(cursor === addNewIdx && { color: 'cyan' as const })}>\n {cursor === addNewIdx ? '❯' : ' '}\n </Text>\n <Text\n bold={cursor === addNewIdx}\n {...(cursor === addNewIdx && { color: 'cyan' as const })}\n >\n + Add new profile\n </Text>\n </Box>\n </Box>\n <Hint text=\"↑↓ to move · Enter to select · Esc to cancel\" />\n </Box>\n );\n }\n\n if (phase.type === 'name-entry') {\n const { nameBuffer, nameError } = phase;\n\n return (\n <Box flexDirection=\"column\" paddingY={1} paddingX={2} gap={1}>\n <AppHeader />\n <Box flexDirection=\"column\" gap={0}>\n <Text bold>New credential profile</Text>\n </Box>\n {nameError && <Text color=\"red\">Error: {nameError}</Text>}\n <Box gap={2}>\n <Box width={12}>\n <Text bold color=\"cyan\">\n Profile name\n </Text>\n </Box>\n <Text color=\"cyan\">{'>'}</Text>\n <Text>{nameBuffer}</Text>\n <Text color=\"cyan\">{'█'}</Text>\n </Box>\n <Hint text=\"Type a name · Enter to confirm · Esc to go back\" />\n </Box>\n );\n }\n\n // creds-entry phase\n const { field: activeField, values, envCursor } = phase;\n const isEnvField = activeField === FIELDS.length;\n const profileLabel = activeProfileName ?? DEFAULT_PROFILE_NAME;\n\n return (\n <Box flexDirection=\"column\" paddingY={1} paddingX={2} gap={1}>\n <AppHeader />\n <Box flexDirection=\"column\" gap={0}>\n <Text bold>\n {activeProfileName !== undefined ? `Profile: ${activeProfileName}` : 'Global credentials'}\n </Text>\n <Text dimColor>\n Saved to:{' '}\n {activeProfileName !== undefined\n ? `~/.kizenappbuilder/${activeProfileName}.json`\n : GLOBAL_CREDENTIALS_PATH}\n </Text>\n </Box>\n {error && <Text color=\"red\">Error: {error}</Text>}\n <Box flexDirection=\"column\" gap={0}>\n {FIELDS.map((name, i) => {\n const isActive = activeField === i;\n const displayValue = isActive ? inputBuffer : (values[name] ?? '');\n\n return (\n <Box key={name} gap={2}>\n <Box width={12}>\n <Text bold={isActive} {...(isActive && { color: 'cyan' as const })}>\n {FIELD_LABELS[name]}\n </Text>\n </Box>\n <Text {...(isActive && { color: 'cyan' as const })}>{'>'}</Text>\n <Text>{displayValue}</Text>\n {isActive && <Text color=\"cyan\">{'█'}</Text>}\n </Box>\n );\n })}\n <Box gap={2}>\n <Box width={12}>\n <Text bold={isEnvField} {...(isEnvField && { color: 'cyan' as const })}>\n Environment\n </Text>\n </Box>\n <Text {...(isEnvField && { color: 'cyan' as const })}>{'>'}</Text>\n <Box gap={1}>\n {ENVIRONMENTS.map((env, i) => {\n const isSelected = i === envCursor;\n\n if (isEnvField) {\n return (\n <Text key={env} bold={isSelected} {...(isSelected && { color: 'cyan' as const })}>\n {isSelected ? `[${env}]` : env}\n </Text>\n );\n }\n\n return (\n <Text key={env} dimColor={!isSelected} bold={isSelected}>\n {env}\n </Text>\n );\n })}\n </Box>\n </Box>\n </Box>\n {isEnvField ? (\n <Hint text=\"←→ to select · ↑↓ to move · Enter to save · Esc to cancel\" />\n ) : (\n <Hint text=\"↑↓ to move · Backspace to delete · Esc to cancel\" />\n )}\n <Text dimColor>Profile: {profileLabel}</Text>\n </Box>\n );\n};\n","import { createElement } from 'react';\nimport { render } from 'ink';\nimport type { Command } from 'commander';\nimport { EncryptUI } from '../ui/EncryptUI.js';\nimport { encryptSecret } from '../lib/encryptionClient.js';\nimport type { EncryptionContext } from '../lib/encryptionClient.js';\nimport { loadCredentialsFromFile, loadGlobalCredentials } from '../lib/credentials.js';\nimport {\n invalidStageMessage,\n isValidStage,\n readManifestDefaults,\n readStdin,\n resolveStage,\n writeEnvelopeFile,\n type ManifestDefaults,\n} from '../lib/encryptHelpers.js';\nimport { runHeadless } from '../lib/encryptHeadless.js';\n\ninterface EncryptOptions {\n remote?: boolean;\n credentials?: string;\n apiName?: string;\n value?: string;\n stage?: string;\n out?: string;\n}\n\nexport function encryptCommand(program: Command): void {\n program\n .command('encrypt')\n .description('Encrypt a secret for a plugin against its encryption keys')\n .option('--remote', \"encrypt via the plugin-wizard's remote API instead of on-machine\")\n .option('-c, --credentials <path>', 'path to a credentials JSON file')\n .option('-a, --api-name <name>', 'plugin api_name the secret belongs to')\n .option('-v, --value <value>', 'plaintext secret value to encrypt')\n .option('-s, --stage <stage>', 'which encryption API to use: dev or prod (default: prod)')\n .option('-o, --out <path>', 'also write the encrypted envelope to a file')\n .action(async (options: EncryptOptions) => {\n if (options.stage !== undefined && !isValidStage(options.stage)) {\n console.error(invalidStageMessage(options.stage));\n process.exit(1);\n }\n\n // Read kizen.json for the api_name default. Skip the file read entirely\n // when api_name is already supplied via a flag.\n const needsDefaults = options.apiName === undefined;\n const defaults: ManifestDefaults = needsDefaults ? await readManifestDefaults() : {};\n\n // Default to prod when --stage isn't given (almost every plugin ships to\n // production); pass --stage dev to override.\n const { stage, wasDefaulted: stageWasDefaulted } = resolveStage(options.stage);\n\n const ctx: EncryptionContext = {\n isRemote: options.remote === true,\n stage,\n };\n\n // ink's interactive UI needs a TTY for raw-mode input AND a TTY stdout to\n // render into. If either is redirected/piped (CI, `> out.json`, `| jq`),\n // fall back to the headless flow so stdout gets clean compact JSON instead\n // of ANSI frames.\n if (!process.stdin.isTTY || !process.stdout.isTTY) {\n try {\n await runHeadless(ctx, options, defaults, stageWasDefaulted, {\n loadCredentialsFromFile,\n loadGlobalCredentials,\n encryptSecret,\n readStdin,\n stdinIsTTY: () => process.stdin.isTTY,\n writeStdout: (text) => {\n process.stdout.write(text);\n },\n writeStderr: (text) => {\n process.stderr.write(text);\n },\n writeEnvelopeFile,\n setExitCode: (code) => {\n process.exitCode = code;\n },\n });\n } catch (err) {\n console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);\n process.exit(1);\n }\n\n return;\n }\n\n // The UI copies to the clipboard itself; we capture the raw value here so\n // that after ink unmounts we can write --out (ink's rendered frame\n // soft-wraps the long base64, so we never read the envelope back off it).\n let envelopeValue: string | undefined;\n\n const { waitUntilExit } = render(\n createElement(EncryptUI, {\n ctx,\n stageDefaulted: stageWasDefaulted,\n onDone: (value: string) => {\n envelopeValue = value;\n },\n ...(options.credentials !== undefined && { credentialsPath: options.credentials }),\n ...(options.apiName !== undefined && { initialApiName: options.apiName }),\n ...(defaults.apiName !== undefined && { defaultApiName: defaults.apiName }),\n ...(options.value !== undefined && { initialValue: options.value }),\n }),\n { exitOnCtrlC: false },\n );\n\n await waitUntilExit();\n\n // envelopeValue is only set on success (onDone); stays undefined on Ctrl+C\n // or error, so nothing is written in those cases.\n if (envelopeValue !== undefined && options.out !== undefined) {\n try {\n await writeEnvelopeFile(options.out, envelopeValue);\n process.stderr.write(`Wrote encrypted envelope to ${options.out}\\n`);\n } catch (err) {\n console.error(\n `Error writing ${options.out}: ${err instanceof Error ? err.message : String(err)}`,\n );\n process.exitCode = 1;\n }\n }\n });\n}\n","import type { FC, ReactNode } from 'react';\nimport { useCallback, useEffect, useState } from 'react';\nimport { Box, Text, useApp, useInput } from 'ink';\nimport {\n listCredentialProfiles,\n loadCredentialProfile,\n loadCredentialsFromFile,\n loadGlobalCredentials,\n} from '../lib/credentials.js';\nimport type { CredentialProfile, Credentials } from '../lib/credentials.js';\nimport { encryptSecret } from '../lib/encryptionClient.js';\nimport type { EncryptionContext } from '../lib/encryptionClient.js';\nimport { copyToClipboard } from '../lib/clipboard.js';\nimport { AppHeader } from './AppHeader.js';\nimport { Spinner } from './Spinner.js';\n\ninterface EncryptUIProps {\n ctx: EncryptionContext;\n /** True when --stage was not given and the stage fell back to the prod default. */\n stageDefaulted?: boolean;\n /** Skip the profile picker and load from this file instead. */\n credentialsPath?: string;\n /** Provided via --api-name; skips the api_name prompt. */\n initialApiName?: string;\n /** Prefill for the api_name prompt (from kizen.json) — does not skip it. */\n defaultApiName?: string;\n /** Provided via --value; skips the secret prompt. */\n initialValue?: string;\n /** Called once with the base64 envelope value when encryption succeeds, so the\n * caller can write --out / emit it after ink unmounts. */\n onDone?: (envelopeValue: string) => void;\n}\n\ntype Phase =\n | { type: 'loading' }\n | { type: 'profile-select'; profiles: CredentialProfile[]; cursor: number }\n | { type: 'api-name-entry'; buffer: string; error?: string }\n | { type: 'value-entry'; buffer: string; error?: string }\n | { type: 'fetching-key' }\n | { type: 'encrypting' }\n | { type: 'done'; envelope: string; copied: boolean }\n | { type: 'error'; message: string };\n\nconst Hint: FC<{ text: string }> = ({ text }) => <Text dimColor>{text}</Text>;\n\nexport const EncryptUI: FC<EncryptUIProps> = ({\n ctx,\n stageDefaulted,\n credentialsPath,\n initialApiName,\n defaultApiName,\n initialValue,\n onDone,\n}) => {\n const app = useApp();\n const [phase, setPhase] = useState<Phase>({ type: 'loading' });\n const [credentials, setCredentials] = useState<Credentials | null>(null);\n const [apiName, setApiName] = useState<string>(initialApiName ?? '');\n const [secret, setSecret] = useState<string>(initialValue ?? '');\n\n const fail = useCallback((err: unknown) => {\n process.exitCode = 1;\n // Exit is deferred to the terminal-phase effect below so the error frame is\n // actually painted before ink unmounts.\n setPhase({ type: 'error', message: err instanceof Error ? err.message : String(err) });\n }, []);\n\n const runEncryption = useCallback(\n async (creds: Credentials, name: string, value: string) => {\n try {\n const envelopeValue = await encryptSecret(ctx, creds, name, value, (p) => {\n setPhase(p === 'fetching-key' ? { type: 'fetching-key' } : { type: 'encrypting' });\n });\n const envelope = JSON.stringify({ encrypted: true, value: envelopeValue }, null, 2);\n\n onDone?.(envelopeValue);\n\n // Copy the envelope to the clipboard so the user can paste it without the\n // terminal's soft-wrapping becoming real line breaks in the copied text.\n // The envelope is ciphertext (never the plaintext secret), so this is\n // safe; the copy is best-effort and the envelope is shown either way.\n const copied = await copyToClipboard(envelope);\n\n // Exit is deferred to the terminal-phase effect below so the done frame\n // (with the envelope) is painted before ink unmounts.\n setPhase({ type: 'done', envelope, copied });\n } catch (err) {\n fail(err);\n }\n },\n [ctx, fail, onDone],\n );\n\n // Advance to the next required input, or kick off the encryption once we have\n // everything. Args are passed explicitly so we never read stale state.\n const proceed = useCallback(\n (creds: Credentials, name: string, value: string) => {\n if (name.trim() === '') {\n setPhase({ type: 'api-name-entry', buffer: defaultApiName ?? '' });\n\n return;\n }\n\n if (value === '') {\n setPhase({ type: 'value-entry', buffer: '' });\n\n return;\n }\n\n void runEncryption(creds, name.trim(), value);\n },\n [defaultApiName, runEncryption],\n );\n\n const handleProfileChosen = useCallback(\n async (profile: CredentialProfile) => {\n try {\n setPhase({ type: 'loading' });\n\n const creds = profile.isDefault\n ? await loadGlobalCredentials()\n : await loadCredentialProfile(profile.name);\n\n if (creds === null) {\n throw new Error(`Could not load credential profile: ${profile.name}`);\n }\n\n setCredentials(creds);\n proceed(creds, apiName, secret);\n } catch (err) {\n fail(err);\n }\n },\n [apiName, secret, proceed, fail],\n );\n\n // Resolve credentials on mount, then either show the picker or move on.\n useEffect(() => {\n void (async () => {\n try {\n if (credentialsPath !== undefined) {\n // loadCredentialsFromFile throws on a missing/invalid file; wrap it so\n // the error frame shows which path failed rather than a raw ENOENT.\n let creds: Credentials;\n\n try {\n creds = await loadCredentialsFromFile(credentialsPath);\n } catch (err) {\n throw new Error(\n `Could not load credentials from ${credentialsPath}: ${\n err instanceof Error ? err.message : String(err)\n }`,\n );\n }\n\n setCredentials(creds);\n proceed(creds, apiName, secret);\n\n return;\n }\n\n const profiles = await listCredentialProfiles();\n\n if (profiles.length === 0) {\n throw new Error(\n 'No credential profiles found. Create ~/.kizenappbuilder/credentials.json first.',\n );\n }\n\n const [only] = profiles;\n\n if (profiles.length === 1 && only !== undefined) {\n const creds = only.isDefault\n ? await loadGlobalCredentials()\n : await loadCredentialProfile(only.name);\n\n if (creds === null) {\n throw new Error(`Could not load credential profile: ${only.name}`);\n }\n\n setCredentials(creds);\n proceed(creds, apiName, secret);\n\n return;\n }\n\n setPhase({ type: 'profile-select', profiles, cursor: 0 });\n } catch (err) {\n fail(err);\n }\n })();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n // Exit only once a terminal frame has been committed and written to the\n // terminal. Calling app.exit() in the same tick as the setPhase would unmount\n // ink before it paints the done/error frame, leaving the spinner as the last\n // thing on screen.\n useEffect(() => {\n if (phase.type === 'done' || phase.type === 'error') {\n app.exit();\n }\n }, [phase, app]);\n\n useInput((input, key) => {\n if (key.ctrl && input === 'c') {\n process.exitCode = 130;\n app.exit();\n\n return;\n }\n\n if (phase.type === 'profile-select') {\n const { profiles, cursor } = phase;\n\n if (key.upArrow) {\n setPhase({ ...phase, cursor: (cursor - 1 + profiles.length) % profiles.length });\n } else if (key.downArrow) {\n setPhase({ ...phase, cursor: (cursor + 1) % profiles.length });\n } else if (key.return) {\n // cursor is kept in range by the modulo above, so this is always defined.\n const selected = profiles[cursor];\n\n if (selected !== undefined) {\n void handleProfileChosen(selected);\n }\n }\n\n return;\n }\n\n if (phase.type === 'api-name-entry') {\n const { buffer } = phase;\n\n if (key.backspace || key.delete) {\n setPhase({ type: 'api-name-entry', buffer: buffer.slice(0, -1) });\n } else if (key.return) {\n const name = buffer.trim();\n\n if (name === '') {\n setPhase({ type: 'api-name-entry', buffer, error: 'api_name cannot be empty' });\n\n return;\n }\n\n setApiName(name);\n\n if (credentials) {\n proceed(credentials, name, secret);\n } else {\n fail(new Error('Internal error: credentials were not loaded'));\n }\n } else if (input && !key.ctrl && !key.meta) {\n setPhase({ type: 'api-name-entry', buffer: buffer + input });\n }\n\n return;\n }\n\n if (phase.type === 'value-entry') {\n const { buffer } = phase;\n\n if (key.backspace || key.delete) {\n setPhase({ type: 'value-entry', buffer: buffer.slice(0, -1) });\n } else if (key.return) {\n if (buffer === '') {\n setPhase({ type: 'value-entry', buffer, error: 'secret cannot be empty' });\n\n return;\n }\n\n setSecret(buffer);\n\n if (credentials) {\n proceed(credentials, apiName, buffer);\n } else {\n fail(new Error('Internal error: credentials were not loaded'));\n }\n } else if (input && !key.ctrl && !key.meta) {\n setPhase({ type: 'value-entry', buffer: buffer + input });\n }\n\n return;\n }\n });\n\n const modeLabel = ctx.isRemote ? 'remote Kizen API' : 'on-machine';\n\n const stageLabel = stageDefaulted === true ? `${ctx.stage} (default)` : ctx.stage;\n\n const frame = (children: ReactNode): ReactNode => (\n <Box flexDirection=\"column\" paddingY={1} paddingX={2} gap={1}>\n <AppHeader />\n <Text dimColor>\n Mode: {modeLabel} Stage: {stageLabel}\n </Text>\n {children}\n </Box>\n );\n\n if (phase.type === 'loading') {\n return frame(\n <Box gap={1}>\n <Spinner />\n <Text dimColor>Loading credentials…</Text>\n </Box>,\n );\n }\n\n if (phase.type === 'profile-select') {\n const { profiles, cursor } = phase;\n\n return frame(\n <>\n <Text bold>Credential profile</Text>\n <Box flexDirection=\"column\">\n {profiles.map((profile, i) => {\n const selected = cursor === i;\n\n return (\n <Box key={profile.name} gap={2}>\n <Text {...(selected && { color: 'cyan' as const })}>{selected ? '❯' : ' '}</Text>\n <Text bold={selected} {...(selected && { color: 'cyan' as const })}>\n {profile.isDefault ? 'Default' : profile.name}\n </Text>\n <Text dimColor>{profile.path}</Text>\n </Box>\n );\n })}\n </Box>\n <Hint text=\"↑↓ to move · Enter to select · Ctrl+C to quit\" />\n </>,\n );\n }\n\n if (phase.type === 'api-name-entry') {\n return frame(\n <>\n <Text bold>Plugin api_name</Text>\n {phase.error !== undefined && <Text color=\"red\">Error: {phase.error}</Text>}\n <Box gap={1}>\n <Text color=\"cyan\">{'>'}</Text>\n <Text>{phase.buffer}</Text>\n <Text color=\"cyan\">█</Text>\n </Box>\n <Hint text=\"Type the api_name · Enter to confirm · Ctrl+C to quit\" />\n </>,\n );\n }\n\n if (phase.type === 'value-entry') {\n return frame(\n <>\n <Text bold>Secret value</Text>\n {phase.error !== undefined && <Text color=\"red\">Error: {phase.error}</Text>}\n <Box gap={1}>\n <Text color=\"cyan\">{'>'}</Text>\n <Text>{'•'.repeat(phase.buffer.length)}</Text>\n <Text color=\"cyan\">█</Text>\n </Box>\n <Hint text=\"Input hidden · Enter to encrypt · Ctrl+C to quit\" />\n </>,\n );\n }\n\n if (phase.type === 'fetching-key') {\n return frame(\n <Box gap={1}>\n <Spinner />\n <Text>\n Fetching {ctx.stage} public key for <Text bold>{apiName}</Text>…\n </Text>\n </Box>,\n );\n }\n\n if (phase.type === 'encrypting') {\n return frame(\n <Box gap={1}>\n <Spinner />\n <Text>Encrypting…</Text>\n </Box>,\n );\n }\n\n if (phase.type === 'error') {\n return frame(\n <Box gap={1}>\n <Text color=\"red\">✗</Text>\n <Text color=\"red\">{phase.message}</Text>\n </Box>,\n );\n }\n\n // phase.type === 'done'\n return frame(\n <>\n <Box gap={1}>\n <Text color=\"green\">✓</Text>\n <Text bold>Encrypted secret ready</Text>\n </Box>\n {phase.copied ? (\n <Text color=\"green\">\n ✓ Copied to clipboard — paste it into the secret value in your kizen.json.\n </Text>\n ) : (\n <Text dimColor>\n {'Paste this into the secret value in your kizen.json (re-run with --out <path> to save ' +\n 'it to a file; selecting it here may capture line wraps):'}\n </Text>\n )}\n <Text>{phase.envelope}</Text>\n </>,\n );\n};\n","/**\n * Network + crypto helpers for the `encrypt` command, shared between the ink UI\n * and any non-interactive callers. Keeping these out of the React tree means the\n * dev/prod routing and envelope handling live in one testable place. KZN-16467.\n *\n * Both modes talk to the encryption API (plugin-wizard) DIRECTLY via\n * `resolveWizardBase(stage)` — the app-builder dev server is never involved, so\n * `appbuilder encrypt` works without `appbuilder dev` running:\n * - on-machine (default): fetch the public key, then encrypt in-process.\n * - remote (`--remote`): POST the plaintext to the wizard's /encrypt endpoint\n * and let it do the crypto with the keypair it already holds.\n */\nimport { encrypt, serializeEnvelope } from '@kizenapps/packager';\nimport type { Credentials } from './credentials.js';\nimport { getProxyEnvStatus, PROXY_UNAVAILABLE_HINT } from './proxyEnv.js';\nimport { resolveWizardBase } from './wizardUrl.js';\n\nexport interface EncryptionContext {\n /**\n * When true, the wizard's /encrypt endpoint performs the encryption; otherwise\n * we fetch the public key and encrypt on-machine. Either way the request goes\n * straight to the wizard host — never through the app-builder dev server.\n */\n isRemote: boolean;\n /** Which encryption API to target. */\n stage: 'dev' | 'prod';\n}\n\n/** Phases reported while encrypting, so a UI can show progress. */\nexport type EncryptPhase = 'fetching-key' | 'encrypting';\n\n/**\n * Node's fetch (undici) wraps socket failures in a generic `TypeError: fetch\n * failed`, stashing the real error (with its `code`) on `.cause`. Look in both\n * places so we can surface a friendlier \"not running\" message.\n */\nfunction isConnRefused(err: unknown): boolean {\n const e = err as { code?: string; cause?: { code?: string } };\n\n return e.code === 'ECONNREFUSED' || e.cause?.code === 'ECONNREFUSED';\n}\n\nfunction authHeaders(credentials: Credentials): Record<string, string> {\n return {\n 'Content-Type': 'application/json',\n 'x-api-key': credentials.apiKey,\n 'x-user-id': credentials.userId,\n 'x-business-id': credentials.businessId,\n 'x-auth-environment': credentials.environment,\n };\n}\n\n/** Wraps a fetch to the wizard so connection failures read clearly. */\nasync function wizardFetch(wizardBase: string, path: string, init: RequestInit): Promise<Response> {\n try {\n return await fetch(`${wizardBase}${path}`, init);\n } catch (err) {\n throw new Error(\n isConnRefused(err)\n ? `Plugin-wizard is not running at ${wizardBase}`\n : `Failed to reach plugin-wizard: ${(err as Error).message}${getProxyEnvStatus() === 'unavailable' ? ` ${PROXY_UNAVAILABLE_HINT}` : ''}`,\n );\n }\n}\n\n/**\n * Parses a wizard JSON response without throwing on a non-JSON body. Upstream\n * errors can arrive as HTML 502 pages, plain-text 429s, or an auth 401 raised\n * before the JSON handler runs — calling res.json() on those would throw an\n * opaque SyntaxError and hide the real status. Returning {} lets callers fall\n * back to a clear HTTP-status error.\n */\nasync function readJsonSafe(res: Response): Promise<Record<string, unknown>> {\n const text = await res.text();\n\n if (text === '') {\n return {};\n }\n\n try {\n const parsed = JSON.parse(text) as unknown;\n\n return typeof parsed === 'object' && parsed !== null ? (parsed as Record<string, unknown>) : {};\n } catch {\n return {};\n }\n}\n\n/**\n * Fetches the public key for a plugin directly from the wizard host. Used by the\n * on-machine encryption path.\n */\nexport async function fetchPublicKey(\n ctx: EncryptionContext,\n credentials: Credentials,\n apiName: string,\n): Promise<string> {\n const wizardBase = resolveWizardBase(ctx.stage);\n const res = await wizardFetch(wizardBase, '/get-public-key', {\n method: 'POST',\n headers: authHeaders(credentials),\n body: JSON.stringify({ api_name: apiName }),\n });\n\n const data = await readJsonSafe(res);\n\n if (!res.ok || typeof data.public_key !== 'string') {\n const errMsg = typeof data.error === 'string' ? data.error : `HTTP ${String(res.status)}`;\n\n throw new Error(`Failed to fetch public key: ${errMsg}`);\n }\n\n return data.public_key;\n}\n\n/** Encrypts a value in-process via @kizenapps/packager and returns the\n * serialized envelope's base64 `value`. */\nfunction encryptLocally(publicKeyPem: string, value: string): string {\n const envelope = encrypt(value, publicKeyPem);\n const serialized = serializeEnvelope(envelope) as { encrypted?: boolean; value?: unknown };\n\n if (typeof serialized.value !== 'string') {\n throw new Error('Unexpected serialized envelope shape from @kizenapps/packager');\n }\n\n return serialized.value;\n}\n\n/**\n * Asks the wizard's /encrypt endpoint to encrypt the value with the keypair it\n * holds for `apiName`, returning the serialized envelope's base64 `value`. The\n * wizard fetches its own public key, so no separate get-public-key call is made.\n */\nasync function encryptRemote(\n ctx: EncryptionContext,\n credentials: Credentials,\n apiName: string,\n value: string,\n): Promise<string> {\n const wizardBase = resolveWizardBase(ctx.stage);\n const res = await wizardFetch(wizardBase, '/encrypt', {\n method: 'POST',\n headers: authHeaders(credentials),\n body: JSON.stringify({ api_name: apiName, value }),\n });\n\n const data = await readJsonSafe(res);\n\n if (!res.ok || data.encrypted !== true || typeof data.value !== 'string') {\n const errMsg = typeof data.error === 'string' ? data.error : `HTTP ${String(res.status)}`;\n\n throw new Error(`Encryption via plugin-wizard failed: ${errMsg}`);\n }\n\n return data.value;\n}\n\nexport async function encryptSecret(\n ctx: EncryptionContext,\n credentials: Credentials,\n apiName: string,\n value: string,\n onPhase?: (phase: EncryptPhase) => void,\n): Promise<string> {\n if (ctx.isRemote) {\n onPhase?.('encrypting');\n\n return encryptRemote(ctx, credentials, apiName, value);\n }\n\n onPhase?.('fetching-key');\n\n const publicKey = await fetchPublicKey(ctx, credentials, apiName);\n\n onPhase?.('encrypting');\n\n return encryptLocally(publicKey, value);\n}\n","import { readFile, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nexport type EncryptStage = 'dev' | 'prod';\n\nexport function envelopeObject(value: string): { encrypted: true; value: string } {\n return { encrypted: true, value };\n}\n\nexport function compactEnvelope(value: string): string {\n return JSON.stringify(envelopeObject(value));\n}\n\nexport async function writeEnvelopeFile(path: string, value: string): Promise<void> {\n await writeFile(path, `${JSON.stringify(envelopeObject(value), null, 2)}\\n`, 'utf-8');\n}\n\nexport interface ManifestDefaults {\n apiName?: string;\n}\n\nexport const DEFAULT_STAGE: EncryptStage = 'prod';\n\nexport function isValidStage(stage: string): stage is EncryptStage {\n return stage === 'dev' || stage === 'prod';\n}\n\nexport function invalidStageMessage(stage: string): string {\n return `Error: --stage must be \"dev\" or \"prod\" (got: \"${stage}\")`;\n}\n\nexport function resolveStage(stage: string | undefined): {\n stage: EncryptStage;\n wasDefaulted: boolean;\n} {\n return {\n stage: stage === 'dev' || stage === 'prod' ? stage : DEFAULT_STAGE,\n wasDefaulted: stage === undefined,\n };\n}\n\nexport function defaultStageNotice(stage: EncryptStage): string {\n return `No --stage given; defaulting to ${stage} encryption keys (pass --stage dev to override)\\n`;\n}\n\nexport async function readManifestDefaults(cwd: string = process.cwd()): Promise<ManifestDefaults> {\n try {\n const raw = await readFile(join(cwd, 'kizen.json'), 'utf-8');\n const parsed = JSON.parse(raw) as unknown;\n const manifest = (Array.isArray(parsed) ? parsed[0] : parsed) as Record<string, unknown>;\n\n const apiName =\n typeof manifest.api_name === 'string' && manifest.api_name !== ''\n ? manifest.api_name\n : undefined;\n\n return {\n ...(apiName !== undefined && { apiName }),\n };\n } catch {\n // Not in a plugin directory — fine, the UI will prompt with no defaults.\n }\n\n return {};\n}\n\nexport function stripTrailingNewlines(value: string): string {\n return value.replace(/[\\r\\n]+$/, '');\n}\n\nexport async function readStdin(): Promise<string> {\n const chunks: Buffer[] = [];\n\n for await (const chunk of process.stdin) {\n chunks.push(chunk as Buffer);\n }\n\n return Buffer.concat(chunks).toString('utf-8');\n}\n","import type { EncryptionContext } from './encryptionClient.js';\nimport type { Credentials } from './credentials.js';\nimport type { ManifestDefaults } from './encryptHelpers.js';\nimport { compactEnvelope, defaultStageNotice, stripTrailingNewlines } from './encryptHelpers.js';\n\nexport interface HeadlessEncryptOptions {\n credentials?: string;\n apiName?: string;\n value?: string;\n out?: string;\n}\n\nexport interface HeadlessEncryptDeps {\n loadCredentialsFromFile: (path: string) => Promise<Credentials>;\n loadGlobalCredentials: () => Promise<Credentials | null>;\n encryptSecret: (\n ctx: EncryptionContext,\n credentials: Credentials,\n apiName: string,\n value: string,\n ) => Promise<string>;\n readStdin: () => Promise<string>;\n stdinIsTTY: () => boolean;\n writeStdout: (text: string) => void;\n writeStderr: (text: string) => void;\n writeEnvelopeFile: (path: string, value: string) => Promise<void>;\n setExitCode: (code: number) => void;\n}\n\nexport async function runHeadless(\n ctx: EncryptionContext,\n options: HeadlessEncryptOptions,\n defaults: ManifestDefaults,\n stageWasDefaulted: boolean,\n deps: HeadlessEncryptDeps,\n): Promise<void> {\n const credentials =\n options.credentials !== undefined\n ? await deps.loadCredentialsFromFile(options.credentials)\n : await deps.loadGlobalCredentials();\n\n if (credentials === null) {\n throw new Error(\n 'No credentials found. Pass --credentials or create ~/.kizenappbuilder/credentials.json.',\n );\n }\n\n const apiName = options.apiName ?? defaults.apiName;\n\n if (apiName === undefined || apiName.trim() === '') {\n throw new Error(\n 'api_name is required in non-interactive mode. Pass --api-name or run inside a plugin directory.',\n );\n }\n\n if (stageWasDefaulted) {\n deps.writeStderr(defaultStageNotice(ctx.stage));\n }\n\n let value = options.value;\n\n if (value === undefined) {\n if (deps.stdinIsTTY()) {\n throw new Error(\n 'No secret provided and stdin is a terminal. Pass --value, or pipe the secret in ' +\n '(e.g. `printf %s \"$SECRET\" | npx --yes @kizenapps/cli encrypt …`).',\n );\n }\n\n deps.writeStderr('Reading secret from stdin (pass --value to skip)…\\n');\n\n value = stripTrailingNewlines(await deps.readStdin());\n }\n\n if (value === '') {\n throw new Error('A secret value is required. Pass --value or pipe it via stdin.');\n }\n\n const envelopeValue = await deps.encryptSecret(ctx, credentials, apiName.trim(), value);\n\n deps.writeStdout(`${compactEnvelope(envelopeValue)}\\n`);\n\n if (options.out !== undefined) {\n try {\n await deps.writeEnvelopeFile(options.out, envelopeValue);\n deps.writeStderr(`Wrote encrypted envelope to ${options.out}\\n`);\n } catch (err) {\n deps.writeStderr(\n `Error writing ${options.out}: ${err instanceof Error ? err.message : String(err)}\\n`,\n );\n deps.setExitCode(1);\n }\n }\n}\n","export const VALID_ICONS = new Set([\n 'phone',\n 'envelope',\n 'pen-nib',\n 'calendar-days',\n 'paperclip',\n 'file',\n 'clipboard',\n 'pen',\n 'tag',\n 'book',\n 'print',\n 'pen-to-square',\n 'folder',\n 'folder-open',\n 'thumbtack',\n 'globe',\n 'city',\n 'briefcase',\n 'compass',\n 'address-book',\n 'business-time',\n 'computer-classic',\n 'pen-fancy',\n 'badge-check',\n 'mug-saucer',\n 'landmark',\n 'chart-simple',\n 'envelopes',\n 'diagram-venn',\n 'calendar',\n 'pencil',\n 'phone-volume',\n 'copy',\n 'table',\n 'building',\n 'network-wired',\n 'address-card',\n 'tags',\n 'registered',\n 'signature',\n 'phone-office',\n 'projector',\n 'sitemap',\n 'marker',\n 'badge',\n 'wallet',\n 'copyright',\n 'bullseye',\n 'calculator',\n 'certificate',\n 'percent',\n 'eraser',\n 'file-spreadsheet',\n 'glasses',\n 'industry',\n 'vault',\n 'user-tie-hair-long',\n 'user-tie-hair',\n 'user-hair-mullet',\n 'trademark',\n 'timeline-arrow',\n 'timeline',\n 'table-tree',\n 'table-rows',\n 'table-pivot',\n 'table-layout',\n 'table-columns',\n 'stapler',\n 'square-poll-vertical',\n 'square-poll-horizontal',\n 'square-phone-flip',\n 'square-phone',\n 'square-pen',\n 'square-kanban',\n 'square-envelope',\n 'socks',\n 'slot-machine',\n 'signature-slash',\n 'signature-lock',\n 'shredder',\n 'scissors',\n 'scanner-image',\n 'scale-unbalanced-flip',\n 'scale-unbalanced',\n 'scale-balanced',\n 'router',\n 'rectangle-pro',\n 'print-slash',\n 'print-magnifying-glass',\n 'presentation-screen',\n 'podium',\n 'phone-slash',\n 'phone-intercom',\n 'phone-flip',\n 'person-chalkboard',\n 'pen-nib-slash',\n 'pen-clip',\n 'paste',\n 'paperclip-vertical',\n 'notebook',\n 'note-sticky',\n 'money-check-pen',\n 'money-check-dollar-pen',\n 'magnifying-glass-chart',\n 'magnifying-glass-arrow-right',\n 'list-tree',\n 'list-timeline',\n 'list-radio',\n 'list-dropdown',\n 'list-check',\n 'laptop-file',\n 'lamp-desk',\n 'keynote',\n 'industry-windows',\n 'inboxes',\n 'inbox-full',\n 'house-laptop',\n 'highlighter',\n 'folders',\n 'folder-xmark',\n 'folder-tree',\n 'folder-plus',\n 'folder-minus',\n 'folder-arrow-up',\n 'folder-arrow-down',\n 'floppy-disk-circle-xmark',\n 'floppy-disk-circle-arrow-right',\n 'floppy-disk',\n 'file-user',\n 'file-lines',\n 'file-circle-plus',\n 'file-circle-info',\n 'file-chart-pie',\n 'file-chart-column',\n 'fax',\n 'envelope-open',\n 'envelope-dot',\n 'envelope-circle-check',\n 'coffee-pot',\n 'cloud-word',\n 'clipboard-question',\n 'chart-user',\n 'chart-tree-map',\n 'chart-simple-horizontal',\n 'chart-pyramid',\n 'chart-pie-simple',\n 'chart-pie',\n 'chart-line-up',\n 'chart-line-down',\n 'chart-line',\n 'cake-candles',\n 'cabinet-filing',\n 'bullhorn',\n 'briefcase-blank',\n 'briefcase-arrow-right',\n 'brain-arrow-curved-right',\n 'boxes-packing',\n 'box-archive',\n 'book-section',\n 'bars-staggered',\n 'bars-progress',\n 'badge-percent',\n 'badge-dollar',\n 'arrows-to-eye',\n 'arrows-to-dot',\n 'arrows-spin',\n 'sparkles',\n 'megaphone',\n 'block-question',\n 'lightbulb-slash',\n 'comments-dollar',\n 'comments',\n 'bullseye-pointer',\n 'lightbulb',\n 'user-group-crown',\n 'user-crown',\n 'signal-stream-slash',\n 'signal-stream',\n 'rectangle-ad',\n 'ranking-star',\n 'person-rays',\n 'people-group',\n 'messages-dollar',\n 'message-dollar',\n 'magnifying-glass-location',\n 'magnifying-glass-dollar',\n 'lightbulb-on',\n 'lightbulb-exclamation',\n 'lightbulb-dollar',\n 'lightbulb-cfl-on',\n 'lightbulb-cfl',\n 'hundred-points',\n 'group-arrows-rotate',\n 'gift-card',\n 'filter-circle-dollar',\n 'envelopes-bulk',\n 'envelope-open-text',\n 'envelope-open-dollar',\n 'comment-dollar',\n 'chart-mixed',\n 'bullseye-arrow',\n 'star',\n 'heart',\n 'camera-retro',\n 'truck-fast',\n 'bell',\n 'cart-shopping',\n 'gift',\n 'barcode',\n 'bookmark',\n 'camera',\n 'thumbs-up',\n 'thumbs-down',\n 'key',\n 'truck',\n 'balloons',\n 'handshake',\n 'shop',\n 'shirt',\n 'bag-shopping',\n 'moped',\n 'cart-plus',\n 'credit-card',\n 'store',\n 'cash-register',\n 'booth-curtain',\n 'trophy',\n 'receipt',\n 'truck-container',\n 'truck-clock',\n 'truck-bolt',\n 'trophy-star',\n 'store-slash',\n 'store-lock',\n 'star-exclamation',\n 'shop-slash',\n 'shop-lock',\n 'rectangle-barcode',\n 'person-booth',\n 'nfc-trash',\n 'nfc-symbol',\n 'nfc-slash',\n 'nfc-signal',\n 'nfc-pen',\n 'nfc-magnifying-glass',\n 'nfc-lock',\n 'nfc',\n 'money-check-dollar',\n 'money-check',\n 'mobile-signal-out',\n 'mobile-signal',\n 'hexagon-vertical-nft-slanted',\n 'hexagon-vertical-nft',\n 'hexagon-image',\n 'hand-holding-box',\n 'gifts',\n 'gem',\n 'credit-card-front',\n 'credit-card-blank',\n 'cart-xmark',\n 'cart-shopping-fast',\n 'cart-minus',\n 'cart-circle-xmark',\n 'cart-circle-plus',\n 'cart-circle-exclamation',\n 'cart-circle-check',\n 'cart-circle-arrow-up',\n 'cart-circle-arrow-down',\n 'cart-arrow-up',\n 'cart-arrow-down',\n 'box-open-full',\n 'basket-shopping-simple',\n 'basket-shopping',\n 'barcode-scan',\n 'barcode-read',\n 'balloon',\n 'bags-shopping',\n 'bars',\n 'browser',\n 'chart-bar',\n 'cog',\n 'database',\n 'calendar-alt',\n 'play',\n 'kizen-k',\n 'add',\n 'book-alt',\n 'form-entity',\n 'arrows-to-circle',\n 'question-circle',\n 'chevron-down',\n 'chevron-up',\n 'window-restore',\n 'forward',\n]);\n\nexport const VALID_ICONS_LIST = [...VALID_ICONS].sort();\n\n// Icons rendered as custom Kizen-brand React components — no FontAwesome equivalent.\nexport const CUSTOM_ICON_NAMES = new Set(['kizen-k', 'form-entity']);\n\nexport const ALL_VALID_ICONS_LIST = [...VALID_ICONS_LIST, ...[...CUSTOM_ICON_NAMES].sort()];\n","import type { Command } from 'commander';\nimport { ALL_VALID_ICONS_LIST } from '../../shared/lib/validIcons.js';\n\nexport function iconsCommand(program: Command): void {\n program\n .command('icons')\n .description('List all valid icon names accepted by toolbar items, pages, and adornments')\n .action(() => {\n for (const name of ALL_VALID_ICONS_LIST) {\n console.log(name);\n }\n });\n}\n","import { mkdir, writeFile, readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { Command } from 'commander';\nimport { readLocalFiles } from '../lib/readFiles.js';\nimport { GLOBAL_CREDENTIALS_DIR } from '../lib/credentials.js';\nimport { generateHtml, generateMarkdown } from '../lib/reportHelpers.js';\n\nconst EXAMPLES_DIR = join(GLOBAL_CREDENTIALS_DIR, 'examples');\n\nexport function reportCommand(program: Command): void {\n program\n .command('report')\n .description('Generate a self-contained HTML report of the plugin')\n .option('-o, --output <path>', `output file path (default: ${EXAMPLES_DIR}/<api_name>.html)`)\n .action(async (options: { output?: string }) => {\n const pluginDir = process.cwd();\n\n let manifest: Record<string, unknown>;\n\n try {\n const raw = await readFile(join(pluginDir, 'kizen.json'), 'utf-8');\n const parsed = JSON.parse(raw) as unknown;\n\n manifest = (Array.isArray(parsed) ? parsed[0] : parsed) as Record<string, unknown>;\n } catch {\n console.error('Error: kizen.json not found. Run this command from a plugin directory.');\n process.exit(1);\n }\n\n const apiName = typeof manifest.api_name === 'string' ? manifest.api_name : 'plugin';\n const htmlPath = options.output ?? join(EXAMPLES_DIR, `${apiName}.html`);\n const mdPath = htmlPath.replace(/\\.html$/, '.md');\n\n const files = await readLocalFiles(pluginDir, { detectBinaryByContent: true });\n\n await mkdir(join(htmlPath, '..'), { recursive: true });\n\n await Promise.all([\n writeFile(htmlPath, generateHtml(manifest, files), 'utf-8'),\n writeFile(mdPath, generateMarkdown(manifest, files), 'utf-8'),\n ]);\n\n console.log(`Plugin report written to:\\n ${htmlPath}\\n ${mdPath}`);\n });\n}\n","import type { FileContent } from '@kizenapps/packager';\n\nconst SENSITIVE_FIELDS = new Set(['developer_business_id']);\n\nexport function redactServices(services: unknown): unknown {\n if (!Array.isArray(services)) {\n return services;\n }\n\n return services.map((svc: unknown) => {\n if (typeof svc !== 'object' || svc === null) {\n return svc;\n }\n\n const s = svc as Record<string, unknown>;\n\n if (typeof s.auth_credentials !== 'object' || s.auth_credentials === null) {\n return s;\n }\n\n const redacted = Object.fromEntries(Object.keys(s.auth_credentials).map((k) => [k, '*****']));\n\n return { ...s, auth_credentials: redacted };\n });\n}\n\nexport interface TreeNode {\n name: string;\n children: Map<string, TreeNode>;\n isFile: boolean;\n filePath: string;\n}\n\nexport function buildTree(files: FileContent[]): TreeNode {\n const root: TreeNode = { name: '', children: new Map(), isFile: false, filePath: '' };\n\n for (const file of files) {\n const parts = file.path.split('/');\n let node = root;\n\n parts.forEach((part, i) => {\n if (!node.children.has(part)) {\n node.children.set(part, {\n name: part,\n children: new Map(),\n isFile: i === parts.length - 1,\n filePath: parts.slice(0, i + 1).join('/'),\n });\n }\n\n const next = node.children.get(part);\n\n if (next) {\n node = next;\n }\n });\n }\n\n return root;\n}\n\nfunction sortTreeChildren(node: TreeNode): TreeNode[] {\n return [...node.children.values()].sort((a, b) => {\n if (a.isFile !== b.isFile) {\n return a.isFile ? 1 : -1;\n }\n\n return a.name.localeCompare(b.name);\n });\n}\n\nexport function fileId(path: string): string {\n return 'file-' + path.replace(/[^a-zA-Z0-9]/g, '-');\n}\n\nexport function esc(str: string): string {\n return str\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"');\n}\n\nexport function fileExt(path: string): string {\n const idx = path.lastIndexOf('.');\n\n return idx >= 0 ? path.slice(idx).toLowerCase() : '';\n}\n\nconst LANG_MAP: Record<string, string> = {\n '.ts': 'typescript',\n '.tsx': 'typescript',\n '.js': 'javascript',\n '.jsx': 'javascript',\n '.mjs': 'javascript',\n '.cjs': 'javascript',\n '.json': 'json',\n '.css': 'css',\n '.scss': 'scss',\n '.html': 'html',\n '.htm': 'html',\n '.md': 'markdown',\n '.mdx': 'markdown',\n '.py': 'python',\n '.sh': 'bash',\n '.yml': 'yaml',\n '.yaml': 'yaml',\n '.xml': 'xml',\n '.toml': 'toml',\n};\n\nexport function mdLang(path: string): string {\n return LANG_MAP[fileExt(path)] ?? '';\n}\n\n// A fenced block must be delimited by more backticks than the longest run inside\n// it, or content that is itself markdown (a README with a code sample) escapes\n// its wrapper and corrupts the rest of the document.\nexport function mdFence(content: string): string {\n const longestRun = [...content.matchAll(/`+/g)].reduce((max, m) => Math.max(max, m[0].length), 0);\n\n return '`'.repeat(Math.max(3, longestRun + 1));\n}\n\nexport function renderTextTree(node: TreeNode, prefix = ''): string {\n const sorted = sortTreeChildren(node);\n\n return sorted\n .map((child, i) => {\n const isLast = i === sorted.length - 1;\n const connector = isLast ? '└── ' : '├── ';\n const childPrefix = isLast ? ' ' : '│ ';\n\n if (child.isFile) {\n return `${prefix}${connector}${child.name}`;\n }\n\n return `${prefix}${connector}${child.name}/\\n${renderTextTree(child, prefix + childPrefix)}`;\n })\n .join('\\n');\n}\n\nconst LICENSE_FILE = /(^|\\/)licen[cs]e(\\.md|\\.txt)?$/i;\n\nexport function filterSourceFiles(files: FileContent[]): FileContent[] {\n return files.filter(\n (f) => f.path !== 'kizen.json' && f.path !== 'plugin-report.html' && !LICENSE_FILE.test(f.path),\n );\n}\n\nexport function buildFilteredConfig(manifest: Record<string, unknown>): Record<string, unknown> {\n return Object.fromEntries(\n Object.entries(manifest)\n .filter(([k]) => !SENSITIVE_FIELDS.has(k))\n .map(([k, v]) => [k, k === 'services' ? redactServices(v) : v]),\n );\n}\n\nconst IMAGE_MIME: Record<string, string> = {\n '.png': 'image/png',\n '.svg': 'image/svg+xml',\n '.jpg': 'image/jpeg',\n '.jpeg': 'image/jpeg',\n '.gif': 'image/gif',\n '.webp': 'image/webp',\n};\n\nfunction renderTree(node: TreeNode): string {\n const sorted = sortTreeChildren(node);\n const items = sorted.map((child) => {\n if (child.isFile) {\n return `<li class=\"tf\"><a href=\"#${fileId(child.filePath)}\" data-id=\"${fileId(child.filePath)}\">${esc(child.name)}</a></li>`;\n }\n\n return `<li class=\"td\"><span class=\"dn\">${esc(child.name)}/</span>${renderTree(child)}</li>`;\n });\n\n return `<ul>${items.join('')}</ul>`;\n}\n\nfunction renderFileSection(file: FileContent): string {\n let body: string;\n\n if (file.base64Image !== undefined) {\n const mime = IMAGE_MIME[fileExt(file.path)] ?? 'image/png';\n\n body = `<img src=\"data:${mime};base64,${file.base64Image}\" alt=\"${esc(file.path)}\" style=\"max-width:100%\">`;\n } else if (file.binaryData !== undefined) {\n body = `<p class=\"bin\">[Binary file: ${String(file.binaryData.length)} bytes]</p>`;\n } else {\n body = `<pre><code>${esc(file.content)}</code></pre>`;\n }\n\n return `<section id=\"${fileId(file.path)}\"><h2 class=\"fp\">${esc(file.path)}</h2><div class=\"fb\">${body}</div></section>`;\n}\n\nexport function generateMarkdown(manifest: Record<string, unknown>, files: FileContent[]): string {\n const filtered = buildFilteredConfig(manifest);\n const name = typeof manifest.name === 'string' ? manifest.name : 'Plugin';\n const version = typeof manifest.version === 'string' ? manifest.version : '';\n const description = typeof manifest.description === 'string' ? manifest.description : '';\n const sourceFiles = filterSourceFiles(files);\n\n const lines: string[] = [];\n\n lines.push(`# ${name}${version ? ` v${version}` : ''}`);\n if (description) {\n lines.push('', description);\n }\n\n const configJson = JSON.stringify(filtered, null, 2);\n const configFence = mdFence(configJson);\n\n lines.push(\n '',\n '## Configuration (`kizen.json`)',\n '',\n `${configFence}json`,\n configJson,\n configFence,\n );\n\n lines.push('', '## File Tree', '', '```', renderTextTree(buildTree(sourceFiles)), '```');\n\n lines.push('', '## Files');\n\n for (const file of sourceFiles) {\n lines.push('', `### \\`${file.path}\\``, '');\n\n if (file.base64Image !== undefined) {\n lines.push(`[Image file: ${file.path}]`);\n } else if (file.binaryData !== undefined) {\n lines.push(`[Binary file: ${String(file.binaryData.length)} bytes]`);\n } else {\n const fence = mdFence(file.content);\n\n lines.push(`${fence}${mdLang(file.path)}`, file.content, fence);\n }\n }\n\n return lines.join('\\n') + '\\n';\n}\n\nexport function generateHtml(manifest: Record<string, unknown>, files: FileContent[]): string {\n const filtered = buildFilteredConfig(manifest);\n const name = typeof manifest.name === 'string' ? manifest.name : 'Plugin';\n const version = typeof manifest.version === 'string' ? manifest.version : '';\n const description = typeof manifest.description === 'string' ? manifest.description : '';\n\n const sourceFiles = filterSourceFiles(files);\n const treeHtml = renderTree(buildTree(sourceFiles));\n const fileSections = sourceFiles.map(renderFileSection).join('\\n');\n\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">\n<title>${esc(name)} — Plugin Report</title>\n<style>\n*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}\n:root{\n --bg:#1e1e2e;--sb:#181825;--hd:#11111b;--tx:#cdd6f4;--mu:#6c7086;\n --ac:#89b4fa;--gr:#a6e3a1;--bd:#313244;--cb:#181825;--sw:280px;\n --fn:'Menlo','Consolas','Monaco',monospace;\n}\nhtml{font-size:14px}\nbody{background:var(--bg);color:var(--tx);font-family:var(--fn);display:flex;flex-direction:column;height:100vh}\nheader{background:var(--hd);border-bottom:1px solid var(--bd);padding:14px 20px;flex-shrink:0}\nheader h1{font-size:1.1rem;color:var(--ac)}\nheader p{color:var(--mu);font-size:.85rem;margin-top:3px}\n.layout{display:flex;flex:1;overflow:hidden}\nnav{width:var(--sw);background:var(--sb);border-right:1px solid var(--bd);overflow-y:auto;padding:12px 0;flex-shrink:0}\nnav a.cfg{display:block;padding:6px 16px;color:var(--gr);text-decoration:none;font-size:.85rem}\nnav a.cfg:hover,nav a.cfg.active{background:var(--bd)}\nnav ul{list-style:none;padding-left:0}\n.td>.dn{display:block;padding:4px 16px;color:var(--mu);font-size:.8rem}\n.td ul{padding-left:14px}\n.tf a{display:block;padding:3px 16px;color:var(--tx);text-decoration:none;font-size:.8rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.tf a:hover,.tf a.active{background:var(--bd);color:var(--ac)}\nmain{flex:1;overflow-y:auto;padding:0 24px 40px}\nsection{padding:32px 0;border-bottom:1px solid var(--bd)}\nh2.fp{font-size:.9rem;color:var(--ac);margin-bottom:12px;word-break:break-all}\n#config h2.fp{color:var(--gr)}\npre{background:var(--cb);border:1px solid var(--bd);border-radius:6px;padding:14px;overflow-x:auto;font-size:.78rem;line-height:1.6;white-space:pre}\ncode{font-family:var(--fn)}\nimg{border:1px solid var(--bd);border-radius:4px}\n.bin{color:var(--mu);font-style:italic;padding:12px 0}\n::-webkit-scrollbar{width:6px;height:6px}\n::-webkit-scrollbar-track{background:transparent}\n::-webkit-scrollbar-thumb{background:var(--bd);border-radius:3px}\n</style>\n</head>\n<body>\n<header>\n <h1>${esc(name)}${version ? ` <span style=\"color:var(--mu);font-size:.8em\">v${esc(version)}</span>` : ''}</h1>\n ${description ? `<p>${esc(description)}</p>` : ''}\n</header>\n<div class=\"layout\">\n<nav>\n <a href=\"#config\" class=\"cfg\" data-id=\"config\">kizen.json (config)</a>\n ${treeHtml}\n</nav>\n<main>\n<section id=\"config\"><h2 class=\"fp\">kizen.json — Plugin Configuration</h2><div class=\"fb\"><pre><code>${esc(JSON.stringify(filtered, null, 2))}</code></pre></div></section>\n${fileSections}\n</main>\n</div>\n<script>\n(function(){\n var links=document.querySelectorAll('[data-id]');\n function setActive(id){links.forEach(function(l){l.classList.toggle('active',l.getAttribute('data-id')===id);})}\n links.forEach(function(l){l.addEventListener('click',function(){setActive(this.getAttribute('data-id'));});});\n var obs=new IntersectionObserver(function(es){es.forEach(function(e){if(e.isIntersecting)setActive(e.target.id);});},{rootMargin:'-20% 0px -70% 0px'});\n document.querySelectorAll('section[id]').forEach(function(s){obs.observe(s);});\n})();\n</script>\n</body>\n</html>`;\n}\n","import type { Command } from 'commander';\nimport { runSetupClaude } from '../lib/setupClaude.js';\n\nexport function setupClaudeCommand(program: Command): void {\n program\n .command('setup-claude')\n .description('Install or refresh the Claude Code skill for building custom blocks')\n .option('--dry-run', 'report what would change without writing files')\n .action(async (options: { dryRun?: boolean }) => {\n await runSetupClaude(process.cwd(), options);\n });\n}\n"],"mappings":"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AAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ECAA,IAAAC,GAAA,g2GCAA,IAAAC,GAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ECAA,IAAAC,GAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ECAA,IAAAC,GAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;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,IAAKkB,CAAa,EAClD,QAAQ,OAAO,MAAM,+BAA+BlB,EAAQ,GAAG;AAAA,CAAI,CACrE,OAASiB,EAAK,CACZ,QAAQ,MACN,iBAAiBjB,EAAQ,GAAG,KAAKiB,aAAe,MAAQA,EAAI,QAAU,OAAOA,CAAG,CAAC,EACnF,EACA,QAAQ,SAAW,CACrB,CAEJ,CAAC,CACL,CK5HO,IAAMO,GAAc,IAAI,IAAI,CACjC,QACA,WACA,UACA,gBACA,YACA,OACA,YACA,MACA,MACA,OACA,QACA,gBACA,SACA,cACA,YACA,QACA,OACA,YACA,UACA,eACA,gBACA,mBACA,YACA,cACA,aACA,WACA,eACA,YACA,eACA,WACA,SACA,eACA,OACA,QACA,WACA,gBACA,eACA,OACA,aACA,YACA,eACA,YACA,UACA,SACA,QACA,SACA,YACA,WACA,aACA,cACA,UACA,SACA,mBACA,UACA,WACA,QACA,qBACA,gBACA,mBACA,YACA,iBACA,WACA,aACA,aACA,cACA,eACA,gBACA,UACA,uBACA,yBACA,oBACA,eACA,aACA,gBACA,kBACA,QACA,eACA,kBACA,iBACA,WACA,WACA,gBACA,wBACA,mBACA,iBACA,SACA,gBACA,cACA,yBACA,sBACA,SACA,cACA,iBACA,aACA,oBACA,gBACA,WACA,QACA,qBACA,WACA,cACA,kBACA,yBACA,yBACA,+BACA,YACA,gBACA,aACA,gBACA,aACA,cACA,YACA,UACA,mBACA,UACA,aACA,eACA,cACA,UACA,eACA,cACA,cACA,eACA,kBACA,oBACA,2BACA,iCACA,cACA,YACA,aACA,mBACA,mBACA,iBACA,oBACA,MACA,gBACA,eACA,wBACA,aACA,aACA,qBACA,aACA,iBACA,0BACA,gBACA,mBACA,YACA,gBACA,kBACA,aACA,eACA,iBACA,WACA,kBACA,wBACA,2BACA,gBACA,cACA,eACA,iBACA,gBACA,gBACA,eACA,gBACA,gBACA,cACA,WACA,YACA,iBACA,kBACA,kBACA,WACA,mBACA,YACA,mBACA,aACA,sBACA,gBACA,eACA,eACA,cACA,eACA,kBACA,iBACA,4BACA,0BACA,eACA,wBACA,mBACA,mBACA,gBACA,iBACA,sBACA,YACA,uBACA,iBACA,qBACA,uBACA,iBACA,cACA,iBACA,OACA,QACA,eACA,aACA,OACA,gBACA,OACA,UACA,WACA,SACA,YACA,cACA,MACA,QACA,WACA,YACA,OACA,QACA,eACA,QACA,YACA,cACA,QACA,gBACA,gBACA,SACA,UACA,kBACA,cACA,aACA,cACA,cACA,aACA,mBACA,aACA,YACA,oBACA,eACA,YACA,aACA,YACA,aACA,UACA,uBACA,WACA,MACA,qBACA,cACA,oBACA,gBACA,+BACA,uBACA,gBACA,mBACA,QACA,MACA,oBACA,oBACA,aACA,qBACA,aACA,oBACA,mBACA,0BACA,oBACA,uBACA,yBACA,gBACA,kBACA,gBACA,yBACA,kBACA,eACA,eACA,UACA,gBACA,OACA,UACA,YACA,MACA,WACA,eACA,OACA,UACA,MACA,WACA,cACA,mBACA,kBACA,eACA,aACA,iBACA,SACF,CAAC,EAEYC,GAAmB,CAAC,GAAGD,EAAW,EAAE,KAAK,EAGzCE,GAAoB,IAAI,IAAI,CAAC,UAAW,aAAa,CAAC,EAEtDC,GAAuB,CAAC,GAAGF,GAAkB,GAAG,CAAC,GAAGC,EAAiB,EAAE,KAAK,CAAC,EC3SnF,SAASE,GAAaC,EAAwB,CACnDA,EACG,QAAQ,OAAO,EACf,YAAY,4EAA4E,EACxF,OAAO,IAAM,CACZ,QAAWC,KAAQC,GACjB,QAAQ,IAAID,CAAI,CAEpB,CAAC,CACL,CCZA,OAAS,SAAAE,GAAO,aAAAC,GAAW,YAAAC,OAAgB,cAC3C,OAAS,QAAAC,OAAY,OCCrB,IAAMC,GAAmB,IAAI,IAAI,CAAC,uBAAuB,CAAC,EAEnD,SAASC,GAAeC,EAA4B,CACzD,OAAK,MAAM,QAAQA,CAAQ,EAIpBA,EAAS,IAAKC,GAAiB,CACpC,GAAI,OAAOA,GAAQ,UAAYA,IAAQ,KACrC,OAAOA,EAGT,IAAMC,EAAID,EAEV,GAAI,OAAOC,EAAE,kBAAqB,UAAYA,EAAE,mBAAqB,KACnE,OAAOA,EAGT,IAAMC,EAAW,OAAO,YAAY,OAAO,KAAKD,EAAE,gBAAgB,EAAE,IAAKE,GAAM,CAACA,EAAG,OAAO,CAAC,CAAC,EAE5F,MAAO,CAAE,GAAGF,EAAG,iBAAkBC,CAAS,CAC5C,CAAC,EAjBQH,CAkBX,CASO,SAASK,GAAUC,EAAgC,CACxD,IAAMC,EAAiB,CAAE,KAAM,GAAI,SAAU,IAAI,IAAO,OAAQ,GAAO,SAAU,EAAG,EAEpF,QAAWC,KAAQF,EAAO,CACxB,IAAMG,EAAQD,EAAK,KAAK,MAAM,GAAG,EAC7BE,EAAOH,EAEXE,EAAM,QAAQ,CAACE,EAAMC,IAAM,CACpBF,EAAK,SAAS,IAAIC,CAAI,GACzBD,EAAK,SAAS,IAAIC,EAAM,CACtB,KAAMA,EACN,SAAU,IAAI,IACd,OAAQC,IAAMH,EAAM,OAAS,EAC7B,SAAUA,EAAM,MAAM,EAAGG,EAAI,CAAC,EAAE,KAAK,GAAG,CAC1C,CAAC,EAGH,IAAMC,EAAOH,EAAK,SAAS,IAAIC,CAAI,EAE/BE,IACFH,EAAOG,EAEX,CAAC,CACH,CAEA,OAAON,CACT,CAEA,SAASO,GAAiBJ,EAA4B,CACpD,MAAO,CAAC,GAAGA,EAAK,SAAS,OAAO,CAAC,EAAE,KAAK,CAACK,EAAGC,IACtCD,EAAE,SAAWC,EAAE,OACVD,EAAE,OAAS,EAAI,GAGjBA,EAAE,KAAK,cAAcC,EAAE,IAAI,CACnC,CACH,CAEO,SAASC,GAAOC,EAAsB,CAC3C,MAAO,QAAUA,EAAK,QAAQ,gBAAiB,GAAG,CACpD,CAEO,SAASC,GAAIC,EAAqB,CACvC,OAAOA,EACJ,QAAQ,KAAM,OAAO,EACrB,QAAQ,KAAM,MAAM,EACpB,QAAQ,KAAM,MAAM,EACpB,QAAQ,KAAM,QAAQ,CAC3B,CAEO,SAASC,GAAQH,EAAsB,CAC5C,IAAMI,EAAMJ,EAAK,YAAY,GAAG,EAEhC,OAAOI,GAAO,EAAIJ,EAAK,MAAMI,CAAG,EAAE,YAAY,EAAI,EACpD,CAEA,IAAMC,GAAmC,CACvC,MAAO,aACP,OAAQ,aACR,MAAO,aACP,OAAQ,aACR,OAAQ,aACR,OAAQ,aACR,QAAS,OACT,OAAQ,MACR,QAAS,OACT,QAAS,OACT,OAAQ,OACR,MAAO,WACP,OAAQ,WACR,MAAO,SACP,MAAO,OACP,OAAQ,OACR,QAAS,OACT,OAAQ,MACR,QAAS,MACX,EAEO,SAASC,GAAON,EAAsB,CAC3C,OAAOK,GAASF,GAAQH,CAAI,CAAC,GAAK,EACpC,CAKO,SAASO,GAAQC,EAAyB,CAC/C,IAAMC,EAAa,CAAC,GAAGD,EAAQ,SAAS,KAAK,CAAC,EAAE,OAAO,CAACE,EAAKC,IAAM,KAAK,IAAID,EAAKC,EAAE,CAAC,EAAE,MAAM,EAAG,CAAC,EAEhG,MAAO,IAAI,OAAO,KAAK,IAAI,EAAGF,EAAa,CAAC,CAAC,CAC/C,CAEO,SAASG,GAAepB,EAAgBqB,EAAS,GAAY,CAClE,IAAMC,EAASlB,GAAiBJ,CAAI,EAEpC,OAAOsB,EACJ,IAAI,CAACC,EAAOrB,IAAM,CACjB,IAAMsB,EAAStB,IAAMoB,EAAO,OAAS,EAC/BG,EAAYD,EAAS,sBAAS,sBAC9BE,EAAcF,EAAS,OAAS,YAEtC,OAAID,EAAM,OACD,GAAGF,CAAM,GAAGI,CAAS,GAAGF,EAAM,IAAI,GAGpC,GAAGF,CAAM,GAAGI,CAAS,GAAGF,EAAM,IAAI;AAAA,EAAMH,GAAeG,EAAOF,EAASK,CAAW,CAAC,EAC5F,CAAC,EACA,KAAK;AAAA,CAAI,CACd,CAEA,IAAMC,GAAe,kCAEd,SAASC,GAAkBhC,EAAqC,CACrE,OAAOA,EAAM,OACViC,GAAMA,EAAE,OAAS,cAAgBA,EAAE,OAAS,sBAAwB,CAACF,GAAa,KAAKE,EAAE,IAAI,CAChG,CACF,CAEO,SAASC,GAAoBC,EAA4D,CAC9F,OAAO,OAAO,YACZ,OAAO,QAAQA,CAAQ,EACpB,OAAO,CAAC,CAACrC,CAAC,IAAM,CAACN,GAAiB,IAAIM,CAAC,CAAC,EACxC,IAAI,CAAC,CAACA,EAAGsC,CAAC,IAAM,CAACtC,EAAGA,IAAM,WAAaL,GAAe2C,CAAC,EAAIA,CAAC,CAAC,CAClE,CACF,CAEA,IAAMC,GAAqC,CACzC,OAAQ,YACR,OAAQ,gBACR,OAAQ,aACR,QAAS,aACT,OAAQ,YACR,QAAS,YACX,EAEA,SAASC,GAAWlC,EAAwB,CAU1C,MAAO,OATQI,GAAiBJ,CAAI,EACf,IAAKuB,GACpBA,EAAM,OACD,4BAA4BhB,GAAOgB,EAAM,QAAQ,CAAC,cAAchB,GAAOgB,EAAM,QAAQ,CAAC,KAAKd,GAAIc,EAAM,IAAI,CAAC,YAG5G,mCAAmCd,GAAIc,EAAM,IAAI,CAAC,WAAWW,GAAWX,CAAK,CAAC,OACtF,EAEmB,KAAK,EAAE,CAAC,OAC9B,CAEA,SAASY,GAAkBrC,EAA2B,CACpD,IAAIsC,EAEJ,OAAItC,EAAK,cAAgB,OAGvBsC,EAAO,kBAFMH,GAAWtB,GAAQb,EAAK,IAAI,CAAC,GAAK,WAElB,WAAWA,EAAK,WAAW,UAAUW,GAAIX,EAAK,IAAI,CAAC,4BACvEA,EAAK,aAAe,OAC7BsC,EAAO,gCAAgC,OAAOtC,EAAK,WAAW,MAAM,CAAC,cAErEsC,EAAO,cAAc3B,GAAIX,EAAK,OAAO,CAAC,gBAGjC,gBAAgBS,GAAOT,EAAK,IAAI,CAAC,oBAAoBW,GAAIX,EAAK,IAAI,CAAC,wBAAwBsC,CAAI,kBACxG,CAEO,SAASC,GAAiBN,EAAmCnC,EAA8B,CAChG,IAAM0C,EAAWR,GAAoBC,CAAQ,EACvCQ,EAAO,OAAOR,EAAS,MAAS,SAAWA,EAAS,KAAO,SAC3DS,EAAU,OAAOT,EAAS,SAAY,SAAWA,EAAS,QAAU,GACpEU,EAAc,OAAOV,EAAS,aAAgB,SAAWA,EAAS,YAAc,GAChFW,EAAcd,GAAkBhC,CAAK,EAErC+C,EAAkB,CAAC,EAEzBA,EAAM,KAAK,KAAKJ,CAAI,GAAGC,EAAU,KAAKA,CAAO,GAAK,EAAE,EAAE,EAClDC,GACFE,EAAM,KAAK,GAAIF,CAAW,EAG5B,IAAMG,EAAa,KAAK,UAAUN,EAAU,KAAM,CAAC,EAC7CO,EAAc9B,GAAQ6B,CAAU,EAEtCD,EAAM,KACJ,GACA,kCACA,GACA,GAAGE,CAAW,OACdD,EACAC,CACF,EAEAF,EAAM,KAAK,GAAI,eAAgB,GAAI,MAAOvB,GAAezB,GAAU+C,CAAW,CAAC,EAAG,KAAK,EAEvFC,EAAM,KAAK,GAAI,UAAU,EAEzB,QAAW7C,KAAQ4C,EAGjB,GAFAC,EAAM,KAAK,GAAI,SAAS7C,EAAK,IAAI,KAAM,EAAE,EAErCA,EAAK,cAAgB,OACvB6C,EAAM,KAAK,gBAAgB7C,EAAK,IAAI,GAAG,UAC9BA,EAAK,aAAe,OAC7B6C,EAAM,KAAK,iBAAiB,OAAO7C,EAAK,WAAW,MAAM,CAAC,SAAS,MAC9D,CACL,IAAMgD,EAAQ/B,GAAQjB,EAAK,OAAO,EAElC6C,EAAM,KAAK,GAAGG,CAAK,GAAGhC,GAAOhB,EAAK,IAAI,CAAC,GAAIA,EAAK,QAASgD,CAAK,CAChE,CAGF,OAAOH,EAAM,KAAK;AAAA,CAAI,EAAI;AAAA,CAC5B,CAEO,SAASI,GAAahB,EAAmCnC,EAA8B,CAC5F,IAAM0C,EAAWR,GAAoBC,CAAQ,EACvCQ,EAAO,OAAOR,EAAS,MAAS,SAAWA,EAAS,KAAO,SAC3DS,EAAU,OAAOT,EAAS,SAAY,SAAWA,EAAS,QAAU,GACpEU,EAAc,OAAOV,EAAS,aAAgB,SAAWA,EAAS,YAAc,GAEhFW,EAAcd,GAAkBhC,CAAK,EACrCoD,EAAWd,GAAWvC,GAAU+C,CAAW,CAAC,EAC5CO,EAAeP,EAAY,IAAIP,EAAiB,EAAE,KAAK;AAAA,CAAI,EAEjE,MAAO;AAAA;AAAA;AAAA;AAAA;AAAA,SAKA1B,GAAI8B,CAAI,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAqCV9B,GAAI8B,CAAI,CAAC,GAAGC,EAAU,kDAAkD/B,GAAI+B,CAAO,CAAC,UAAY,EAAE;AAAA,IACtGC,EAAc,MAAMhC,GAAIgC,CAAW,CAAC,OAAS,EAAE;AAAA;AAAA;AAAA;AAAA;AAAA,IAK/CO,CAAQ;AAAA;AAAA;AAAA,4GAG2FvC,GAAI,KAAK,UAAU6B,EAAU,KAAM,CAAC,CAAC,CAAC;AAAA,EAC3IW,CAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAcd,CDxTA,IAAMC,GAAeC,GAAKC,GAAwB,UAAU,EAErD,SAASC,GAAcC,EAAwB,CACpDA,EACG,QAAQ,QAAQ,EAChB,YAAY,qDAAqD,EACjE,OAAO,sBAAuB,8BAA8BJ,EAAY,mBAAmB,EAC3F,OAAO,MAAOK,GAAiC,CAC9C,IAAMC,EAAY,QAAQ,IAAI,EAE1BC,EAEJ,GAAI,CACF,IAAMC,EAAM,MAAMC,GAASR,GAAKK,EAAW,YAAY,EAAG,OAAO,EAC3DI,EAAS,KAAK,MAAMF,CAAG,EAE7BD,EAAY,MAAM,QAAQG,CAAM,EAAIA,EAAO,CAAC,EAAIA,CAClD,MAAQ,CACN,QAAQ,MAAM,wEAAwE,EACtF,QAAQ,KAAK,CAAC,CAChB,CAEA,IAAMC,EAAU,OAAOJ,EAAS,UAAa,SAAWA,EAAS,SAAW,SACtEK,EAAWP,EAAQ,QAAUJ,GAAKD,GAAc,GAAGW,CAAO,OAAO,EACjEE,EAASD,EAAS,QAAQ,UAAW,KAAK,EAE1CE,EAAQ,MAAMC,GAAeT,EAAW,CAAE,sBAAuB,EAAK,CAAC,EAE7E,MAAMU,GAAMf,GAAKW,EAAU,IAAI,EAAG,CAAE,UAAW,EAAK,CAAC,EAErD,MAAM,QAAQ,IAAI,CAChBK,GAAUL,EAAUM,GAAaX,EAAUO,CAAK,EAAG,OAAO,EAC1DG,GAAUJ,EAAQM,GAAiBZ,EAAUO,CAAK,EAAG,OAAO,CAC9D,CAAC,EAED,QAAQ,IAAI;AAAA,IAAgCF,CAAQ;AAAA,IAAOC,CAAM,EAAE,CACrE,CAAC,CACL,CEzCO,SAASO,GAAmBC,EAAwB,CACzDA,EACG,QAAQ,cAAc,EACtB,YAAY,qEAAqE,EACjF,OAAO,YAAa,gDAAgD,EACpE,OAAO,MAAOC,GAAkC,CAC/C,MAAMC,GAAe,QAAQ,IAAI,EAAGD,CAAO,CAC7C,CAAC,CACL,ClFEA,SAASE,IAAsB,CAC7B,IAAMC,EAAUC,GAAKC,GAAQC,GAAc,YAAY,GAAG,CAAC,EAAG,KAAM,cAAc,EAGlF,OAFY,KAAK,MAAMC,GAAaJ,EAAS,OAAO,CAAC,EAE1C,OACb,CAEO,SAASK,IAAyB,CACvC,IAAMC,EAAU,IAAIC,GAEpB,OAAAD,EAAQ,KAAK,YAAY,EAAE,YAAY,0BAA0B,EAAE,QAAQP,GAAY,CAAC,EAExFS,GAAcF,CAAO,EAErBG,GAAmBH,CAAO,EAE1BI,GAAaJ,CAAO,EAEpBK,GAAWL,CAAO,EAElBM,GAAeN,CAAO,EAEtBO,GAAcP,CAAO,EAErBQ,GAAaR,CAAO,EAEpBS,GAAaT,CAAO,EAEbA,CACT,CFtCAU,GAAkB,CAAE,IAAK,QAAQ,IAAK,KAAAC,EAAK,CAAC,EAE5CC,GAAc,EAAE,MAAM","names":["http","PROXY_UNAVAILABLE_HINT","PROXY_VARS","isSet","value","status","applyProxyFromEnv","env","http","name","getProxyEnvStatus","readFileSync","dirname","join","fileURLToPath","Command","createElement","render","PluginValidationError","spawn","platform","clipboardCommands","CLIPBOARD_TIMEOUT_MS","runClipboardCommand","text","cmd","args","resolve","child","spawned","settled","finish","ok","timer","code","copyToClipboard","command","BLOCKS_DIRECTORY_NAME","CONFIG_FILE_NAME","MANIFEST_FILE_NAME","sanitizeToAPIName","mkdir","writeFile","join","PluginValidationError","packagePlugin","parseManifestFromFiles","transformDeployablePlugin","transformFiles","validatePluginApp","readdir","readFile","join","relative","IMAGE_EXTENSIONS","BINARY_EXTENSIONS","SKIP_FILES","SKIP_DIRS","BINARY_SNIFF_BYTES","looksBinary","buf","walk","dir","rootDir","entries","paths","entry","readLocalFiles","detectBinaryByContent","absolutePaths","absPath","relPath","dotIndex","ext","serializePlugin","plugin","allReleaseNotes","packageLocalPlugin","pluginDir","onStep","files","readLocalFiles","issues","validatePluginApp","issue","PluginValidationError","minified","transformFiles","manifests","parseManifestFromFiles","packaged","packagePlugin","deployable","transformDeployablePlugin","runBuild","outputDir","mkdir","bundle","notesDir","f","a","b","jsonStr","stripReleaseNotes","key","value","bundleSize","writeFile","join","DIMENSION_FIELDS","DIMENSION_RANGES","DEFAULT_SIZE_BOUNDS","DEFAULT_SIZE_FIELDS","SIZE_FIELDS","AUTHORED_FIELDS","UNSUPPORTED_SEQUENCES","BlockExportError","reason","message","options","formatAvailableBlocks","available","multiplePlugins","entry","selectBlock","deployable","apiName","candidates","plugin","block","pluginApiName","only","matches","match","isRecord","value","isPositiveInteger","hasUnsupportedContent","sequence","findInvalidBlockField","raw","name","script","styles","eventScripts","invalidEntry","eventName","body","unsupported","invalidDimension","field","invertedMin","minField","maxField","min","max","invalidDefault","invalidBlockMessage","range","selectionError","selection","list","parseJsonRecord","content","parsed","manifestEntries","files","manifestFile","file","MANIFEST_FILE_NAME","manifests","entries","manifest","authoredBlockConfig","prefix","BLOCKS_DIRECTORY_NAME","authoredByApiName","directory","fileName","rest","CONFIG_FILE_NAME","config","sanitizeToAPIName","authored","withAuthoredConfig","key","applyAuthoredConfig","packageBlocks","pluginDir","issues","packageLocalPlugin","issue","exportBlock","warnings","invalidField","plural","count","singular","pluralForm","groupIssuesByPath","issues","groups","issue","key","group","formatHeader","errorCount","warningCount","errors","formatValidationIssues","sections","path","randomUUID","join","PluginValidationError","BASE_URLS","APP_URLS","PRODUCTION_ENVIRONMENTS","isProductionEnvironment","env","mkdir","readFile","writeFile","join","loadConfig","outputDir","content","saveConfig","config","mkdir","readFile","readdir","writeFile","homedir","dirname","join","ENVIRONMENTS","cleanCredentialId","value","normalizeCredentialIds","values","GLOBAL_CREDENTIALS_DIR","join","homedir","GLOBAL_CREDENTIALS_PATH","DEFAULT_PROFILE_NAME","isValidEnvironment","value","ENVIRONMENTS","trimString","parseCredentials","raw","obj","env","normalizeCredentialIds","loadCredentialsFromFile","filePath","content","readFile","environmentSourceOf","loadCredentialsDetailed","loadGlobalCredentials","saveGlobalCredentials","credentials","mkdir","dirname","writeFile","getProfilePath","name","listCredentialProfiles","profiles","entries","readdir","entry","saveCredentialProfile","loadCredentialProfile","listLoadableCredentialProfiles","loadable","profile","_","index","fs","path","ensureGitignore","projectDir","gitignorePath","entry","contents","lines","l","addition","AUTH_FAILED_HINT","FORBIDDEN_HINT","MAX_PAGES","UNPREFIXED_KEYS","KizenApiError","kind","message","options","isRecord","value","collectMessages","prefix","out","push","text","texts","item","key","child","childPrefix","formatDrfError","body","messages","errorCause","err","e","readBody","res","statusError","method","path","status","detail","listResults","data","createKizenClient","credentials","fetchImpl","baseUrl","BASE_URLS","request","target","url","headers","init","getProxyEnvStatus","PROXY_UNAVAILABLE_HINT","json","segment","resolveNext","next","base","resolved","type","customObjectId","params","all","seen","page","id","business","clientObject","dashboardId","dashletId","createHash","mkdir","readFile","writeFile","dirname","join","PUSH_NAME_PREFIX","PUSH_MAP_RELATIVE_PATH","DIMENSION_KEYS","PUSH_MAP_STRING_FIELDS","isRecord","value","isFiniteNumber","clamp","min","max","withoutCustomObject","record","rest","pushKey","pluginApiName","blockApiName","parsePushKey","name","parts","pickDimensions","source","dimensions","key","pickHostChrome","toCustomCodeContent","block","script","buildDashletConfig","args","computeMaxBottom","dashlets","maxBottom","dashlet","layout","y","h","computeCreateLayout","content","layoutId","w","buildCreateBody","buildUpdateBody","existing","rawConfig","contentOf","config","isCustomCodeDashlet","findCustomCodeDashlets","dashboard","customCodeName","normalizeEventScripts","stringOr","candidate","entry","sortKeysDeep","sorted","nameOf","canonicalContentHash","canonical","createHash","matchPushTarget","mapped","named","first","detectDrift","matchesKey","findPushMapEntry","entries","upsertPushMapEntry","index","candidateIndex","removePushMapEntry","toPushMapEntry","field","cleanCredentialId","pushedAtTime","latestPerKey","byKey","id","current","isMissingFileError","error","pushMapErrorDetail","readPushMap","pluginDir","raw","readFile","join","parsed","writePushMap","filePath","mkdir","dirname","writeFile","DASHBOARD_TYPE_TO_SURFACE","SURFACE_TO_DASHBOARD_TYPE","dashboardTypeToSurface","type","surfaceToDashboardType","surface","buildDashboardUrl","base","access","mkdir","readFile","writeFile","dirname","join","posix","SKILL_default","design_default","copilot_instructions_default","security_instructions_default","version_discipline_instructions_default","kizenData_default","copilotFiles","copilot_instructions_default","security_instructions_default","version_discipline_instructions_default","KIZEN_DATA_LIB_FILE","kizenDataLibPath","entryDir","claudeFiles","entryDirs","SKILL_default","design_default","kizenData_default","CLAUDE_SKILL_PATH","STALE_CLAUDE_SKILL_WARNING","isMissing","error","nodeClaudeFs","path","readFile","content","mkdir","dirname","writeFile","access","normalizeEntryDir","entry","normalized","posix","entryDirsOf","manifest","entryDirs","entryDir","pluginClaudeFiles","dir","fs","join","claudeFiles","statusOf","current","bundled","planClaudeFiles","files","file","applyClaudeFiles","options","plan","_file","index","isClaudeSkillStale","managed","defaultSetupClaudeDeps","line","code","count","status","runSetupClaude","deps","dryRun","counts","createDefaultPushDeps","cwd","loadCredentialsDetailed","listLoadableCredentialProfiles","loadConfig","packageBlocks","credentials","createKizenClient","readPushMap","writePushMap","ensureGitignore","dir","isClaudeSkillStale","randomUUID","text","code","EDIT_ACCESS_LEVELS","CHART_GROUP_HINT","errorMessage","error","failure","message","extra","success","value","apiFailure","KizenApiError","PluginValidationError","formatValidationIssues","environmentList","ENVIRONMENTS","loadCredentialSource","source","deps","detailed","problem","empty","field","profileSource","profile","resolveCredentials","options","profiles","names","candidate","GLOBAL_CREDENTIALS_PATH","config","join","active","only","blockChoices","deployable","available","multiplePlugins","entry","pluginApiName","apiName","block","plugin","qualified","blockSelectionMessage","selection","list","formatAvailableBlocks","resolveBlock","packaged","selectBlock","findInvalidBlockField","invalidBlockMessage","content","toCustomCodeContent","canonicalContentHash","canEditFor","employeeAccess","toTargetRow","summary","surface","toTargetCustomObject","object","CONTACTS_OBJECT_NAME","listPushableObjects","client","objects","clientObjectId","pushable","left","right","listTargets","environment","businessId","objectId","chartGroups","row","dashboards","homepages","customObjects","isMemberDashlet","dashboard","dashlet","buildTargetChoices","findCustomCodeDashlets","parsed","parsePushKey","customCodeName","target","action","resolvedBy","dashboardTypeToSurface","chooseDashboard","context","toChoice","resolveFlaggedDashboard","dashboardId","choices","dashletId","isCustomCodeDashlet","match","matchPushTarget","resolveRemembered","resolveTarget","customObjectOf","raw","id","fetchUrl","segment","buildPlan","resolved","warnings","body","path","actionLine","detectDrift","drift","buildUpdateBody","buildCreateBody","url","buildDashboardUrl","APP_URLS","isProductionEnvironment","pushMapKeyOf","applyPlan","plan","createdId","remembered","upsertPushMapEntry","PUSH_MAP_RELATIVE_PATH","UUID_PATTERN","buildBrowserRefresh","forgetRemembered","key","findPushMapEntry","removePushMapEntry","headlessWriteGate","DRY_RUN_NOTE","formatSummaryLines","formatIssueWarning","issue","quoteArg","arg","formatFailureText","result","command","choiceArgs","lines","choice","args","writeFailure","output","credentialArgs","claudeSkillWarnings","STALE_CLAUDE_SKILL_WARNING","runPushHeadless","blockArgs","kind","fail","credentialStep","blockStep","forgotten","targetStep","gateStep","planStep","blockInfo","common","issueWarnings","gate","w","warning","appliedStep","applied","refresh","pad","width","formatTargetTable","title","rows","header","cells","widths","label","index","cell","line","formatTargetsText","runTargetsHeadless","objectArgs","targetsStep","useEffect","useState","Box","Text","useApp","useInput","Box","Text","Box","Text","jsx","LOGO_LINES","Logo","line","i","Fragment","jsx","jsxs","AppHeader","marginBottom","Logo","Box","Text","useMemo","useState","Box","Text","useInput","clamp","value","min","max","moveCursor","cursor","length","delta","options","current","isEnabled","index","step","offset","target","visibleWindow","size","rows","start","jsx","jsxs","DEFAULT_HINT","DEFAULT_WINDOW_SIZE","initialCursor","items","initialIndex","clamped","moveCursor","firstEnabled","item","SelectList","title","onSelect","onCancel","hint","windowSize","isActive","cursorState","setCursorState","useState","disabled","useMemo","cursor","pageSize","useInput","input","key","move","delta","start","end","visibleWindow","above","below","Box","Text","offset","selected","itemDisabled","highlight","useEffect","useState","Text","jsx","SPINNER_FRAMES","Spinner","frame","setFrame","id","prev","Fragment","jsx","jsxs","SURFACE_ITEMS","SURFACE_NOUNS","DRIFT_WARNING","isCreateChoice","choice","orderTargetChoices","choices","matchedId","matched","creates","rest","targetItem","description","dashboardItem","row","label","part","withTarget","options","dashboardId","next","createPushFlow","apiName","deps","setPhase","setSession","fail","view","guard","task","error","apiFailure","apply","context","plan","step","applyPlan","target","buildPlan","gate","headlessWriteGate","resolve","back","resolveTarget","prepare","credentials","block","key","pushMapKeyOf","pushMap","forgetRemembered","removePushMapEntry","session","findPushMapEntry","packageBlock","name","resolveBlock","loadCredentials","resolveCredentials","listDashboards","surface","object","noun","rows","surfaceToDashboardType","summary","toTargetRow","environment","businessId","phase","objects","listPushableObjects","dashboard","match","matchPushTarget","buildTargetChoices","ConfirmPrompt","prompt","strict","onAccept","onCancel","useInput","input","answer","Text","Lines","lines","color","Box","line","index","PlanSummary","formatSummaryLines","Working","Spinner","ErrorFrame","formatValidationIssues","DoneFrame","applied","refresh","buildBrowserRefresh","warning","PushUI","app","useApp","useState","flow","initialOptions","useEffect","frame","children","AppHeader","SelectList","_item","item","describeError","error","PluginValidationError","formatValidationIssues","blockCommand","program","block","apiName","options","exported","warnings","exportBlock","json","copyToClipboard","runPushHeadless","createDefaultPushDeps","waitUntilExit","render","createElement","PushUI","runTargetsHeadless","createElement","render","useEffect","useState","Box","Text","useApp","PluginValidationError","formatBytes","n","Box","Text","jsx","jsxs","groupIssuesByPath","issues","groups","issue","key","group","ValidationIssues","errorCount","path","Fragment","jsx","jsxs","STEPS","STEP_LABELS","BuildUI","outputDir","pluginDir","app","useApp","step","setStep","useState","failed","setFailed","issues","setIssues","errorMessage","setErrorMessage","bundleSize","setBundleSize","useEffect","runBuild","size","err","PluginValidationError","currentIndex","isDone","Box","AppHeader","s","i","isActive","isStepDone","Text","Spinner","formatBytes","ValidationIssues","buildCommand","program","pluginDir","outputDir","ensureGitignore","waitUntilExit","render","createElement","BuildUI","createElement","render","useCallback","useState","Box","Text","useApp","useInput","join","access","mkdir","writeFile","dirname","join","config_default","script_default","styles_default","config_default","script_default","styles_default","config_default","script_default","config_default","script_default","styles_default","greet_default","config_default","script_default","config_default","script_default","config_default","script_default","ARTIFACT_TYPES","ARTIFACT_LABELS","TEMPLATES","config_default","script_default","styles_default","greet_default","artifactFiles","type","entryDir","directory","component","files","relativePath","content","scaffoldArtifactFiles","types","deflateSync","THUMBNAIL_SIZE","BODY_HALF_SIZE","BODY_CORNER_RADIUS","KNOB_RADIUS","KNOB_OFFSET_RATIO","NECK_HALF_WIDTH","SATURATION","LIGHTNESS","fnv1a","text","hash","i","thumbnailStyle","apiName","hslToRgb","hue","saturation","lightness","chroma","sector","secondary","match","r","g","b","roundedBoxDistance","x","y","halfW","halfH","radius","qx","qy","circleDistance","cx","cy","puzzlePieceDistance","s","k","offset","neckHalf","d","topKnob","rightKnob","bottomSocket","leftSocket","renderPixels","style","size","pixels","knobExtension","centre","shift","py","px","turn","coverage","CRC_TABLE","_","n","c","crc32","bytes","crc","byte","pngChunk","type","data","typeBytes","length","PNG_SIGNATURE","encodePng","width","height","rgba","ihdr","stride","raw","thumbnailBytes","THUMBNAIL_PATH","PROD_ENVIRONMENTS","pathExists","path","access","precheckTargetDir","dir","join","findAvailableSubDir","parentDir","baseName","base","i","candidate","buildManifest","input","businessId","targetEnvironments","writeScaffoldedFiles","targetDir","scaffolded","files","file","directories","dirname","mkdir","writeFile","createPlugin","manifest","scaffoldArtifactFiles","copilotFiles","claudeFiles","thumbnailBytes","ensureGitignore","FIELDS","FIELD_LABELS","REQUIRED_FIELDS","API_NAME_PATTERN","API_NAME_HINT","inferApiName","name","emptyValues","defaultBusinessId","validateField","fieldName","inputBuffer","value","normalizeFieldValue","toggleArtifactSelection","selected","type","next","ARTIFACT_TYPES","candidate","jsx","jsxs","Hint","text","Text","CreateUI","parentDir","defaultBusinessId","defaultEnvironment","app","useApp","phase","setPhase","useState","mode","setMode","values","setValues","emptyValues","artifacts","setArtifacts","ARTIFACT_TYPES","inputBuffer","setInputBuffer","targetDir","setTargetDir","enterFieldEntry","useCallback","nextMode","initialValues","runPrecheck","dir","result","precheckTargetDir","resolveSubDirAndConfirm","finalValues","findAvailableSubDir","err","runWrite","createPlugin","useInput","input","key","field","current","fieldName","FIELDS","prev","updated","prevField","prevName","fieldError","validateField","valueToStore","normalizeFieldValue","nextField","nextName","existing","nextBuffer","inferApiName","cursor","selected","lastField","lastName","type","next","toggleArtifactSelection","options","Box","AppHeader","opt","i","reason","activeField","targetLine","name","isActive","displayValue","isRequired","REQUIRED_FIELDS","label","FIELD_LABELS","active","checked","ARTIFACT_LABELS","manifest","buildManifest","join","PLACEHOLDER_DESCRIPTION","parseArtifactSelection","raw","ARTIFACT_TYPES","requested","part","unknown","resolveHeadlessInput","options","defaults","targetDir","name","apiName","inferApiName","API_NAME_PATTERN","API_NAME_HINT","description","developerBusinessId","developerEnvironment","resolveEnvironment","isEnvironment","value","ENVIRONMENTS","runHeadlessCreate","deps","input","err","precheck","conflict","artifactSummary","createCommand","program","ENVIRONMENTS","ARTIFACT_TYPES","options","parentDir","globalCreds","loadGlobalCredentials","defaultBusinessId","defaultEnvironment","suppliedFlags","value","runHeadlessCreate","precheckTargetDir","createPlugin","text","code","waitUntilExit","render","createElement","CreateUI","createElement","render","useCallback","useEffect","useRef","useState","Box","Text","useInput","PluginValidationError","watch","createServer","join","WebSocketServer","createReadStream","realpathSync","access","readdir","readFile","realpath","stat","dirname","extname","join","resolve","sep","fileURLToPath","STRIPPED_RESPONSE_HEADERS","sanitizeUpstreamHeaders","headers","filtered","key","value","lower","MAX_PROXY_BYTES","CACHE_TTL_MS","CACHE_MAX_ENTRIES","ProxyResponseTooLargeError","bytesRead","limit","readBodyWithLimit","response","body","chunks","total","chunk","toCachedResponse","createProxyCache","options","onChange","enabled","_key","fetcher","cache","emitChange","evict","existing","oldest","pending","error","MIME_TYPES","ENCRYPTION_API_DEFAULTS","resolveWizardBase","target","forced","spawn","writeFile","rm","mkdtemp","access","join","tmpdir","python_requirements_default","parseRequirementsFile","content","line","resolvePythonBinary","runtime","match","major","minor","toStepInputValue","raw","coerceStepInputValue","value","toStepInputValue","normalizeStepInputs","inputs","name","WRAPPER_SCRIPT","DEFAULT_TIMEOUT","VENV_DIR","join","SUPPORTED_RUNTIMES","isSupportedRuntime","runtime","VENV_PACKAGES","parseRequirementsFile","python_requirements_default","venvReady","MIN_PYTHON","meetsMinimum","major","minor","formatVersion","version","probePython","bin","resolve","proc","spawn","out","chunk","code","match","findSystemPython","preferred","resolvePythonBinary","candidates","tried","runCommand","args","onLine","reject","pipeLines","source","stream","captured","buffer","idx","line","stderrCaptured","tail","detail","venvInstallListeners","ensureVenv","listener","listeners","emit","event","l","venvPython","reusable","access","existing","rm","systemPython","err","message","parseResult","stdout","startMarker","endMarker","startIdx","endIdx","userStdout","jsonStr","result","failedExecutionResult","error","executePythonStep","params","timeout","pythonBin","start","tmpDir","mkdtemp","tmpdir","wrapperPath","scriptPath","writeFile","env","exitCode","stderr","stdoutChunks","stderrChunks","settled","timer","finish","durationMs","base","TEXT_EXTENSIONS","CRYPTO_ALG","CRYPTO_VERSION","deserializeEnvelope","encrypt","serializeEnvelope","proxyLogEntryToString","entry","cache","upstream","SOURCE_FILE_MAX_BYTES","SKIP_FILES","isLocalHost","host","hostname","PROXY_ALLOWED_DOMAINS","isAllowedWizardTarget","target","url","domain","isAllowedProxyTarget","isLocalOrigin","origin","resolveSafePath","realPluginDir","relParam","rel","abs","resolve","sep","realAbs","realpath","isInsideSkippedDir","pluginDir","segment","SKIP_DIRS","getViewerPath","filename","fileURLToPath","join","dirname","extractUpstreamStatus","upstreamPath","headers","body","parsed","fileExists","filePath","access","createRequestHandler","viewerPath","createServerLog","createProxyLog","credentialsRef","activeProfileRef","outputDir","broadcast","onProxyCacheChange","lastPathRef","cacheEnabled","proxyCache","createProxyCache","realpathSync","req","res","profiles","listCredentialProfiles","chunks","chunk","profileName","creds","loadGlobalCredentials","loadCredentialProfile","active","currentConfig","loadConfig","saveConfig","bundlePath","content","readFile","stepParams","normalizeStepInputs","event","result","executePythonStep","envelope","encrypt","serialized","serializeEnvelope","err","parseError","deserializeEnvelope","bufLen","b64","checks","CRYPTO_VERSION","CRYPTO_ALG","c","rawTarget","wizardBase","resolveWizardBase","upstreamUrl","method","_wizardHost","_encTarget","wizardForwardHeaders","resolvedBody","upstream","message","wizardResponseHeaders","sanitizeUpstreamHeaders","wizardBody","proxyTarget","_drop","forwardHeaders","cacheKey","cached","fromCache","responseHeaders","responseBody","readBodyWithLimit","MAX_PROXY_BYTES","dirEntries","readdir","entries","entry","kind","stats","stat","a","b","normalizedPath","detail","ext","extname","explicitMime","MIME_TYPES","isKnownText","TEXT_EXTENSIONS","contentType","createReadStream","resolvedPath","mimeType","ProxyResponseTooLargeError","launch","createRequire","mkdirSync","readFile","dirname","join","fileURLToPath","CDP","CSP_HEADERS","KIZEN_DOMAINS","isKizenUrl","url","hostname","d","installDockIcon","client","iconPath","icon","launchChromeViewer","opts","baseUrl","chrome","cdpPort","cookieTimer","mainTargetId","reconnectTimer","reconnectAttempt","killed","dbg","msg","vb","clearCookieTimer","isNewTabUrl","setupClient","c","rawParams","params","requestId","request","responseHeaders","responseStatusCode","filtered","rewroteSetCookie","h","patched","cookie","body","base64Encoded","e","e2","cookies","raw","bare","handleTarget","targetInfo","scheduleReconnect","delay","attemptNumber","MAX_CDP_ATTEMPTS","CDP_ATTEMPT_DELAY_MS","attempt","r","warning","useCallback","useState","useLogHistory","limit","history","setHistory","append","message","h","useCallback","useEffect","useState","Box","Text","useInput","jsx","jsxs","FIELDS","FIELD_LABELS","Hint","text","Text","CredentialSetupUI","initialMode","showProfileManager","onComplete","onCancel","phase","setPhase","useState","inputBuffer","setInputBuffer","error","setError","activeProfileName","setActiveProfileName","handleModeChosen","useCallback","mode","handleProfileChosen","profile","profiles","listCredentialProfiles","existing","loadGlobalCredentials","loadCredentialProfile","envCursor","ENVIRONMENTS","handleSave","values","environment","credentials","normalizeCredentialIds","saveCredentialProfile","DEFAULT_PROFILE_NAME","err","useInput","input","key","loadProfileList","cursor","addNewIdx","totalItems","selected","nameBuffer","existingProfiles","trimmed","p","field","fieldName","prev","updatedValues","prevField","nextField","useEffect","label","Box","AppHeader","opt","i","nameError","activeField","isEnvField","profileLabel","GLOBAL_CREDENTIALS_PATH","name","isActive","displayValue","env","isSelected","jsx","jsxs","SKIP_WATCH_PREFIXES","DevUI","port","pluginDir","outputDir","initialCredentials","initialCredentialMode","initialActiveProfile","initialLastPath","debug","verbose","autoViewer","cacheEnabled","credentialsRef","useRef","activeProfileRef","lastPathRef","credMode","setCredMode","useState","credentialMode","setCredentialMode","status","setStatus","errorMessage","setErrorMessage","serverLogHistory","appendServerLog","useLogHistory","buildLogHistory","appendBuildLog","cdpLogHistory","appendCdpLog","proxyLogHistory","setProxyLogHistory","buildStatus","setBuildStatus","buildError","setBuildError","buildIssues","setBuildIssues","lastBuilt","setLastBuilt","lastBundleSize","setLastBundleSize","wsClientCount","setWsClientCount","proxyCacheSize","setProxyCacheSize","proxyCacheHits","setProxyCacheHits","proxyCacheMisses","setProxyCacheMisses","buildingRef","viewerLaunchedRef","chromeHandleRef","debounceTimerRef","wsClientsRef","pendingMessagesRef","broadcast","useCallback","msg","json","pruned","client","createServerLog","launchChromeViewerCb","launchChromeViewer","join","handle","useEffect","onExit","useInput","input","key","handleCredentialsDone","result","profile","saveConfig","createProxyLog","entry","h","proxyLogEntryToString","n","createBuildLog","message","triggerBuild","runBuild","bundleSize","formatBytes","err","PluginValidationError","watcher","watch","_","filename","normalized","prefix","viewerPath","getViewerPath","fileExists","viewerBuilt","handler","createRequestHandler","server","createServer","wss","WebSocketServer","ws","CredentialSetupUI","elapsedSeconds","elapsedLabel","buildErrorCount","issue","Box","AppHeader","Text","Spinner","ValidationIssues","log","index","i","runSetupUI","initialMode","resolve","unmountFn","handleComplete","result","unmount","render","createElement","CredentialSetupUI","devCommand","program","options","port","pluginDir","outputDir","ensureGitignore","credentials","credentialMode","activeCredentialProfile","lastPath","loadConfig","loadCredentialsFromFile","config","loadCredentialProfile","loadGlobalCredentials","profile","saveConfig","verbose","debug","autoViewer","cacheEnabled","waitUntilExit","DevUI","createElement","render","useCallback","useEffect","useState","Box","Text","useApp","useInput","encrypt","serializeEnvelope","isConnRefused","err","e","authHeaders","credentials","wizardFetch","wizardBase","path","init","getProxyEnvStatus","PROXY_UNAVAILABLE_HINT","readJsonSafe","res","text","parsed","fetchPublicKey","ctx","apiName","resolveWizardBase","data","errMsg","encryptLocally","publicKeyPem","value","envelope","encrypt","serialized","serializeEnvelope","encryptRemote","encryptSecret","onPhase","publicKey","Fragment","jsx","jsxs","Hint","text","Text","EncryptUI","ctx","stageDefaulted","credentialsPath","initialApiName","defaultApiName","initialValue","onDone","app","useApp","phase","setPhase","useState","credentials","setCredentials","apiName","setApiName","secret","setSecret","fail","useCallback","err","runEncryption","creds","name","value","envelopeValue","encryptSecret","p","envelope","copied","copyToClipboard","proceed","handleProfileChosen","profile","loadGlobalCredentials","loadCredentialProfile","useEffect","loadCredentialsFromFile","profiles","listCredentialProfiles","only","useInput","input","key","cursor","selected","buffer","modeLabel","stageLabel","frame","children","Box","AppHeader","Spinner","i","readFile","writeFile","join","envelopeObject","value","compactEnvelope","writeEnvelopeFile","path","DEFAULT_STAGE","isValidStage","stage","invalidStageMessage","resolveStage","defaultStageNotice","readManifestDefaults","cwd","raw","parsed","manifest","apiName","stripTrailingNewlines","readStdin","chunks","chunk","runHeadless","ctx","options","defaults","stageWasDefaulted","deps","credentials","apiName","defaultStageNotice","value","stripTrailingNewlines","envelopeValue","compactEnvelope","err","encryptCommand","program","options","isValidStage","invalidStageMessage","defaults","readManifestDefaults","stage","stageWasDefaulted","resolveStage","ctx","runHeadless","loadCredentialsFromFile","loadGlobalCredentials","encryptSecret","readStdin","text","writeEnvelopeFile","code","err","envelopeValue","waitUntilExit","render","createElement","EncryptUI","value","VALID_ICONS","VALID_ICONS_LIST","CUSTOM_ICON_NAMES","ALL_VALID_ICONS_LIST","iconsCommand","program","name","ALL_VALID_ICONS_LIST","mkdir","writeFile","readFile","join","SENSITIVE_FIELDS","redactServices","services","svc","s","redacted","k","buildTree","files","root","file","parts","node","part","i","next","sortTreeChildren","a","b","fileId","path","esc","str","fileExt","idx","LANG_MAP","mdLang","mdFence","content","longestRun","max","m","renderTextTree","prefix","sorted","child","isLast","connector","childPrefix","LICENSE_FILE","filterSourceFiles","f","buildFilteredConfig","manifest","v","IMAGE_MIME","renderTree","renderFileSection","body","generateMarkdown","filtered","name","version","description","sourceFiles","lines","configJson","configFence","fence","generateHtml","treeHtml","fileSections","EXAMPLES_DIR","join","GLOBAL_CREDENTIALS_DIR","reportCommand","program","options","pluginDir","manifest","raw","readFile","parsed","apiName","htmlPath","mdPath","files","readLocalFiles","mkdir","writeFile","generateHtml","generateMarkdown","setupClaudeCommand","program","options","runSetupClaude","readVersion","pkgPath","join","dirname","fileURLToPath","readFileSync","createProgram","program","Command","createCommand","setupClaudeCommand","buildCommand","devCommand","encryptCommand","reportCommand","iconsCommand","blockCommand","applyProxyFromEnv","http","createProgram"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/lib/proxyEnv.ts","../src/program.ts","../src/commands/block.ts","../src/lib/clipboard.ts","../src/lib/exportBlock.ts","../src/lib/runBuild.ts","../src/lib/readFiles.ts","../src/lib/formatValidationIssues.ts","../src/lib/pushHeadless.ts","../shared/lib/kizenUrls.ts","../src/lib/config.ts","../src/lib/credentials.ts","../shared/lib/credentials.ts","../src/lib/gitignore.ts","../src/lib/kizenClient.ts","../src/lib/pushBlock.ts","../src/lib/setupClaude.ts","raw:/Users/keegan/Developer/app-builder/src/templates/claude/skills/kizen-custom-block/SKILL.md?raw","raw:/Users/keegan/Developer/app-builder/src/templates/claude/skills/kizen-custom-block/design.md?raw","raw:/Users/keegan/Developer/app-builder/src/templates/github/copilot-instructions.md?raw","raw:/Users/keegan/Developer/app-builder/src/templates/github/instructions/security.instructions.md?raw","raw:/Users/keegan/Developer/app-builder/src/templates/github/instructions/version-discipline.instructions.md?raw","raw:/Users/keegan/Developer/app-builder/src/templates/plugin/lib/kizenData.js?raw","../src/lib/createCopilotFiles.ts","../src/ui/PushUI.tsx","../src/ui/AppHeader.tsx","../src/ui/Logo.tsx","../src/ui/SelectList.tsx","../src/lib/moveCursor.ts","../src/ui/Spinner.tsx","../src/commands/build.ts","../src/ui/BuildUI.tsx","../shared/lib/formatBytes.ts","../src/ui/ValidationIssues.tsx","../src/commands/create.ts","../src/ui/CreateUI.tsx","../src/lib/createPlugin.ts","raw:/Users/keegan/Developer/app-builder/src/templates/artifacts/floatingFrames/helloFrame/config.json?raw","raw:/Users/keegan/Developer/app-builder/src/templates/artifacts/floatingFrames/helloFrame/script.js?raw","raw:/Users/keegan/Developer/app-builder/src/templates/artifacts/floatingFrames/helloFrame/styles.css?raw","raw:/Users/keegan/Developer/app-builder/src/templates/artifacts/blocks/helloBlock/config.json?raw","raw:/Users/keegan/Developer/app-builder/src/templates/artifacts/blocks/helloBlock/script.js?raw","raw:/Users/keegan/Developer/app-builder/src/templates/artifacts/blocks/helloBlock/styles.css?raw","raw:/Users/keegan/Developer/app-builder/src/templates/artifacts/dataAdornments/helloAdornment/config.json?raw","raw:/Users/keegan/Developer/app-builder/src/templates/artifacts/dataAdornments/helloAdornment/script.js?raw","raw:/Users/keegan/Developer/app-builder/src/templates/artifacts/pages/helloPage/config.json?raw","raw:/Users/keegan/Developer/app-builder/src/templates/artifacts/pages/helloPage/script.js?raw","raw:/Users/keegan/Developer/app-builder/src/templates/artifacts/pages/helloPage/styles.css?raw","raw:/Users/keegan/Developer/app-builder/src/templates/artifacts/pages/helloPage/eventScripts/greet.js?raw","raw:/Users/keegan/Developer/app-builder/src/templates/artifacts/toolbarItems/helloToolbarItem/config.json?raw","raw:/Users/keegan/Developer/app-builder/src/templates/artifacts/toolbarItems/helloToolbarItem/script.js?raw","raw:/Users/keegan/Developer/app-builder/src/templates/artifacts/objectSettingsItems/helloObjectSettingsItem/config.json?raw","raw:/Users/keegan/Developer/app-builder/src/templates/artifacts/objectSettingsItems/helloObjectSettingsItem/script.js?raw","raw:/Users/keegan/Developer/app-builder/src/templates/artifacts/actions/helloAction/config.json?raw","raw:/Users/keegan/Developer/app-builder/src/templates/artifacts/actions/helloAction/script.js?raw","../src/lib/createArtifacts.ts","../src/lib/createThumbnail.ts","../src/lib/createForm.ts","../src/lib/createHeadless.ts","../src/commands/dev.ts","../src/ui/DevUI.tsx","../src/server/requestHandler.ts","../src/lib/proxyCache.ts","../src/lib/constants.ts","../src/lib/wizardUrl.ts","../src/server/pythonExecutor.ts","../src/server/python-requirements.txt","../src/lib/pythonRuntime.ts","../shared/lib/execution.ts","../shared/lib/fileExtensions.ts","../shared/lib/proxy.ts","../src/chrome/launcher.ts","../src/hooks/useLogHistory.ts","../src/ui/CredentialSetupUI.tsx","../src/commands/encrypt.ts","../src/ui/EncryptUI.tsx","../src/lib/encryptionClient.ts","../src/lib/encryptHelpers.ts","../src/lib/encryptHeadless.ts","../shared/lib/validIcons.ts","../src/commands/icons.ts","../src/commands/report.ts","../src/lib/reportHelpers.ts","../src/commands/setupClaude.ts"],"sourcesContent":["import * as http from 'node:http';\nimport { applyProxyFromEnv } from './lib/proxyEnv.js';\nimport { createProgram } from './program.js';\n\napplyProxyFromEnv({ env: process.env, http });\n\ncreateProgram().parse();\n","export type ProxyEnvStatus = 'applied' | 'unavailable' | 'not-configured' | 'already-set';\n\nexport interface ProxyHttp {\n setGlobalProxyFromEnv?: (proxyEnv?: NodeJS.ProcessEnv) => unknown;\n}\n\nexport interface ApplyProxyFromEnvOptions {\n env: NodeJS.ProcessEnv;\n http: ProxyHttp;\n}\n\nexport const PROXY_UNAVAILABLE_HINT =\n \"If you're behind a proxy, upgrade Node to 24.14+ or set NODE_USE_ENV_PROXY=1 on a Node version that supports it.\";\n\nconst PROXY_VARS = ['HTTPS_PROXY', 'https_proxy', 'HTTP_PROXY', 'http_proxy'] as const;\n\nconst isSet = (value: string | undefined): boolean => value !== undefined && value !== '';\n\nlet status: ProxyEnvStatus = 'not-configured';\n\nexport function applyProxyFromEnv({ env, http }: ApplyProxyFromEnvOptions): ProxyEnvStatus {\n if (status === 'applied') {\n return status;\n }\n\n if (!PROXY_VARS.some((name) => isSet(env[name]))) {\n status = 'not-configured';\n } else if (isSet(env.NODE_USE_ENV_PROXY)) {\n status = 'already-set';\n } else if (typeof http.setGlobalProxyFromEnv !== 'function') {\n status = 'unavailable';\n } else {\n http.setGlobalProxyFromEnv(env);\n status = 'applied';\n }\n\n return status;\n}\n\nexport const getProxyEnvStatus = (): ProxyEnvStatus => status;\n","import { readFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { Command } from 'commander';\nimport { blockCommand } from './commands/block.js';\nimport { buildCommand } from './commands/build.js';\nimport { createCommand } from './commands/create.js';\nimport { devCommand } from './commands/dev.js';\nimport { encryptCommand } from './commands/encrypt.js';\nimport { iconsCommand } from './commands/icons.js';\nimport { reportCommand } from './commands/report.js';\nimport { setupClaudeCommand } from './commands/setupClaude.js';\n\nfunction readVersion(): string {\n const pkgPath = join(dirname(fileURLToPath(import.meta.url)), '..', 'package.json');\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8')) as { version: string };\n\n return pkg.version;\n}\n\nexport function createProgram(): Command {\n const program = new Command();\n\n program.name('appbuilder').description('Kizen plugin app builder').version(readVersion());\n\n createCommand(program);\n\n setupClaudeCommand(program);\n\n buildCommand(program);\n\n devCommand(program);\n\n encryptCommand(program);\n\n reportCommand(program);\n\n iconsCommand(program);\n\n blockCommand(program);\n\n return program;\n}\n","import { createElement } from 'react';\nimport { render } from 'ink';\nimport type { Command } from 'commander';\nimport { PluginValidationError } from '@kizenapps/packager';\nimport { copyToClipboard } from '../lib/clipboard.js';\nimport { exportBlock } from '../lib/exportBlock.js';\nimport { formatValidationIssues } from '../lib/formatValidationIssues.js';\nimport {\n createDefaultPushDeps,\n runPushHeadless,\n runTargetsHeadless,\n type PushCommandOptions,\n type TargetsCommandOptions,\n} from '../lib/pushHeadless.js';\nimport { PushUI } from '../ui/PushUI.js';\n\nconst describeError = (error: unknown): string => {\n if (error instanceof PluginValidationError) {\n return formatValidationIssues(error.issues);\n }\n\n return `Error: ${error instanceof Error ? error.message : String(error)}`;\n};\n\nexport function blockCommand(program: Command): void {\n const block = program.command('block').description('Work with plugin content blocks');\n\n block\n .command('export')\n .description('Print one packaged block as JSON for the Custom Block (AI Coded) paste editor')\n .argument('[api_name]', 'api_name of the block to export (optional when there is only one)')\n .option('--copy', 'also copy the JSON to the clipboard')\n .action(async (apiName: string | undefined, options: { copy?: boolean }) => {\n try {\n const { block: exported, warnings } = await exportBlock(process.cwd(), apiName);\n\n if (warnings.length > 0) {\n console.error(formatValidationIssues(warnings));\n }\n\n const json = JSON.stringify(exported, null, 2);\n\n console.log(json);\n\n if (options.copy) {\n console.error(\n (await copyToClipboard(json))\n ? `Copied block \"${exported.api_name}\" to the clipboard.`\n : \"Couldn't copy to the clipboard; use the JSON printed to stdout instead.\",\n );\n }\n } catch (error) {\n console.error(describeError(error));\n process.exitCode = 1;\n }\n });\n block\n .command('push')\n .description('Push a block to a Kizen dashboard, homepage or chart group dashlet')\n .argument('[api_name]', 'api_name of the block to push (optional when there is only one)')\n .option('-c, --credentials <path>', 'path to a credentials JSON file')\n .option('--profile <name>', 'stored credential profile to use')\n .option('--dashboard <id>', 'dashboard, homepage or chart group to push to')\n .option('--dashlet <id>', 'existing custom code dashlet to update (needs --dashboard)')\n .option('--create', 'create a new dashlet instead of updating one')\n .option('--dry-run', 'show the request without writing anything')\n .option('--yes', 'write without asking (headless runs are dry runs without it)')\n .option('--allow-production', 'allow headless writes to go/fmo')\n .option('--force', 'overwrite even if the block was edited in Kizen since the last push')\n .option('--forget', 'clear the remembered target for this block first')\n .option('--json', 'print a JSON result to stdout (always headless)')\n .action(async (apiName: string | undefined, options: PushCommandOptions) => {\n try {\n if (!process.stdin.isTTY || !process.stdout.isTTY || options.json === true) {\n await runPushHeadless(apiName, options, createDefaultPushDeps(process.cwd()));\n\n return;\n }\n\n const { waitUntilExit } = render(\n createElement(PushUI, {\n ...(apiName !== undefined && { apiName }),\n options,\n deps: createDefaultPushDeps(process.cwd()),\n }),\n { exitOnCtrlC: false },\n );\n\n await waitUntilExit();\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exitCode = 1;\n }\n });\n\n block\n .command('targets')\n .description('List the dashboards, homepages and chart groups a block can be pushed to')\n .option('-c, --credentials <path>', 'path to a credentials JSON file')\n .option('--profile <name>', 'stored credential profile to use')\n .option('--object <id>', 'list the chart groups of this custom object')\n .option('--json', 'print a JSON result to stdout')\n .action(async (options: TargetsCommandOptions) => {\n try {\n await runTargetsHeadless(options, createDefaultPushDeps(process.cwd()));\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exitCode = 1;\n }\n });\n}\n","/**\n * Best-effort system-clipboard copy with no third-party dependency. Used by the\n * `encrypt` command so the user can paste the envelope without the terminal's\n * soft-wrapping turning into real line breaks in the copied text.\n *\n * Only the encrypted envelope (ciphertext) is ever copied — never a plaintext\n * secret — so writing it to the clipboard is safe.\n */\nimport { spawn } from 'node:child_process';\nimport { platform } from 'node:process';\n\ninterface ClipboardCommand {\n cmd: string;\n args: string[];\n}\n\n/**\n * Clipboard tools to try, in order, for the current platform. Linux/other has\n * several candidates (Wayland first, then X11) since none is guaranteed.\n */\nfunction clipboardCommands(): ClipboardCommand[] {\n if (platform === 'darwin') {\n return [{ cmd: 'pbcopy', args: [] }];\n }\n\n if (platform === 'win32') {\n return [{ cmd: 'clip', args: [] }];\n }\n\n return [\n // wl-copy (Wayland) intentionally WITHOUT --foreground: the default forks a\n // background process that keeps serving the selection after this CLI exits.\n // --foreground would instead tie the selection to our process, so the 2s\n // kill-timeout below would terminate it and wipe the clipboard.\n { cmd: 'wl-copy', args: [] },\n { cmd: 'xclip', args: ['-selection', 'clipboard'] },\n { cmd: 'xsel', args: ['--clipboard', '--input'] },\n ];\n}\n\n/** How long to wait for a clipboard tool before giving up. Encryption has\n * already succeeded by the time we copy, so a tool that hangs (some Linux\n * xclip/xsel setups can) must never freeze the CLI — it just falls back. */\nconst CLIPBOARD_TIMEOUT_MS = 2000;\n\n/** Pipes `text` into one clipboard command. Resolves false (never rejects) on\n * any failure — a missing tool (ENOENT), a non-zero exit, a broken pipe, or a\n * tool that doesn't exit within the timeout. */\nfunction runClipboardCommand(text: string, { cmd, args }: ClipboardCommand): Promise<boolean> {\n return new Promise((resolve) => {\n let child;\n\n try {\n child = spawn(cmd, args, { stdio: ['pipe', 'ignore', 'ignore'] });\n } catch {\n // Spawn threw synchronously (e.g. invalid command) — nothing to clean up.\n resolve(false);\n\n return;\n }\n\n const spawned = child;\n let settled = false;\n\n function finish(ok: boolean): void {\n if (settled) {\n return;\n }\n\n settled = true;\n clearTimeout(timer);\n resolve(ok);\n }\n\n const timer = setTimeout(() => {\n spawned.kill();\n finish(false);\n }, CLIPBOARD_TIMEOUT_MS);\n\n // Don't let a pending clipboard timer keep the process alive on its own.\n timer.unref();\n\n spawned.on('error', () => {\n finish(false);\n });\n spawned.on('close', (code) => {\n finish(code === 0);\n });\n spawned.stdin.on('error', () => {\n finish(false);\n });\n\n try {\n spawned.stdin.end(text);\n } catch {\n finish(false);\n }\n });\n}\n\n/**\n * Copies `text` to the system clipboard, returning whether it succeeded. Tries\n * each platform candidate until one works; returns false if none is available.\n */\nexport async function copyToClipboard(text: string): Promise<boolean> {\n for (const command of clipboardCommands()) {\n if (await runClipboardCommand(text, command)) {\n return true;\n }\n }\n\n return false;\n}\n","import {\n BLOCKS_DIRECTORY_NAME,\n CONFIG_FILE_NAME,\n MANIFEST_FILE_NAME,\n sanitizeToAPIName,\n} from '@kizenapps/packager';\nimport type { Block, DeployablePlugin, FileContent, ValidationIssue } from '@kizenapps/packager';\nimport { packageLocalPlugin } from './runBuild.js';\n\nexport type BlockSelectionFailure = 'not_found' | 'ambiguous' | 'no_blocks';\n\nexport type BlockExportReason = BlockSelectionFailure | 'invalid_block';\n\nexport interface AvailableBlock {\n pluginApiName: string;\n apiName: string;\n}\n\nexport type BlockSelection =\n | { ok: true; block: Block; pluginApiName: string }\n | { ok: false; reason: BlockSelectionFailure; available: AvailableBlock[] };\n\nexport interface ExportedBlock {\n block: Block;\n pluginApiName: string;\n warnings: ValidationIssue[];\n}\n\nconst DIMENSION_FIELDS = ['min_w', 'max_w', 'min_h', 'max_h'] as const;\n\nconst DIMENSION_RANGES = [\n ['min_w', 'max_w'],\n ['min_h', 'max_h'],\n] as const;\n\nconst DEFAULT_SIZE_BOUNDS = {\n default_w: ['min_w', 'max_w'],\n default_h: ['min_h', 'max_h'],\n} as const;\n\ntype DefaultSizeField = keyof typeof DEFAULT_SIZE_BOUNDS;\n\nconst DEFAULT_SIZE_FIELDS = Object.keys(DEFAULT_SIZE_BOUNDS) as DefaultSizeField[];\n\nconst SIZE_FIELDS = [...DIMENSION_FIELDS, ...DEFAULT_SIZE_FIELDS] as const;\n\nconst AUTHORED_FIELDS = [...SIZE_FIELDS, 'host_chrome'] as const;\n\ntype AuthoredField = (typeof AUTHORED_FIELDS)[number];\n\nconst UNSUPPORTED_SEQUENCES = ['\\u0000', '{__ref:'];\n\nexport class BlockExportError extends Error {\n readonly reason: BlockExportReason;\n readonly available: AvailableBlock[];\n readonly field: string | undefined;\n\n constructor(\n reason: BlockExportReason,\n message: string,\n options: { available?: AvailableBlock[]; field?: string } = {},\n ) {\n super(message);\n this.name = 'BlockExportError';\n this.reason = reason;\n this.available = options.available ?? [];\n this.field = options.field;\n }\n}\n\nexport function formatAvailableBlocks(available: AvailableBlock[]): string {\n const multiplePlugins = new Set(available.map((entry) => entry.pluginApiName)).size > 1;\n\n return available\n .map((entry) => (multiplePlugins ? `${entry.pluginApiName}/${entry.apiName}` : entry.apiName))\n .join(', ');\n}\n\nexport function selectBlock(deployable: DeployablePlugin[], apiName?: string): BlockSelection {\n const candidates = deployable.flatMap((plugin) =>\n plugin.artifacts.custom_blocks.map((block) => ({ block, pluginApiName: plugin.api_name })),\n );\n const available = candidates.map(({ block, pluginApiName }) => ({\n pluginApiName,\n apiName: block.api_name,\n }));\n\n if (candidates.length === 0) {\n return { ok: false, reason: 'no_blocks', available };\n }\n\n if (apiName === undefined) {\n const [only] = candidates;\n\n return candidates.length === 1 && only\n ? { ok: true, ...only }\n : { ok: false, reason: 'ambiguous', available };\n }\n\n const matches = candidates.filter(({ block }) => block.api_name === apiName);\n const [match] = matches;\n\n if (!match) {\n return { ok: false, reason: 'not_found', available };\n }\n\n if (matches.length > 1) {\n return {\n ok: false,\n reason: 'ambiguous',\n available: matches.map(({ block, pluginApiName }) => ({\n pluginApiName,\n apiName: block.api_name,\n })),\n };\n }\n\n return { ok: true, ...match };\n}\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value);\n\nconst isPositiveInteger = (value: unknown): boolean =>\n typeof value === 'number' && Number.isInteger(value) && value > 0;\n\nconst hasUnsupportedContent = (value: string): boolean =>\n UNSUPPORTED_SEQUENCES.some((sequence) => value.includes(sequence));\n\nexport function findInvalidBlockField(block: Block): string | undefined {\n const raw = block as unknown as Record<string, unknown>;\n const { name, script, styles, event_scripts: eventScripts } = raw;\n\n if (typeof script !== 'string' || !script.trim()) {\n return 'script';\n }\n\n if (name !== undefined && typeof name !== 'string') {\n return 'name';\n }\n\n if (styles !== undefined && typeof styles !== 'string') {\n return 'styles';\n }\n\n if (eventScripts !== undefined) {\n if (!isRecord(eventScripts)) {\n return 'event_scripts';\n }\n\n const invalidEntry = Object.entries(eventScripts).find(\n ([eventName, body]) =>\n typeof body !== 'string' || hasUnsupportedContent(eventName) || hasUnsupportedContent(body),\n );\n\n if (invalidEntry) {\n return `event_scripts.${invalidEntry[0]}`;\n }\n }\n\n const unsupported = (\n [\n ['name', name],\n ['script', script],\n ['styles', styles],\n ] as const\n ).find(([, value]) => typeof value === 'string' && hasUnsupportedContent(value));\n\n if (unsupported) {\n return unsupported[0];\n }\n\n const invalidDimension = DIMENSION_FIELDS.find(\n (field) => raw[field] !== undefined && !isPositiveInteger(raw[field]),\n );\n\n if (invalidDimension) {\n return invalidDimension;\n }\n\n const invertedMin = DIMENSION_RANGES.find(([minField, maxField]) => {\n const min = raw[minField];\n const max = raw[maxField];\n\n return typeof min === 'number' && typeof max === 'number' && min > max;\n });\n\n if (invertedMin) {\n return invertedMin[0];\n }\n\n const invalidDefault = DEFAULT_SIZE_FIELDS.find((field) => {\n const value = raw[field];\n\n if (value === undefined) {\n return false;\n }\n\n if (typeof value !== 'number' || !isPositiveInteger(value)) {\n return true;\n }\n\n const [minField, maxField] = DEFAULT_SIZE_BOUNDS[field];\n const min = raw[minField];\n const max = raw[maxField];\n\n return (typeof min === 'number' && value < min) || (typeof max === 'number' && value > max);\n });\n\n if (invalidDefault) {\n return invalidDefault;\n }\n\n if (raw.host_chrome !== undefined && typeof raw.host_chrome !== 'boolean') {\n return 'host_chrome';\n }\n\n return undefined;\n}\n\nexport const invalidBlockMessage = (apiName: string, field: string): string => {\n if (field === 'script') {\n return `Block \"${apiName}\" has no script. Add a non-empty script.js to the block directory.`;\n }\n\n if (field === 'host_chrome') {\n return `Block \"${apiName}\" has an invalid host_chrome: it must be true or false.`;\n }\n\n const range = DIMENSION_RANGES.find(([minField]) => minField === field);\n\n if (range) {\n return `Block \"${apiName}\" has an invalid ${field}: it must be a positive integer no greater than ${range[1]}.`;\n }\n\n if ((DIMENSION_FIELDS as readonly string[]).includes(field)) {\n return `Block \"${apiName}\" has an invalid ${field}: it must be a positive integer.`;\n }\n\n if (field in DEFAULT_SIZE_BOUNDS) {\n const [minField, maxField] = DEFAULT_SIZE_BOUNDS[field as DefaultSizeField];\n\n return `Block \"${apiName}\" has an invalid ${field}: it must be a positive integer between ${minField} and ${maxField}.`;\n }\n\n return `Block \"${apiName}\" has an invalid ${field}: it must be a string without NUL characters or \"{__ref:\".`;\n};\n\nexport const selectionError = (\n selection: Extract<BlockSelection, { ok: false }>,\n apiName: string | undefined,\n): BlockExportError => {\n const { reason, available } = selection;\n const list = formatAvailableBlocks(available);\n\n if (reason === 'no_blocks') {\n return new BlockExportError(\n reason,\n 'This plugin has no blocks. Scaffold one with `appbuilder create --artifacts block`.',\n { available },\n );\n }\n\n if (reason === 'not_found') {\n return new BlockExportError(\n reason,\n `No block with api_name \"${apiName ?? ''}\". Available blocks: ${list}`,\n { available },\n );\n }\n\n return new BlockExportError(\n reason,\n apiName === undefined\n ? `This plugin has several blocks; pass the api_name of the one to export: ${list}`\n : `More than one plugin has a block with api_name \"${apiName}\": ${list}`,\n { available },\n );\n};\n\nconst parseJsonRecord = (content: string): Record<string, unknown> | undefined => {\n try {\n const parsed: unknown = JSON.parse(content);\n\n return isRecord(parsed) ? parsed : undefined;\n } catch {\n return undefined;\n }\n};\n\nconst manifestEntries = (files: readonly FileContent[]): Map<string, string> => {\n const manifestFile = files.find((file) => file.path === MANIFEST_FILE_NAME);\n const parsed: unknown = manifestFile ? JSON.parse(manifestFile.content) : [];\n const manifests: unknown[] = Array.isArray(parsed) ? parsed : [parsed];\n const entries = new Map<string, string>();\n\n for (const manifest of manifests) {\n if (\n isRecord(manifest) &&\n typeof manifest.api_name === 'string' &&\n typeof manifest.entry === 'string'\n ) {\n entries.set(manifest.api_name, manifest.entry);\n }\n }\n\n return entries;\n};\n\nconst authoredBlockConfig = (\n files: readonly FileContent[],\n entry: string,\n): Map<string, Partial<Record<AuthoredField, unknown>>> => {\n const prefix = `${entry.replace(/\\/+$/, '')}/${BLOCKS_DIRECTORY_NAME}/`;\n const authoredByApiName = new Map<string, Partial<Record<AuthoredField, unknown>>>();\n\n for (const file of files) {\n if (!file.path.startsWith(prefix)) {\n continue;\n }\n\n const [directory, fileName, ...rest] = file.path.slice(prefix.length).split('/');\n\n if (!directory || fileName !== CONFIG_FILE_NAME || rest.length > 0) {\n continue;\n }\n\n const config = parseJsonRecord(file.content);\n\n if (!config) {\n continue;\n }\n\n const apiName =\n typeof config.api_name === 'string' && config.api_name !== ''\n ? config.api_name\n : sanitizeToAPIName(directory);\n const authored: Partial<Record<AuthoredField, unknown>> = {};\n\n for (const field of AUTHORED_FIELDS) {\n if (config[field] !== undefined) {\n authored[field] = config[field];\n }\n }\n\n authoredByApiName.set(apiName, authored);\n }\n\n return authoredByApiName;\n};\n\nconst withAuthoredConfig = (\n block: Block,\n authored: Partial<Record<AuthoredField, unknown>> = {},\n): Block => {\n const packaged = Object.fromEntries(\n Object.entries(block).filter(([key]) => !(AUTHORED_FIELDS as readonly string[]).includes(key)),\n );\n\n return { ...packaged, ...authored } as unknown as Block;\n};\n\nexport function applyAuthoredConfig(\n deployable: DeployablePlugin[],\n files: readonly FileContent[],\n): DeployablePlugin[] {\n const entries = manifestEntries(files);\n\n return deployable.map((plugin) => {\n const entry = entries.get(plugin.api_name);\n const authored =\n entry === undefined\n ? new Map<string, Partial<Record<AuthoredField, unknown>>>()\n : authoredBlockConfig(files, entry);\n\n return {\n ...plugin,\n artifacts: {\n ...plugin.artifacts,\n custom_blocks: plugin.artifacts.custom_blocks.map((block) =>\n withAuthoredConfig(block, authored.get(block.api_name)),\n ),\n },\n };\n });\n}\n\nexport async function packageBlocks(\n pluginDir: string,\n): Promise<{ deployable: DeployablePlugin[]; warnings: ValidationIssue[] }> {\n const { files, deployable, issues } = await packageLocalPlugin(pluginDir);\n\n return {\n deployable: applyAuthoredConfig(deployable, files),\n warnings: issues.filter((issue) => issue.severity === 'warning'),\n };\n}\n\nexport async function exportBlock(pluginDir: string, apiName?: string): Promise<ExportedBlock> {\n const { deployable, warnings } = await packageBlocks(pluginDir);\n const selection = selectBlock(deployable, apiName);\n\n if (!selection.ok) {\n throw selectionError(selection, apiName);\n }\n\n const invalidField = findInvalidBlockField(selection.block);\n\n if (invalidField !== undefined) {\n throw new BlockExportError(\n 'invalid_block',\n invalidBlockMessage(selection.block.api_name, invalidField),\n { field: invalidField },\n );\n }\n\n return { block: selection.block, pluginApiName: selection.pluginApiName, warnings };\n}\n","import { mkdir, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport {\n PluginValidationError,\n packagePlugin,\n parseManifestFromFiles,\n transformDeployablePlugin,\n transformFiles,\n validatePluginApp,\n} from '@kizenapps/packager';\nimport type { DeployablePlugin, FileContent, ValidationIssue } from '@kizenapps/packager';\nimport { readLocalFiles } from './readFiles.js';\n\nexport type BuildStepName =\n | 'creating-dir'\n | 'reading-files'\n | 'validating'\n | 'minifying'\n | 'packaging'\n | 'writing-bundle';\n\ninterface ReleaseNote {\n version: string;\n notes: string;\n}\n\ntype SerializableDeployablePlugin = Omit<DeployablePlugin, 'thumbnail' | 'kznFile'> & {\n thumbnail: string | null;\n kznFile: string | null;\n allReleaseNotes: ReleaseNote[];\n};\n\nconst serializePlugin = (\n plugin: DeployablePlugin,\n allReleaseNotes: ReleaseNote[],\n): SerializableDeployablePlugin => ({\n ...plugin,\n thumbnail: plugin.thumbnail ? Buffer.from(plugin.thumbnail).toString('base64') : null,\n kznFile: plugin.kznFile ? Buffer.from(plugin.kznFile).toString('base64') : null,\n allReleaseNotes,\n});\n\nexport interface BuildResult {\n bundleSize: number;\n}\n\nexport interface PackagedLocalPlugin {\n files: FileContent[];\n deployable: DeployablePlugin[];\n issues: ValidationIssue[];\n}\n\nexport async function packageLocalPlugin(\n pluginDir: string,\n onStep?: (step: BuildStepName) => void,\n): Promise<PackagedLocalPlugin> {\n onStep?.('reading-files');\n\n const files = await readLocalFiles(pluginDir);\n\n onStep?.('validating');\n\n const issues = validatePluginApp(files);\n\n if (issues.some((issue) => issue.severity === 'error')) {\n throw new PluginValidationError(issues);\n }\n\n onStep?.('minifying');\n\n const minified = await transformFiles(files);\n\n onStep?.('packaging');\n\n const manifests = parseManifestFromFiles(minified);\n const packaged = packagePlugin(minified, manifests);\n const deployable = Object.values(packaged).map(transformDeployablePlugin);\n\n return { files, deployable, issues };\n}\n\nexport async function runBuild(\n pluginDir: string,\n outputDir: string,\n onStep?: (step: BuildStepName) => void,\n): Promise<BuildResult> {\n await mkdir(outputDir, { recursive: true });\n\n const { files, deployable } = await packageLocalPlugin(pluginDir, onStep);\n\n onStep?.('writing-bundle');\n\n const bundle = deployable.map((plugin) => {\n const notesDir = plugin.release_notes_directory?.replace(/\\/$/, '');\n const allReleaseNotes: ReleaseNote[] = notesDir\n ? files\n .filter((f) => f.path.startsWith(notesDir + '/') && f.path.endsWith('.md') && f.content)\n .map((f) => ({\n version: f.path.slice(f.path.lastIndexOf('/') + 1, -3),\n notes: f.content,\n }))\n .sort((a, b) => b.version.localeCompare(a.version, undefined, { numeric: true }))\n : [];\n\n return serializePlugin(plugin, allReleaseNotes);\n });\n\n const jsonStr = JSON.stringify(bundle, null, 2);\n\n // Report the size of the plugin bundle excluding the informational release\n // notes, so \"bundle: 12KB\" reflects actual plugin code rather than long\n // markdown changelogs.\n const stripReleaseNotes = (key: string, value: unknown): unknown =>\n key === 'allReleaseNotes' ? undefined : value;\n const bundleSize = Buffer.byteLength(JSON.stringify(bundle, stripReleaseNotes, 2), 'utf-8');\n\n await writeFile(join(outputDir, 'bundle.json'), jsonStr, 'utf-8');\n\n return { bundleSize };\n}\n","import { readdir, readFile } from 'node:fs/promises';\nimport { join, relative } from 'node:path';\nimport type { FileContent } from '@kizenapps/packager';\n\nconst IMAGE_EXTENSIONS = new Set(['.png', '.svg']);\nconst BINARY_EXTENSIONS = new Set(['.kzn']);\nconst SKIP_FILES = new Set(['.DS_Store']);\n\nexport const SKIP_DIRS = new Set([\n 'node_modules',\n '.git',\n '.kizenapp',\n '.github',\n '.claude',\n '__pycache__',\n]);\n\n// a NUL in the first 8 KB means binary\nconst BINARY_SNIFF_BYTES = 8000;\n\nfunction looksBinary(buf: Buffer): boolean {\n return buf.subarray(0, BINARY_SNIFF_BYTES).includes(0);\n}\n\nexport interface ReadLocalFilesOptions {\n detectBinaryByContent?: boolean;\n}\n\nasync function walk(dir: string, rootDir: string): Promise<string[]> {\n const entries = await readdir(dir, { withFileTypes: true });\n const paths: string[] = [];\n\n for (const entry of entries) {\n if (entry.isDirectory()) {\n if (SKIP_DIRS.has(entry.name)) {\n continue;\n }\n\n paths.push(...(await walk(join(dir, entry.name), rootDir)));\n } else if (entry.isFile()) {\n if (!SKIP_FILES.has(entry.name)) {\n paths.push(join(dir, entry.name));\n }\n }\n }\n\n return paths;\n}\n\nexport async function readLocalFiles(\n rootDir: string,\n { detectBinaryByContent = false }: ReadLocalFilesOptions = {},\n): Promise<FileContent[]> {\n const absolutePaths = await walk(rootDir, rootDir);\n\n return Promise.all(\n absolutePaths.map(async (absPath): Promise<FileContent> => {\n const relPath = relative(rootDir, absPath).split('\\\\').join('/');\n const dotIndex = relPath.lastIndexOf('.');\n const ext = dotIndex >= 0 ? relPath.slice(dotIndex).toLowerCase() : '';\n\n if (IMAGE_EXTENSIONS.has(ext)) {\n const buf = await readFile(absPath);\n\n return { path: relPath, content: '', base64Image: buf.toString('base64') };\n }\n\n const buf = await readFile(absPath);\n\n if (BINARY_EXTENSIONS.has(ext) || (detectBinaryByContent && looksBinary(buf))) {\n return { path: relPath, content: '', binaryData: buf };\n }\n\n return { path: relPath, content: buf.toString('utf-8') };\n }),\n );\n}\n","import type { ValidationIssue } from '@kizenapps/packager';\n\nconst plural = (count: number, singular: string, pluralForm: string): string =>\n `${String(count)} ${count === 1 ? singular : pluralForm}`;\n\nconst groupIssuesByPath = (issues: ValidationIssue[]): Map<string, ValidationIssue[]> => {\n const groups = new Map<string, ValidationIssue[]>();\n\n for (const issue of issues) {\n const key = issue.path ?? issue.pluginApiName ?? 'general';\n const group = groups.get(key) ?? [];\n\n group.push(issue);\n groups.set(key, group);\n }\n\n return groups;\n};\n\nconst formatHeader = (issues: ValidationIssue[]): string => {\n const errorCount = issues.filter((issue) => issue.severity === 'error').length;\n const warningCount = issues.length - errorCount;\n\n if (errorCount === 0) {\n return `⚠ ${plural(warningCount, 'validation warning', 'validation warnings')}`;\n }\n\n const errors = `✗ ${plural(errorCount, 'validation error', 'validation errors')}`;\n\n return warningCount === 0 ? errors : `${errors}, ${plural(warningCount, 'warning', 'warnings')}`;\n};\n\nexport function formatValidationIssues(issues: ValidationIssue[]): string {\n if (issues.length === 0) {\n return '';\n }\n\n const sections = [...groupIssuesByPath(issues)].map(([path, group]) =>\n [\n path,\n ...group.map(\n (issue) => ` ${issue.severity === 'error' ? '✗' : '⚠'} ${issue.message} (${issue.rule})`,\n ),\n ].join('\\n'),\n );\n\n return [formatHeader(issues), ...sections].join('\\n\\n');\n}\n","import { randomUUID } from 'node:crypto';\nimport { join } from 'node:path';\nimport { PluginValidationError } from '@kizenapps/packager';\nimport type { Block, DeployablePlugin, ValidationIssue } from '@kizenapps/packager';\nimport { APP_URLS, isProductionEnvironment } from '../../shared/lib/kizenUrls.js';\nimport { loadConfig, type AppBuilderConfig } from './config.js';\nimport {\n ENVIRONMENTS,\n GLOBAL_CREDENTIALS_PATH,\n listLoadableCredentialProfiles,\n loadCredentialsDetailed,\n type CredentialProfile,\n type Credentials,\n type DetailedCredentials,\n type Environment,\n} from './credentials.js';\nimport {\n findInvalidBlockField,\n invalidBlockMessage,\n packageBlocks,\n selectBlock,\n formatAvailableBlocks,\n} from './exportBlock.js';\nimport { formatValidationIssues } from './formatValidationIssues.js';\nimport { ensureGitignore } from './gitignore.js';\nimport { createKizenClient, KizenApiError } from './kizenClient.js';\nimport type {\n CreateDashletBody,\n CustomCodeContent,\n KizenClient,\n PushMapEntry,\n Surface,\n UpdateDashletBody,\n WireCustomObject,\n WireDashboard,\n WireDashboardSummary,\n WireDashlet,\n} from './kizenTypes.js';\nimport {\n buildCreateBody,\n buildDashboardUrl,\n buildUpdateBody,\n canonicalContentHash,\n customCodeName,\n dashboardTypeToSurface,\n detectDrift,\n findCustomCodeDashlets,\n findPushMapEntry,\n isCustomCodeDashlet,\n matchPushTarget,\n parsePushKey,\n PUSH_MAP_RELATIVE_PATH,\n readPushMap,\n removePushMapEntry,\n toCustomCodeContent,\n upsertPushMapEntry,\n writePushMap,\n type PushMapKey,\n} from './pushBlock.js';\nimport { isClaudeSkillStale, STALE_CLAUDE_SKILL_WARNING } from './setupClaude.js';\n\nexport type PushErrorCode =\n | 'needs_choice'\n | 'validation_failed'\n | 'invalid_block'\n | 'auth_failed'\n | 'forbidden'\n | 'remembered_target_missing'\n | 'drift_detected'\n | 'network_error'\n | 'credentials_invalid'\n | 'production_requires_flag'\n | 'not_found'\n | 'usage_error'\n | 'api_error'\n | 'local_error';\n\nexport type ChoiceKind = 'profile' | 'block' | 'dashboard' | 'target';\n\nexport interface PushChoice {\n value: string;\n label: string;\n args: string[];\n surface?: Surface;\n canEdit?: boolean | null;\n pushKey?: string | null;\n isFromThisPlugin?: boolean;\n}\n\nexport interface PushFailure {\n ok: false;\n code: PushErrorCode;\n message: string;\n choice?: ChoiceKind;\n choices?: PushChoice[];\n issues?: ValidationIssue[];\n field?: string;\n hint?: string;\n}\n\nexport type Step<T> = { ok: true; value: T } | PushFailure;\n\nexport interface PushCommandOptions {\n credentials?: string;\n profile?: string;\n dashboard?: string;\n dashlet?: string;\n create?: boolean;\n dryRun?: boolean;\n yes?: boolean;\n allowProduction?: boolean;\n force?: boolean;\n forget?: boolean;\n json?: boolean;\n}\n\nexport interface TargetsCommandOptions {\n credentials?: string;\n profile?: string;\n object?: string;\n json?: boolean;\n}\n\nexport interface PushDeps {\n cwd: string;\n loadCredentialsDetailed: (path: string) => Promise<DetailedCredentials>;\n listLoadableCredentialProfiles: () => Promise<CredentialProfile[]>;\n loadConfig: (outputDir: string) => Promise<AppBuilderConfig>;\n packageBlocks: (\n dir: string,\n ) => Promise<{ deployable: DeployablePlugin[]; warnings: ValidationIssue[] }>;\n createClient: (credentials: Credentials) => KizenClient;\n readPushMap: (dir: string) => Promise<PushMapEntry[]>;\n writePushMap: (dir: string, entries: readonly PushMapEntry[]) => Promise<void>;\n ensureGitignore: (dir: string) => void;\n isClaudeSkillStale: (dir: string) => Promise<boolean>;\n randomUUID: () => string;\n now: () => Date;\n writeStdout: (text: string) => void;\n writeStderr: (text: string) => void;\n setExitCode: (code: number) => void;\n}\n\nexport function createDefaultPushDeps(cwd: string): PushDeps {\n return {\n cwd,\n loadCredentialsDetailed,\n listLoadableCredentialProfiles,\n loadConfig,\n packageBlocks,\n createClient: (credentials) => createKizenClient({ credentials }),\n readPushMap,\n writePushMap,\n ensureGitignore,\n isClaudeSkillStale: (dir) => isClaudeSkillStale(dir),\n randomUUID,\n now: () => new Date(),\n writeStdout: (text) => {\n process.stdout.write(text);\n },\n writeStderr: (text) => {\n process.stderr.write(text);\n },\n setExitCode: (code) => {\n process.exitCode = code;\n },\n };\n}\n\nconst EDIT_ACCESS_LEVELS = new Set(['owner', 'admin', 'edit']);\n\nconst CHART_GROUP_HINT =\n 'Chart groups are not listed here; find them with `appbuilder block targets --object <id> --json` and pass --dashboard <id>.';\n\nconst errorMessage = (error: unknown): string =>\n error instanceof Error ? error.message : typeof error === 'string' ? error : 'Unknown error';\n\nfunction failure(\n code: PushErrorCode,\n message: string,\n extra: Omit<PushFailure, 'ok' | 'code' | 'message'> = {},\n): PushFailure {\n return { ok: false, code, message, ...extra };\n}\n\nconst success = <T>(value: T): Step<T> => ({ ok: true, value });\n\nexport function apiFailure(error: unknown): PushFailure {\n if (error instanceof KizenApiError) {\n return failure(error.kind, error.message, error.hint === undefined ? {} : { hint: error.hint });\n }\n\n if (error instanceof PluginValidationError) {\n return failure('validation_failed', formatValidationIssues(error.issues), {\n issues: error.issues,\n });\n }\n\n return failure('local_error', errorMessage(error));\n}\n\nexport interface ResolvedCredentials {\n credentials: Credentials;\n source: { kind: 'file'; path: string } | { kind: 'profile'; name: string; path: string };\n}\n\nconst environmentList = (): string => ENVIRONMENTS.join(', ');\n\nasync function loadCredentialSource(\n source: ResolvedCredentials['source'],\n deps: PushDeps,\n): Promise<Step<ResolvedCredentials>> {\n let detailed: DetailedCredentials;\n\n try {\n detailed = await deps.loadCredentialsDetailed(source.path);\n } catch (error) {\n return failure(\n 'credentials_invalid',\n `Couldn't read credentials from ${source.path}: ${errorMessage(error)}`,\n );\n }\n\n if (detailed.environmentSource !== 'explicit') {\n const problem =\n detailed.environmentSource === 'missing'\n ? 'has no \"environment\"'\n : 'has an invalid \"environment\"';\n\n return failure(\n 'credentials_invalid',\n `${source.path} ${problem}. Set it to one of: ${environmentList()}. The CLI won't default to production.`,\n );\n }\n\n const { credentials } = detailed;\n const empty = (['apiKey', 'userId', 'businessId'] as const).filter(\n (field) => credentials[field].trim() === '',\n );\n\n if (empty.length > 0) {\n return failure(\n 'credentials_invalid',\n `${source.path} is missing ${empty.map((field) => `\"${field}\"`).join(', ')}.`,\n );\n }\n\n return success({ credentials, source });\n}\n\nconst profileSource = (profile: CredentialProfile): ResolvedCredentials['source'] => ({\n kind: 'profile',\n name: profile.name,\n path: profile.path,\n});\n\nexport async function resolveCredentials(\n options: { credentials?: string; profile?: string },\n deps: PushDeps,\n): Promise<Step<ResolvedCredentials>> {\n if (options.credentials !== undefined) {\n return loadCredentialSource({ kind: 'file', path: options.credentials }, deps);\n }\n\n const profiles = await deps.listLoadableCredentialProfiles();\n const names = profiles.map((profile) => profile.name);\n\n if (options.profile !== undefined) {\n const profile = profiles.find((candidate) => candidate.name === options.profile);\n\n if (!profile) {\n return failure(\n 'credentials_invalid',\n names.length === 0\n ? `No loadable credential profile named \"${options.profile}\". No profiles are loadable; create ${GLOBAL_CREDENTIALS_PATH} or pass -c <path>.`\n : `No loadable credential profile named \"${options.profile}\". Loadable profiles: ${names.join(', ')}`,\n );\n }\n\n return loadCredentialSource(profileSource(profile), deps);\n }\n\n const config = await deps.loadConfig(join(deps.cwd, '.kizenapp'));\n\n if (config.credentialMode === 'local') {\n return failure(\n 'credentials_invalid',\n \"This plugin is set to use local browser-only credentials the CLI can't read. Pass -c <path> or --profile <name>.\",\n );\n }\n\n const active =\n config.activeCredentialProfile === undefined\n ? undefined\n : profiles.find((candidate) => candidate.name === config.activeCredentialProfile);\n\n if (active) {\n return loadCredentialSource(profileSource(active), deps);\n }\n\n const [only] = profiles;\n\n if (profiles.length === 1 && only) {\n return loadCredentialSource(profileSource(only), deps);\n }\n\n if (profiles.length === 0) {\n return failure(\n 'credentials_invalid',\n `No credentials found. Create ${GLOBAL_CREDENTIALS_PATH} or pass -c <path>.`,\n );\n }\n\n return failure(\n 'needs_choice',\n `Several credential profiles are available; pass --profile <name>: ${names.join(', ')}`,\n {\n choice: 'profile',\n choices: profiles.map((profile) => ({\n value: profile.name,\n label: profile.isDefault ? `${profile.name} (default)` : profile.name,\n args: ['--profile', profile.name],\n })),\n },\n );\n}\n\nexport interface ResolvedBlock {\n block: Block;\n pluginApiName: string;\n content: CustomCodeContent;\n contentHash: string;\n warnings: ValidationIssue[];\n}\n\nfunction blockChoices(\n deployable: DeployablePlugin[],\n available: { pluginApiName: string; apiName: string }[],\n): PushChoice[] {\n const multiplePlugins = new Set(available.map((entry) => entry.pluginApiName)).size > 1;\n\n return available.map(({ pluginApiName, apiName }) => {\n const block = deployable\n .find((plugin) => plugin.api_name === pluginApiName)\n ?.artifacts.custom_blocks.find((candidate) => candidate.api_name === apiName);\n const qualified = multiplePlugins ? `${pluginApiName}/${apiName}` : apiName;\n\n return {\n value: apiName,\n label: `${block?.name ?? apiName} (${qualified})`,\n args: [apiName],\n };\n });\n}\n\nfunction blockSelectionMessage(\n selection: Extract<ReturnType<typeof selectBlock>, { ok: false }>,\n apiName: string | undefined,\n): string {\n const list = formatAvailableBlocks(selection.available);\n\n if (selection.reason === 'no_blocks') {\n return 'This plugin has no blocks. Scaffold one with `appbuilder create --artifacts block`.';\n }\n\n if (selection.reason === 'not_found') {\n return `No block with api_name \"${apiName ?? ''}\". Available blocks: ${list}`;\n }\n\n return apiName === undefined\n ? `This plugin has several blocks; pass the api_name of the one to push: ${list}`\n : `More than one plugin has a block with api_name \"${apiName}\": ${list}`;\n}\n\nexport async function resolveBlock(\n apiName: string | undefined,\n deps: PushDeps,\n): Promise<Step<ResolvedBlock>> {\n let packaged: { deployable: DeployablePlugin[]; warnings: ValidationIssue[] };\n\n try {\n packaged = await deps.packageBlocks(deps.cwd);\n } catch (error) {\n if (error instanceof PluginValidationError) {\n return failure('validation_failed', formatValidationIssues(error.issues), {\n issues: error.issues,\n });\n }\n\n throw error;\n }\n\n const selection = selectBlock(packaged.deployable, apiName);\n\n if (!selection.ok) {\n const message = blockSelectionMessage(selection, apiName);\n\n if (selection.reason === 'no_blocks') {\n return failure('invalid_block', message);\n }\n\n return failure('needs_choice', message, {\n choice: 'block',\n choices: blockChoices(packaged.deployable, selection.available),\n });\n }\n\n const field = findInvalidBlockField(selection.block);\n\n if (field !== undefined) {\n return failure('invalid_block', invalidBlockMessage(selection.block.api_name, field), {\n field,\n });\n }\n\n const content = toCustomCodeContent(selection.block);\n\n return success({\n block: selection.block,\n pluginApiName: selection.pluginApiName,\n content,\n contentHash: canonicalContentHash(content),\n warnings: packaged.warnings,\n });\n}\n\nexport interface TargetRow {\n id: string;\n name: string;\n type: Surface;\n dashletsCount: number | null;\n employeeAccess: string | null;\n hidden: boolean;\n canEdit: boolean | null;\n}\n\nexport interface TargetCustomObject {\n id: string;\n objectName: string;\n fetchUrl: string;\n}\n\nexport type TargetsResult =\n | {\n ok: true;\n environment: Environment;\n businessId: string;\n surfaces: { dashboard: TargetRow[]; homepage: TargetRow[] };\n customObjects: TargetCustomObject[];\n }\n | {\n ok: true;\n environment: Environment;\n businessId: string;\n object: TargetCustomObject | null;\n surfaces: { chart_group: TargetRow[] };\n };\n\nconst canEditFor = (employeeAccess: string | null | undefined): boolean | null =>\n employeeAccess === undefined || employeeAccess === null\n ? null\n : EDIT_ACCESS_LEVELS.has(employeeAccess.toLowerCase());\n\nexport function toTargetRow(summary: WireDashboardSummary, surface: Surface): TargetRow {\n return {\n id: summary.id,\n name: summary.name,\n type: surface,\n dashletsCount: summary.dashlets_count ?? null,\n employeeAccess: summary.employee_access ?? null,\n hidden: summary.hidden ?? false,\n canEdit: canEditFor(summary.employee_access),\n };\n}\n\nconst toTargetCustomObject = (object: WireCustomObject): TargetCustomObject => ({\n id: object.id,\n objectName: object.object_name,\n fetchUrl: object.fetch_url,\n});\n\nconst CONTACTS_OBJECT_NAME = 'Contacts';\n\nexport async function listPushableObjects(client: KizenClient): Promise<TargetCustomObject[]> {\n const [objects, clientObjectId] = await Promise.all([\n client.listCustomObjects(),\n client.getClientObjectId().catch((): null => null),\n ]);\n const pushable = objects\n .map(toTargetCustomObject)\n .sort((left, right) => left.objectName.localeCompare(right.objectName));\n\n if (\n clientObjectId !== null &&\n clientObjectId !== '' &&\n !pushable.some((object) => object.id === clientObjectId)\n ) {\n pushable.push({ id: clientObjectId, objectName: CONTACTS_OBJECT_NAME, fetchUrl: 'client' });\n }\n\n return pushable;\n}\n\nexport async function listTargets(\n client: KizenClient,\n credentials: Credentials,\n options: { object?: string },\n): Promise<Step<TargetsResult>> {\n const { environment, businessId } = credentials;\n\n try {\n if (options.object !== undefined) {\n const objectId = options.object;\n const [object, chartGroups] = await Promise.all([\n client.getCustomObject(objectId).catch((): null => null),\n client.listDashboards('chart_group', objectId),\n ]);\n\n return success({\n ok: true,\n environment,\n businessId,\n object: object ? toTargetCustomObject(object) : null,\n surfaces: { chart_group: chartGroups.map((row) => toTargetRow(row, 'chart_group')) },\n });\n }\n\n const [dashboards, homepages, customObjects] = await Promise.all([\n client.listDashboards('generic_dashboard'),\n client.listDashboards('homepage'),\n listPushableObjects(client),\n ]);\n\n return success({\n ok: true,\n environment,\n businessId,\n surfaces: {\n dashboard: dashboards.map((row) => toTargetRow(row, 'dashboard')),\n homepage: homepages.map((row) => toTargetRow(row, 'homepage')),\n },\n customObjects,\n });\n } catch (error) {\n return apiFailure(error);\n }\n}\n\nexport interface PushContext {\n client: KizenClient;\n credentials: Credentials;\n block: ResolvedBlock;\n pushMap: PushMapEntry[];\n entry: PushMapEntry | undefined;\n}\n\nexport type ResolvedBy = 'flag' | 'remembered' | 'push_map' | 'name';\n\nexport interface ResolvedTarget {\n dashboard: WireDashboard;\n surface: Surface;\n action: 'create' | 'update';\n dashlet: WireDashlet | undefined;\n resolvedBy: ResolvedBy;\n}\n\nconst isMemberDashlet = (dashboard: WireDashboard, dashlet: WireDashlet): boolean =>\n dashlet.dashboard === dashboard.id;\n\nexport function buildTargetChoices(dashboard: WireDashboard, block: ResolvedBlock): PushChoice[] {\n const existing = findCustomCodeDashlets(dashboard)\n .filter((dashlet) => isMemberDashlet(dashboard, dashlet))\n .map((dashlet): PushChoice => {\n const parsed = parsePushKey(dashlet.name);\n\n return {\n value: dashlet.id,\n label: customCodeName(dashlet),\n args: ['--dashboard', dashboard.id, '--dashlet', dashlet.id],\n pushKey: parsed ? dashlet.name : null,\n isFromThisPlugin: parsed?.pluginApiName === block.pluginApiName,\n };\n });\n\n return [\n ...existing,\n { value: 'new', label: 'Create a new block', args: ['--dashboard', dashboard.id, '--create'] },\n ];\n}\n\nfunction target(\n dashboard: WireDashboard,\n action: 'create' | 'update',\n dashlet: WireDashlet | undefined,\n resolvedBy: ResolvedBy,\n): Step<ResolvedTarget> {\n return success({\n dashboard,\n surface: dashboardTypeToSurface(dashboard.type),\n action,\n dashlet,\n resolvedBy,\n });\n}\n\nasync function chooseDashboard(context: PushContext): Promise<Step<ResolvedTarget>> {\n const [dashboards, homepages] = await Promise.all([\n context.client.listDashboards('generic_dashboard'),\n context.client.listDashboards('homepage'),\n ]);\n const toChoice =\n (surface: Surface) =>\n (summary: WireDashboardSummary): PushChoice => ({\n value: summary.id,\n label: summary.name,\n args: ['--dashboard', summary.id],\n surface,\n canEdit: canEditFor(summary.employee_access),\n });\n\n return failure(\n 'needs_choice',\n `Choose where to push; pass --dashboard <id>. ${CHART_GROUP_HINT}`,\n {\n choice: 'dashboard',\n choices: [...dashboards.map(toChoice('dashboard')), ...homepages.map(toChoice('homepage'))],\n },\n );\n}\n\nasync function resolveFlaggedDashboard(\n context: PushContext,\n dashboardId: string,\n options: PushCommandOptions,\n): Promise<Step<ResolvedTarget>> {\n const dashboard = await context.client.getDashboard(dashboardId);\n\n if (options.create) {\n return target(dashboard, 'create', undefined, 'flag');\n }\n\n const choices = (): PushChoice[] => buildTargetChoices(dashboard, context.block);\n\n if (options.dashlet !== undefined) {\n const dashletId = options.dashlet;\n const dashlet = dashboard.dashlets.find(\n (candidate) => candidate.id === dashletId && isMemberDashlet(dashboard, candidate),\n );\n\n if (!dashlet) {\n return failure(\n 'not_found',\n `Dashlet ${dashletId} is not on dashboard \"${dashboard.name}\" (${dashboard.id}).`,\n { choice: 'target', choices: choices() },\n );\n }\n\n if (!isCustomCodeDashlet(dashlet)) {\n return failure(\n 'usage_error',\n `Dashlet ${dashletId} is not a custom code block, so it can't be updated with a pushed block. Pass --create to add a new one.`,\n );\n }\n\n return target(dashboard, 'update', dashlet, 'flag');\n }\n\n const match = matchPushTarget({\n dashboardId: dashboard.id,\n dashlets: dashboard.dashlets,\n pluginApiName: context.block.pluginApiName,\n blockApiName: context.block.block.api_name,\n entry: context.entry,\n });\n\n if (match.kind === 'map') {\n return target(dashboard, 'update', match.dashlet, 'push_map');\n }\n\n if (match.kind === 'name') {\n return target(dashboard, 'update', match.dashlet, 'name');\n }\n\n return failure(\n 'needs_choice',\n match.kind === 'ambiguous'\n ? `Dashboard \"${dashboard.name}\" has ${String(match.dashlets.length)} blocks pushed from this block; pass --dashlet <id> to pick one, or --create.`\n : `Choose a block to update on \"${dashboard.name}\", or create a new one; pass --dashlet <id> or --create.`,\n { choice: 'target', choices: choices() },\n );\n}\n\nasync function resolveRemembered(\n context: PushContext,\n entry: PushMapEntry,\n options: PushCommandOptions,\n): Promise<Step<ResolvedTarget>> {\n let dashboard: WireDashboard;\n\n try {\n dashboard = await context.client.getDashboard(entry.dashboardId);\n } catch (error) {\n if (error instanceof KizenApiError && error.kind === 'not_found') {\n return failure(\n 'remembered_target_missing',\n `The remembered dashboard ${entry.dashboardId} no longer exists. Pass --dashboard <id> to choose another, or --forget to clear it.`,\n );\n }\n\n throw error;\n }\n\n if (options.create) {\n return target(dashboard, 'create', undefined, 'remembered');\n }\n\n const dashlet = dashboard.dashlets.find(\n (candidate) => candidate.id === entry.dashletId && isMemberDashlet(dashboard, candidate),\n );\n\n if (dashlet && isCustomCodeDashlet(dashlet)) {\n return target(dashboard, 'update', dashlet, 'remembered');\n }\n\n return failure(\n 'remembered_target_missing',\n `The remembered block (dashlet ${entry.dashletId}) is no longer on \"${dashboard.name}\". Choose a block to update, or create a new one.`,\n { choice: 'target', choices: buildTargetChoices(dashboard, context.block) },\n );\n}\n\nexport async function resolveTarget(\n context: PushContext,\n options: PushCommandOptions,\n): Promise<Step<ResolvedTarget>> {\n if (options.dashlet !== undefined && options.create) {\n return failure('usage_error', 'Pass either --dashlet <id> or --create, not both.');\n }\n\n if (options.dashlet !== undefined && options.dashboard === undefined) {\n return failure('usage_error', '--dashlet <id> needs --dashboard <id>.');\n }\n\n try {\n if (options.dashboard !== undefined) {\n return await resolveFlaggedDashboard(context, options.dashboard, options);\n }\n\n if (context.entry) {\n return await resolveRemembered(context, context.entry, options);\n }\n\n return await chooseDashboard(context);\n } catch (error) {\n return apiFailure(error);\n }\n}\n\nexport interface PushSummary {\n environment: Environment;\n businessId: string;\n isProduction: boolean;\n surface: Surface;\n dashboardId: string;\n dashboardName: string;\n action: 'create' | 'update';\n actionLine: string;\n dashletId: string | null;\n blockName: string;\n blockApiName: string;\n pluginApiName: string;\n scriptBytes: number;\n stylesBytes: number;\n}\n\nexport interface PushPlan {\n action: 'create' | 'update';\n method: 'POST' | 'PATCH';\n path: string;\n body: CreateDashletBody | UpdateDashletBody;\n dashboard: { id: string; name: string; type: Surface };\n dashletId: string | null;\n url: string;\n resolvedBy: ResolvedBy;\n summary: PushSummary;\n warnings: string[];\n}\n\nasync function customObjectOf(\n client: KizenClient,\n dashboard: WireDashboard,\n surface: Surface,\n): Promise<{ id: string; fetchUrl?: string } | null> {\n const raw: unknown = dashboard.custom_object;\n\n if (raw === null || raw === undefined || raw === '') {\n return null;\n }\n\n if (typeof raw !== 'string') {\n if (typeof raw !== 'object' || typeof (raw as { id?: unknown }).id !== 'string') {\n return null;\n }\n\n const { id, fetch_url: fetchUrl } = raw as { id: string; fetch_url?: unknown };\n\n return typeof fetchUrl === 'string' ? { id, fetchUrl } : { id };\n }\n\n if (surface !== 'chart_group') {\n return { id: raw };\n }\n\n try {\n const object = await client.getCustomObject(raw);\n\n return { id: raw, fetchUrl: object.fetch_url };\n } catch {\n return { id: raw };\n }\n}\n\nconst segment = encodeURIComponent;\n\nexport async function buildPlan(\n context: PushContext,\n resolved: ResolvedTarget,\n options: Pick<PushCommandOptions, 'force'>,\n deps: Pick<PushDeps, 'randomUUID'>,\n): Promise<Step<PushPlan>> {\n const { credentials, block } = context;\n const { dashboard, surface, dashlet } = resolved;\n const warnings: string[] = [];\n let body: CreateDashletBody | UpdateDashletBody;\n let path: string;\n let actionLine: string;\n\n if (resolved.action === 'update') {\n if (!dashlet) {\n return failure('usage_error', 'An update needs a dashlet to update.');\n }\n\n if (detectDrift(dashlet, context.entry)) {\n const drift = `\"${customCodeName(dashlet)}\" (dashlet ${dashlet.id}) was changed in Kizen since the last push.`;\n\n if (!options.force) {\n return failure(\n 'drift_detected',\n `${drift} Pushing would overwrite those changes; pass --force to overwrite them.`,\n );\n }\n\n warnings.push(`${drift} Overwriting it because of --force.`);\n }\n\n body = buildUpdateBody(dashlet, block.content);\n path = `/dashboards/${segment(dashboard.id)}/dashlet/${segment(dashlet.id)}`;\n actionLine = `Update \"${customCodeName(dashlet)}\" (dashlet ${dashlet.id})`;\n } else {\n body = buildCreateBody({\n pluginApiName: block.pluginApiName,\n blockApiName: block.block.api_name,\n content: block.content,\n dashlets: dashboard.dashlets,\n objectId: deps.randomUUID(),\n layoutId: deps.randomUUID(),\n });\n path = `/dashboards/${segment(dashboard.id)}/dashlet`;\n actionLine = `Create a new block on \"${dashboard.name}\"`;\n }\n\n const dashletId = resolved.action === 'update' && dashlet ? dashlet.id : null;\n const url = buildDashboardUrl({\n appBaseUrl: APP_URLS[credentials.environment],\n surface,\n dashboardId: dashboard.id,\n customObject: await customObjectOf(context.client, dashboard, surface),\n });\n\n return success({\n action: resolved.action,\n method: resolved.action === 'update' ? 'PATCH' : 'POST',\n path,\n body,\n dashboard: { id: dashboard.id, name: dashboard.name, type: surface },\n dashletId,\n url,\n resolvedBy: resolved.resolvedBy,\n warnings,\n summary: {\n environment: credentials.environment,\n businessId: credentials.businessId,\n isProduction: isProductionEnvironment(credentials.environment),\n surface,\n dashboardId: dashboard.id,\n dashboardName: dashboard.name,\n action: resolved.action,\n actionLine,\n dashletId,\n blockName: block.block.name,\n blockApiName: block.block.api_name,\n pluginApiName: block.pluginApiName,\n scriptBytes: Buffer.byteLength(block.content.script, 'utf8'),\n stylesBytes: Buffer.byteLength(block.content.styles, 'utf8'),\n },\n });\n}\n\nexport interface AppliedPush {\n dashletId: string;\n remembered: boolean;\n warnings: string[];\n}\n\nexport const pushMapKeyOf = (context: Pick<PushContext, 'credentials' | 'block'>): PushMapKey => ({\n environment: context.credentials.environment,\n businessId: context.credentials.businessId,\n pluginApiName: context.block.pluginApiName,\n blockApiName: context.block.block.api_name,\n});\n\nexport async function applyPlan(\n context: PushContext,\n plan: PushPlan,\n deps: PushDeps,\n): Promise<Step<AppliedPush>> {\n let dashletId: string;\n\n try {\n if (plan.action === 'create') {\n const created = await context.client.createDashlet(\n plan.dashboard.id,\n plan.body as CreateDashletBody,\n );\n\n const createdId: unknown = created.id;\n\n if (typeof createdId !== 'string' || createdId === '') {\n return failure(\n 'api_error',\n `POST ${plan.path} succeeded but the response had no dashlet id; check \"${plan.dashboard.name}\" before pushing again.`,\n );\n }\n\n dashletId = createdId;\n } else {\n if (plan.dashletId === null) {\n return failure('usage_error', 'An update needs a dashlet to update.');\n }\n\n await context.client.updateDashlet(plan.dashboard.id, plan.dashletId, plan.body);\n dashletId = plan.dashletId;\n }\n } catch (error) {\n return apiFailure(error);\n }\n\n const warnings = [...plan.warnings];\n const entry: PushMapEntry = {\n ...pushMapKeyOf(context),\n dashboardId: plan.dashboard.id,\n dashletId,\n contentHash: context.block.contentHash,\n pushedAt: deps.now().toISOString(),\n };\n let remembered = false;\n\n try {\n deps.ensureGitignore(deps.cwd);\n await deps.writePushMap(deps.cwd, upsertPushMapEntry(context.pushMap, entry));\n remembered = true;\n } catch (error) {\n warnings.push(\n `The push succeeded, but ${PUSH_MAP_RELATIVE_PATH} couldn't be written, so this target isn't remembered: ${errorMessage(error)}`,\n );\n }\n\n return success({ dashletId, remembered, warnings });\n}\n\nexport interface BrowserRefresh {\n dashboardId: string;\n script: string;\n}\n\nconst UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\nexport function buildBrowserRefresh(dashboardId: string): BrowserRefresh | null {\n if (!UUID_PATTERN.test(dashboardId)) {\n return null;\n }\n\n return {\n dashboardId,\n script: `await window.__kizenCustomBlocks?.refresh('${dashboardId}')`,\n };\n}\n\nexport async function forgetRemembered(\n context: Pick<PushContext, 'credentials' | 'block' | 'pushMap'>,\n deps: Pick<PushDeps, 'cwd' | 'writePushMap'>,\n): Promise<boolean> {\n const key = pushMapKeyOf(context);\n\n if (!findPushMapEntry(context.pushMap, key)) {\n return false;\n }\n\n await deps.writePushMap(deps.cwd, removePushMapEntry(context.pushMap, key));\n\n return true;\n}\n\nexport type WriteGate = { kind: 'dry-run'; reason: 'flag' | 'no_yes' } | { kind: 'apply' };\n\nexport function headlessWriteGate(\n options: PushCommandOptions,\n environment: Environment,\n): Step<WriteGate> {\n if (options.dryRun) {\n return success({ kind: 'dry-run', reason: 'flag' });\n }\n\n if (!options.yes) {\n return success({ kind: 'dry-run', reason: 'no_yes' });\n }\n\n if (isProductionEnvironment(environment) && !options.allowProduction) {\n return failure(\n 'production_requires_flag',\n `${environment} is a production environment. Pass --allow-production with --yes to write to it.`,\n );\n }\n\n return success({ kind: 'apply' });\n}\n\nexport const DRY_RUN_NOTE = 'Dry run only: pass --yes to write.';\n\nexport function formatSummaryLines(summary: PushSummary): string[] {\n return [\n `Environment: ${summary.environment}${summary.isProduction ? ' (production)' : ''}`,\n `Business: ${summary.businessId}`,\n `Surface: ${summary.surface}`,\n `Dashboard: \"${summary.dashboardName}\" (${summary.dashboardId})`,\n `Action: ${summary.actionLine}`,\n `Block: ${summary.blockName} (${summary.pluginApiName}/${summary.blockApiName})`,\n `Size: script ${String(summary.scriptBytes)} bytes, styles ${String(summary.stylesBytes)} bytes`,\n ];\n}\n\nconst formatIssueWarning = (issue: ValidationIssue): string =>\n `${issue.path === undefined ? '' : `${issue.path}: `}${issue.message} (${issue.rule})`;\n\nconst quoteArg = (arg: string): string => (/^[\\w./:@=-]+$/.test(arg) ? arg : JSON.stringify(arg));\n\ntype ChoiceArgs = (choice: PushChoice, kind: ChoiceKind | undefined) => string[];\n\nfunction formatFailureText(result: PushFailure, command: string, choiceArgs: ChoiceArgs): string {\n const lines = [`Error: ${result.message}`];\n\n if (result.hint !== undefined) {\n lines.push(`Hint: ${result.hint}`);\n }\n\n if (result.choices && result.choices.length > 0) {\n lines.push('Choices:');\n\n for (const choice of result.choices) {\n const args = choiceArgs(choice, result.choice).map(quoteArg).join(' ');\n\n lines.push(` ${choice.label} → ${command} ${args}`);\n }\n }\n\n return `${lines.join('\\n')}\\n`;\n}\n\ninterface Output {\n json: boolean;\n deps: PushDeps;\n}\n\nfunction writeFailure(\n output: Output,\n result: PushFailure,\n command: string,\n choiceArgs: ChoiceArgs,\n): void {\n if (output.json) {\n output.deps.writeStdout(`${JSON.stringify(result, null, 2)}\\n`);\n } else {\n output.deps.writeStderr(formatFailureText(result, command, choiceArgs));\n }\n\n output.deps.setExitCode(1);\n}\n\nconst credentialArgs = (options: { credentials?: string; profile?: string }): string[] => {\n if (options.credentials !== undefined) {\n return ['-c', options.credentials];\n }\n\n return options.profile === undefined ? [] : ['--profile', options.profile];\n};\n\nasync function claudeSkillWarnings(deps: PushDeps): Promise<string[]> {\n try {\n return (await deps.isClaudeSkillStale(deps.cwd)) ? [STALE_CLAUDE_SKILL_WARNING] : [];\n } catch {\n return [];\n }\n}\n\nexport async function runPushHeadless(\n apiName: string | undefined,\n options: PushCommandOptions,\n deps: PushDeps,\n): Promise<void> {\n const output: Output = { json: options.json === true, deps };\n const command = 'appbuilder block push';\n let blockArgs = apiName === undefined ? [] : [apiName];\n const choiceArgs: ChoiceArgs = (choice, kind) => {\n if (kind === 'profile') {\n return [...blockArgs, ...choice.args];\n }\n\n if (kind === 'block') {\n return [...choice.args, ...credentialArgs(options)];\n }\n\n return [...blockArgs, ...credentialArgs(options), ...choice.args];\n };\n\n const fail = (result: PushFailure): void => {\n writeFailure(output, result, command, choiceArgs);\n };\n\n try {\n const credentialStep = await resolveCredentials(options, deps);\n\n if (!credentialStep.ok) {\n fail(credentialStep);\n\n return;\n }\n\n const { credentials } = credentialStep.value;\n const client = deps.createClient(credentials);\n const blockStep = await resolveBlock(apiName, deps);\n\n if (!blockStep.ok) {\n fail(blockStep);\n\n return;\n }\n\n const block = blockStep.value;\n\n blockArgs = [block.block.api_name];\n\n if (block.warnings.length > 0) {\n deps.writeStderr(`${formatValidationIssues(block.warnings)}\\n`);\n }\n\n const context: PushContext = { client, credentials, block, pushMap: [], entry: undefined };\n\n context.pushMap = await deps.readPushMap(deps.cwd);\n\n let forgotten = false;\n\n if (options.forget) {\n forgotten = await forgetRemembered(context, deps);\n\n if (forgotten) {\n context.pushMap = removePushMapEntry(context.pushMap, pushMapKeyOf(context));\n deps.writeStderr(`Forgot the remembered target for ${block.block.api_name}.\\n`);\n }\n }\n\n context.entry = findPushMapEntry(context.pushMap, pushMapKeyOf(context));\n\n const targetStep = await resolveTarget(context, options);\n\n if (!targetStep.ok) {\n fail(targetStep);\n\n return;\n }\n\n const gateStep = headlessWriteGate(options, credentials.environment);\n\n if (!gateStep.ok) {\n fail(gateStep);\n\n return;\n }\n\n const planStep = await buildPlan(context, targetStep.value, options, deps);\n\n if (!planStep.ok) {\n fail(planStep);\n\n return;\n }\n\n const plan = planStep.value;\n const blockInfo = {\n pluginApiName: block.pluginApiName,\n apiName: block.block.api_name,\n name: block.block.name,\n };\n const common = {\n environment: credentials.environment,\n businessId: credentials.businessId,\n dashboard: plan.dashboard,\n };\n const issueWarnings = [\n ...block.warnings.map(formatIssueWarning),\n ...(await claudeSkillWarnings(deps)),\n ];\n const gate = gateStep.value;\n\n if (gate.kind === 'dry-run') {\n const warnings = [...issueWarnings, ...plan.warnings];\n const result = {\n ok: true as const,\n applied: false as const,\n dryRun: true as const,\n reason: gate.reason,\n action: plan.action,\n ...common,\n dashletId: plan.dashletId,\n url: plan.url,\n resolvedBy: plan.resolvedBy,\n block: blockInfo,\n method: plan.method,\n path: plan.path,\n body: plan.body,\n warnings,\n ...(forgotten ? { forgotten: true as const } : {}),\n };\n\n if (output.json) {\n deps.writeStdout(`${JSON.stringify(result, null, 2)}\\n`);\n deps.writeStderr(\n [...formatSummaryLines(plan.summary), ...warnings.map((w) => `Warning: ${w}`), ''].join(\n '\\n',\n ),\n );\n } else {\n deps.writeStdout(\n [\n ...formatSummaryLines(plan.summary),\n `URL: ${plan.url}`,\n ...warnings.map((warning) => `Warning: ${warning}`),\n '',\n `${plan.method} ${plan.path}`,\n JSON.stringify(plan.body, null, 2),\n '',\n ].join('\\n'),\n );\n }\n\n if (gate.reason === 'no_yes') {\n deps.writeStderr(`${DRY_RUN_NOTE}\\n`);\n }\n\n return;\n }\n\n const appliedStep = await applyPlan(context, plan, deps);\n\n if (!appliedStep.ok) {\n fail(appliedStep);\n\n return;\n }\n\n const applied = appliedStep.value;\n const warnings = [...issueWarnings, ...applied.warnings];\n const refresh = buildBrowserRefresh(plan.dashboard.id);\n const result = {\n ok: true as const,\n applied: true as const,\n dryRun: false as const,\n action: plan.action === 'create' ? ('created' as const) : ('updated' as const),\n ...common,\n dashletId: applied.dashletId,\n url: plan.url,\n ...(refresh ? { refresh } : {}),\n resolvedBy: plan.resolvedBy,\n block: blockInfo,\n remembered: applied.remembered,\n warnings,\n ...(forgotten ? { forgotten: true as const } : {}),\n };\n\n const text = [\n `✓ ${result.action === 'created' ? 'Created' : 'Updated'} ${block.block.name} on \"${plan.dashboard.name}\" (dashlet ${applied.dashletId})`,\n ...formatSummaryLines(plan.summary),\n `URL: ${plan.url}`,\n ...(refresh ? [`Refresh an open tab: ${refresh.script}`] : []),\n ...warnings.map((warning) => `Warning: ${warning}`),\n '',\n ].join('\\n');\n\n if (output.json) {\n deps.writeStdout(`${JSON.stringify(result, null, 2)}\\n`);\n deps.writeStderr(text);\n } else {\n deps.writeStdout(text);\n }\n } catch (error) {\n fail(apiFailure(error));\n }\n}\n\nconst pad = (value: string, width: number): string => value.padEnd(width);\n\nfunction formatTargetTable(title: string, rows: TargetRow[]): string[] {\n if (rows.length === 0) {\n return [title, ' (none)'];\n }\n\n const header = ['NAME', 'ID', 'DASHLETS', 'ACCESS'];\n const cells = rows.map((row) => [\n `${row.name}${row.hidden ? ' (hidden)' : ''}`,\n row.id,\n row.dashletsCount === null ? '-' : String(row.dashletsCount),\n `${row.employeeAccess ?? '-'}${row.canEdit === false ? ' (no edit access)' : ''}`,\n ]);\n const widths = header.map((label, index) =>\n Math.max(label.length, ...cells.map((cell) => (cell[index] ?? '').length)),\n );\n const line = (cell: string[]): string =>\n ` ${cell.map((value, index) => pad(value, widths[index] ?? 0)).join(' ')}`.trimEnd();\n\n return [title, line(header), ...cells.map(line)];\n}\n\nfunction formatTargetsText(result: TargetsResult): string {\n const lines = [`Environment: ${result.environment}`, `Business: ${result.businessId}`, ''];\n\n if ('object' in result) {\n lines.push(\n result.object === null\n ? 'Custom object: not found in /custom-objects'\n : `Custom object: ${result.object.objectName} (${result.object.id})`,\n '',\n ...formatTargetTable('Chart groups', result.surfaces.chart_group),\n );\n } else {\n lines.push(\n ...formatTargetTable('Dashboards', result.surfaces.dashboard),\n '',\n ...formatTargetTable('Homepages', result.surfaces.homepage),\n '',\n 'Custom objects',\n ...(result.customObjects.length === 0\n ? [' (none)']\n : result.customObjects.map((object) => ` ${object.objectName} ${object.id}`)),\n '',\n 'List an object’s chart groups with `appbuilder block targets --object <id>`.',\n );\n }\n\n return `${lines.join('\\n')}\\n`;\n}\n\nexport async function runTargetsHeadless(\n options: TargetsCommandOptions,\n deps: PushDeps,\n): Promise<void> {\n const output: Output = { json: options.json === true, deps };\n const command = 'appbuilder block targets';\n const objectArgs = options.object === undefined ? [] : ['--object', options.object];\n const choiceArgs: ChoiceArgs = (choice) => [...choice.args, ...objectArgs];\n const fail = (result: PushFailure): void => {\n writeFailure(output, result, command, choiceArgs);\n };\n\n try {\n const credentialStep = await resolveCredentials(options, deps);\n\n if (!credentialStep.ok) {\n fail(credentialStep);\n\n return;\n }\n\n const { credentials } = credentialStep.value;\n const targetsStep = await listTargets(\n deps.createClient(credentials),\n credentials,\n options.object === undefined ? {} : { object: options.object },\n );\n\n if (!targetsStep.ok) {\n fail(targetsStep);\n\n return;\n }\n\n deps.writeStdout(\n output.json\n ? `${JSON.stringify(targetsStep.value, null, 2)}\\n`\n : formatTargetsText(targetsStep.value),\n );\n } catch (error) {\n fail(apiFailure(error));\n }\n}\n","import type { Environment } from './credentials.js';\n\nexport const BASE_URLS: Record<Environment, string> = {\n go: 'https://app.go.kizen.com/api',\n fmo: 'https://app.fmo.kizen.com/api',\n staging: 'https://staging.kizen.com/api',\n integration: 'https://integration.kizen.dev/api',\n test1: 'https://test1.kizen.dev/api',\n};\n\nexport const APP_URLS: Record<Environment, string> = {\n go: 'https://go.kizen.com',\n fmo: 'https://fmo.kizen.com',\n staging: 'https://v2.staging.kizen.com',\n integration: 'https://v2.integration.kizen.dev',\n test1: 'https://test1.kizen.dev',\n};\n\nexport const PRODUCTION_ENVIRONMENTS: readonly Environment[] = ['go', 'fmo'];\n\nexport function isProductionEnvironment(env: Environment): boolean {\n return PRODUCTION_ENVIRONMENTS.includes(env);\n}\n","import { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nexport interface AppBuilderConfig {\n credentialMode?: 'global' | 'local';\n activeCredentialProfile?: string;\n lastPath?: string;\n // Which encryption API the Secrets page fetches public keys from. Defaults to\n // 'prod' when unset; 'dev' is an explicit per-project override (KZN-16467).\n // (A legacy 'auto' value may exist in older config files; it is read as the\n // 'prod' default — see GET /api/encryption-target.)\n encryptionTarget?: 'dev' | 'prod';\n}\n\nexport async function loadConfig(outputDir: string): Promise<AppBuilderConfig> {\n try {\n const content = await readFile(join(outputDir, 'config.json'), 'utf-8');\n\n return JSON.parse(content) as AppBuilderConfig;\n } catch {\n return {};\n }\n}\n\nexport async function saveConfig(outputDir: string, config: AppBuilderConfig): Promise<void> {\n await mkdir(outputDir, { recursive: true });\n\n await writeFile(join(outputDir, 'config.json'), JSON.stringify(config, null, 2), 'utf-8');\n}\n","import { mkdir, readFile, readdir, writeFile } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { dirname, join } from 'node:path';\nimport {\n ENVIRONMENTS,\n normalizeCredentialIds,\n type Environment,\n type Credentials,\n} from '../../shared/lib/credentials.js';\nexport {\n ENVIRONMENTS,\n cleanCredentialId,\n normalizeCredentialIds,\n type CredentialIds,\n type Environment,\n type Credentials,\n} from '../../shared/lib/credentials.js';\n\nexport interface CredentialProfile {\n name: string;\n path: string;\n isDefault: boolean;\n}\n\nexport const GLOBAL_CREDENTIALS_DIR = join(homedir(), '.kizenappbuilder');\nexport const GLOBAL_CREDENTIALS_PATH = join(GLOBAL_CREDENTIALS_DIR, 'credentials.json');\nexport const DEFAULT_PROFILE_NAME = 'credentials';\n\nfunction isValidEnvironment(value: unknown): value is Environment {\n return ENVIRONMENTS.includes(value as Environment);\n}\n\nfunction trimString(value: unknown): unknown {\n return typeof value === 'string' ? value.trim() : value;\n}\n\nfunction parseCredentials(raw: unknown): Credentials {\n if (typeof raw !== 'object' || raw === null) {\n throw new Error('Credentials must be a JSON object');\n }\n\n const obj = raw as Record<string, unknown>;\n const env = trimString(obj.environment);\n\n return {\n ...normalizeCredentialIds(obj),\n environment: isValidEnvironment(env) ? env : 'go',\n };\n}\n\nexport async function loadCredentialsFromFile(filePath: string): Promise<Credentials> {\n const content = await readFile(filePath, 'utf-8');\n\n return parseCredentials(JSON.parse(content) as unknown);\n}\n\nexport type EnvironmentSource = 'explicit' | 'missing' | 'invalid';\n\nexport interface DetailedCredentials {\n credentials: Credentials;\n environmentSource: EnvironmentSource;\n}\n\nfunction environmentSourceOf(raw: unknown): EnvironmentSource {\n const env = trimString((raw as Record<string, unknown>).environment);\n\n if (env === undefined || env === null || env === '') {\n return 'missing';\n }\n\n return isValidEnvironment(env) ? 'explicit' : 'invalid';\n}\n\nexport async function loadCredentialsDetailed(filePath: string): Promise<DetailedCredentials> {\n const content = await readFile(filePath, 'utf-8');\n const raw = JSON.parse(content) as unknown;\n const credentials = parseCredentials(raw);\n\n return { credentials, environmentSource: environmentSourceOf(raw) };\n}\n\nexport async function loadGlobalCredentials(): Promise<Credentials | null> {\n try {\n return await loadCredentialsFromFile(GLOBAL_CREDENTIALS_PATH);\n } catch {\n return null;\n }\n}\n\nexport async function saveGlobalCredentials(credentials: Credentials): Promise<void> {\n await mkdir(dirname(GLOBAL_CREDENTIALS_PATH), { recursive: true, mode: 0o700 });\n\n await writeFile(GLOBAL_CREDENTIALS_PATH, JSON.stringify(credentials, null, 2), {\n encoding: 'utf-8',\n mode: 0o600,\n });\n}\n\nexport function getProfilePath(name: string): string {\n return join(GLOBAL_CREDENTIALS_DIR, `${name}.json`);\n}\n\nexport async function listCredentialProfiles(): Promise<CredentialProfile[]> {\n const profiles: CredentialProfile[] = [\n { name: DEFAULT_PROFILE_NAME, path: GLOBAL_CREDENTIALS_PATH, isDefault: true },\n ];\n\n try {\n const entries = await readdir(GLOBAL_CREDENTIALS_DIR);\n\n for (const entry of entries) {\n if (!entry.endsWith('.json')) {\n continue;\n }\n\n const name = entry.slice(0, -5);\n\n if (name === DEFAULT_PROFILE_NAME) {\n continue;\n }\n\n profiles.push({ name, path: join(GLOBAL_CREDENTIALS_DIR, entry), isDefault: false });\n }\n } catch {\n // directory doesn't exist yet — only the default profile\n }\n\n return profiles;\n}\n\nexport async function saveCredentialProfile(name: string, credentials: Credentials): Promise<void> {\n if (name === DEFAULT_PROFILE_NAME) {\n await saveGlobalCredentials(credentials);\n\n return;\n }\n\n await mkdir(GLOBAL_CREDENTIALS_DIR, { recursive: true, mode: 0o700 });\n\n await writeFile(getProfilePath(name), JSON.stringify(credentials, null, 2), {\n encoding: 'utf-8',\n mode: 0o600,\n });\n}\n\nexport async function loadCredentialProfile(name: string): Promise<Credentials | null> {\n try {\n return await loadCredentialsFromFile(getProfilePath(name));\n } catch {\n return null;\n }\n}\n\nexport async function listLoadableCredentialProfiles(): Promise<CredentialProfile[]> {\n const profiles = await listCredentialProfiles();\n const loadable = await Promise.all(\n profiles.map((profile) =>\n loadCredentialsDetailed(profile.path).then(\n () => true,\n () => false,\n ),\n ),\n );\n\n return profiles.filter((_, index) => loadable[index] === true);\n}\n","export const ENVIRONMENTS = ['go', 'fmo', 'staging', 'integration', 'test1'] as const;\nexport type Environment = (typeof ENVIRONMENTS)[number];\n\nexport interface Credentials {\n apiKey: string;\n userId: string;\n businessId: string;\n environment: Environment;\n}\n\nexport type CredentialIds = Pick<Credentials, 'apiKey' | 'userId' | 'businessId'>;\n\nexport function cleanCredentialId(value: unknown): string {\n return typeof value === 'string' ? value.trim() : '';\n}\n\nexport function normalizeCredentialIds(\n values: Partial<Record<keyof CredentialIds, unknown>>,\n): CredentialIds {\n return {\n apiKey: cleanCredentialId(values.apiKey),\n userId: cleanCredentialId(values.userId),\n businessId: cleanCredentialId(values.businessId),\n };\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\n\nexport function ensureGitignore(projectDir: string): void {\n const gitignorePath = path.join(projectDir, '.gitignore');\n const entry = '.kizenapp/';\n\n let contents = '';\n\n if (fs.existsSync(gitignorePath)) {\n contents = fs.readFileSync(gitignorePath, 'utf8');\n\n const lines = contents.split('\\n').map((l) => l.trim());\n\n if (lines.includes(entry) || lines.includes('.kizenapp')) {\n return;\n }\n }\n\n const addition = contents.endsWith('\\n') ? entry + '\\n' : '\\n' + entry + '\\n';\n\n fs.writeFileSync(gitignorePath, contents + addition);\n}\n","import { BASE_URLS } from '../../shared/lib/kizenUrls.js';\nimport type { Credentials } from './credentials.js';\nimport type {\n CreateDashletBody,\n DashboardType,\n KizenApiErrorKind,\n KizenClient,\n UpdateDashletBody,\n WireCustomObject,\n WireDashboard,\n WireDashboardSummary,\n WireDashlet,\n} from './kizenTypes.js';\nimport { getProxyEnvStatus, PROXY_UNAVAILABLE_HINT } from './proxyEnv.js';\n\nexport interface KizenClientOptions {\n credentials: Credentials;\n fetch?: typeof fetch;\n baseUrl?: string;\n}\n\nconst AUTH_FAILED_HINT =\n \"The API key is invalid for this business, or the user id doesn't match. Check the credentials file's apiKey, userId and businessId.\";\n\nconst FORBIDDEN_HINT =\n \"The API key's user needs the Standard API Keys permission and edit access to this dashboard. Homepages also need the Customize Homepages permission.\";\n\ninterface ListPage {\n results: unknown[];\n next: unknown;\n}\n\nconst MAX_PAGES = 100;\n\nconst UNPREFIXED_KEYS = new Set(['detail', 'non_field_errors']);\n\nexport class KizenApiError extends Error {\n readonly kind: KizenApiErrorKind;\n readonly status: number | undefined;\n readonly hint: string | undefined;\n\n constructor(\n kind: KizenApiErrorKind,\n message: string,\n options: { status?: number; hint?: string } = {},\n ) {\n super(message);\n this.name = 'KizenApiError';\n this.kind = kind;\n this.status = options.status;\n this.hint = options.hint;\n }\n}\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value);\n\nfunction collectMessages(value: unknown, prefix: string, out: string[]): void {\n const push = (text: string): void => {\n out.push(prefix === '' ? text : `${prefix}: ${text}`);\n };\n\n if (typeof value === 'string') {\n if (value.trim() !== '') {\n push(value);\n }\n\n return;\n }\n\n if (typeof value === 'number' || typeof value === 'boolean') {\n push(String(value));\n\n return;\n }\n\n if (Array.isArray(value)) {\n const texts = value.filter(\n (item): item is string | number | boolean =>\n (typeof item === 'string' && item.trim() !== '') ||\n typeof item === 'number' ||\n typeof item === 'boolean',\n );\n\n if (texts.length > 0) {\n push(texts.map(String).join(' '));\n }\n\n for (const item of value) {\n if (typeof item === 'object' && item !== null) {\n collectMessages(item, prefix, out);\n }\n }\n\n return;\n }\n\n if (isRecord(value)) {\n for (const [key, child] of Object.entries(value)) {\n const childPrefix =\n prefix === '' && UNPREFIXED_KEYS.has(key) ? '' : prefix === '' ? key : `${prefix}.${key}`;\n\n collectMessages(child, childPrefix, out);\n }\n }\n}\n\nexport function formatDrfError(body: unknown): string | undefined {\n if (typeof body !== 'object' || body === null) {\n return undefined;\n }\n\n const messages: string[] = [];\n\n collectMessages(body, '', messages);\n\n return messages.length > 0 ? messages.join('; ') : undefined;\n}\n\nfunction errorCause(err: unknown): string {\n const e = err as { code?: string; message?: string; cause?: { code?: string; message?: string } };\n\n return e.cause?.code ?? e.code ?? e.cause?.message ?? e.message ?? String(err);\n}\n\nasync function readBody(res: Response): Promise<{ text: string; json: unknown }> {\n const text = await res.text();\n\n if (text === '') {\n return { text, json: undefined };\n }\n\n try {\n return { text, json: JSON.parse(text) as unknown };\n } catch {\n return { text, json: undefined };\n }\n}\n\nfunction statusError(method: string, path: string, status: number, body: unknown): KizenApiError {\n const detail = formatDrfError(body);\n const message = `${method} ${path} failed with ${String(status)}${detail === undefined ? '' : `: ${detail}`}`;\n\n if (status === 401) {\n return new KizenApiError('auth_failed', message, { status, hint: AUTH_FAILED_HINT });\n }\n\n if (status === 403) {\n return new KizenApiError('forbidden', message, { status, hint: FORBIDDEN_HINT });\n }\n\n if (status === 404) {\n return new KizenApiError('not_found', message, { status });\n }\n\n return new KizenApiError('api_error', message, { status });\n}\n\nfunction listResults(method: string, path: string, data: unknown): ListPage {\n if (Array.isArray(data)) {\n return { results: data, next: null };\n }\n\n if (isRecord(data) && Array.isArray(data.results)) {\n return { results: data.results, next: data.next };\n }\n\n throw new KizenApiError('api_error', `${method} ${path} returned an unexpected response shape`);\n}\n\nexport function createKizenClient(options: KizenClientOptions): KizenClient {\n const { credentials } = options;\n const fetchImpl = options.fetch ?? fetch;\n const baseUrl = options.baseUrl ?? BASE_URLS[credentials.environment];\n\n const request = async (method: string, target: string, body?: unknown): Promise<unknown> => {\n const url = /^https?:\\/\\//.test(target) ? target : `${baseUrl}${target}`;\n const path = url.startsWith(baseUrl) ? url.slice(baseUrl.length) : url;\n const headers: Record<string, string> = {\n 'X-API-KEY': credentials.apiKey,\n 'X-USER-ID': credentials.userId,\n 'X-BUSINESS-ID': credentials.businessId,\n Accept: 'application/json',\n };\n const init: RequestInit = { method, headers };\n\n if (body !== undefined) {\n headers['Content-Type'] = 'application/json';\n init.body = JSON.stringify(body);\n }\n\n let res: Response;\n\n try {\n res = await fetchImpl(url, init);\n } catch (err) {\n throw new KizenApiError(\n 'network_error',\n `Couldn't reach Kizen at ${baseUrl}: ${errorCause(err)}${getProxyEnvStatus() === 'unavailable' ? ` ${PROXY_UNAVAILABLE_HINT}` : ''}`,\n );\n }\n\n let text: string;\n let json: unknown;\n\n try {\n ({ text, json } = await readBody(res));\n } catch (err) {\n throw new KizenApiError(\n 'network_error',\n `${method} ${path}: couldn't read the response: ${errorCause(err)}. The request may have been applied; check Kizen before retrying.`,\n { status: res.status },\n );\n }\n\n if (!res.ok) {\n throw statusError(method, path, res.status, json);\n }\n\n if (json === undefined && text !== '') {\n throw new KizenApiError(\n 'api_error',\n `${method} ${path} returned a response that is not JSON`,\n { status: res.status },\n );\n }\n\n return json;\n };\n\n const segment = encodeURIComponent;\n\n const resolveNext = (next: string): string => {\n const base = new URL(baseUrl);\n const resolved = new URL(next, base.origin);\n\n if (resolved.hostname !== base.hostname) {\n throw new KizenApiError(\n 'api_error',\n `GET /custom-objects pagination pointed at an unexpected host ${resolved.hostname}`,\n );\n }\n\n return new URL(`${resolved.pathname}${resolved.search}`, base.origin).toString();\n };\n\n return {\n async listDashboards(type: DashboardType, customObjectId?: string) {\n const params = new URLSearchParams({\n size: '10000',\n include_sharing: 'true',\n dashboard_type: type,\n });\n\n if (customObjectId !== undefined) {\n params.set('custom_object_id', customObjectId);\n }\n\n const path = `/dashboards/mine?${params.toString()}`;\n\n return listResults('GET', path, await request('GET', path)).results as WireDashboardSummary[];\n },\n\n async listCustomObjects() {\n const all: WireCustomObject[] = [];\n const seen = new Set<string>();\n let target: string | undefined = '/custom-objects?page_size=200';\n\n while (target !== undefined && !seen.has(target) && seen.size < MAX_PAGES) {\n seen.add(target);\n\n const page: ListPage = listResults('GET', target, await request('GET', target));\n\n all.push(...(page.results as WireCustomObject[]));\n target =\n typeof page.next === 'string' && page.next !== '' ? resolveNext(page.next) : undefined;\n }\n\n return all;\n },\n\n async getCustomObject(id: string) {\n const path = `/custom-objects/${segment(id)}`;\n const data = await request('GET', path);\n\n if (!isRecord(data) || typeof data.id !== 'string' || typeof data.fetch_url !== 'string') {\n throw new KizenApiError('api_error', `GET ${path} returned an unexpected response shape`);\n }\n\n return data as unknown as WireCustomObject;\n },\n\n async getClientObjectId() {\n const data = await request('GET', '/auth/bootstrap');\n const business = isRecord(data) ? data.business : undefined;\n const clientObject = isRecord(business) ? business.client_object : undefined;\n const id = isRecord(clientObject) ? clientObject.id : undefined;\n\n return typeof id === 'string' && id !== '' ? id : null;\n },\n\n async getDashboard(id: string) {\n return (await request('GET', `/dashboards/${segment(id)}`)) as WireDashboard;\n },\n\n async createDashlet(dashboardId: string, body: CreateDashletBody) {\n return (await request(\n 'POST',\n `/dashboards/${segment(dashboardId)}/dashlet`,\n body,\n )) as WireDashlet;\n },\n\n async updateDashlet(dashboardId: string, dashletId: string, body: UpdateDashletBody) {\n return (await request(\n 'PATCH',\n `/dashboards/${segment(dashboardId)}/dashlet/${segment(dashletId)}`,\n body,\n )) as WireDashlet;\n },\n };\n}\n","import { createHash } from 'node:crypto';\nimport { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\nimport type { Block } from '@kizenapps/packager';\nimport { cleanCredentialId } from '../../shared/lib/credentials.js';\nimport type {\n CreateDashletBody,\n CustomCodeContent,\n DashboardType,\n DashletLayout,\n EventScriptEntry,\n PushMapEntry,\n Surface,\n UpdateDashletBody,\n WireDashboard,\n WireDashlet,\n} from './kizenTypes.js';\n\nexport const PUSH_NAME_PREFIX = 'appbuilder:';\n\nexport const PUSH_MAP_RELATIVE_PATH = '.kizenapp/pushes.json';\n\nconst DIMENSION_KEYS = ['min_w', 'max_w', 'min_h', 'max_h', 'default_w', 'default_h'] as const;\n\ntype DimensionKey = (typeof DIMENSION_KEYS)[number];\n\nconst PUSH_MAP_STRING_FIELDS = [\n 'environment',\n 'businessId',\n 'pluginApiName',\n 'blockApiName',\n 'dashboardId',\n 'dashletId',\n 'contentHash',\n 'pushedAt',\n] as const satisfies readonly (keyof PushMapEntry)[];\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction isFiniteNumber(value: unknown): value is number {\n return typeof value === 'number' && Number.isFinite(value);\n}\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.min(Math.max(value, min), max);\n}\n\nfunction withoutCustomObject(record: Record<string, unknown>): Record<string, unknown> {\n const rest = { ...record };\n\n delete rest.custom_object;\n\n return rest;\n}\n\nexport function pushKey(pluginApiName: string, blockApiName: string): string {\n return `${PUSH_NAME_PREFIX}${pluginApiName}/${blockApiName}`;\n}\n\nexport function parsePushKey(name: string): { pluginApiName: string; blockApiName: string } | null {\n if (!name.startsWith(PUSH_NAME_PREFIX)) {\n return null;\n }\n\n const parts = name.slice(PUSH_NAME_PREFIX.length).split('/');\n\n if (parts.length !== 2) {\n return null;\n }\n\n const [pluginApiName, blockApiName] = parts;\n\n if (!pluginApiName || !blockApiName) {\n return null;\n }\n\n return { pluginApiName, blockApiName };\n}\n\nfunction pickDimensions(source: Record<string, unknown>): Partial<Record<DimensionKey, number>> {\n const dimensions: Partial<Record<DimensionKey, number>> = {};\n\n for (const key of DIMENSION_KEYS) {\n const value = source[key];\n\n if (isFiniteNumber(value)) {\n dimensions[key] = value;\n }\n }\n\n return dimensions;\n}\n\nfunction pickHostChrome(source: Record<string, unknown>): { host_chrome?: boolean } {\n return typeof source.host_chrome === 'boolean' ? { host_chrome: source.host_chrome } : {};\n}\n\nexport function toCustomCodeContent(block: Block): CustomCodeContent {\n return {\n kind: 'custom_code',\n version: 1,\n name: block.name,\n script: block.script,\n styles: block.styles,\n event_scripts: Object.entries(block.event_scripts).map(([name, script]) => ({ name, script })),\n ...pickDimensions(block as unknown as Record<string, unknown>),\n ...pickHostChrome(block as unknown as Record<string, unknown>),\n };\n}\n\nexport function buildDashletConfig(args: {\n content: CustomCodeContent;\n objectId: string;\n}): Record<string, unknown> {\n return {\n object_id: args.objectId,\n entity_type: 'static_content',\n report_type: 'html',\n chart_type: 'html',\n content: args.content,\n fe_extra_info: {},\n };\n}\n\nexport function computeMaxBottom(dashlets: readonly WireDashlet[]): number {\n let maxBottom = 0;\n\n for (const dashlet of dashlets) {\n const layout: unknown = dashlet.layout;\n\n if (!isRecord(layout)) {\n continue;\n }\n\n const { y, h } = layout;\n\n if (!isFiniteNumber(y) || !isFiniteNumber(h)) {\n continue;\n }\n\n maxBottom = Math.max(maxBottom, y + h);\n }\n\n return maxBottom;\n}\n\nexport function computeCreateLayout(\n dashlets: readonly WireDashlet[],\n content: CustomCodeContent,\n layoutId: string,\n): DashletLayout {\n const w = clamp(content.default_w ?? content.min_w ?? 6, content.min_w ?? 1, content.max_w ?? 12);\n const h = clamp(content.default_h ?? content.min_h ?? 3, content.min_h ?? 1, content.max_h ?? 99);\n\n return {\n i: layoutId,\n x: 0,\n y: computeMaxBottom(dashlets),\n w: clamp(w, 2, 12),\n h: clamp(h, 1, 99),\n };\n}\n\nexport function buildCreateBody(args: {\n pluginApiName: string;\n blockApiName: string;\n content: CustomCodeContent;\n dashlets: readonly WireDashlet[];\n objectId: string;\n layoutId: string;\n}): CreateDashletBody {\n return {\n name: pushKey(args.pluginApiName, args.blockApiName),\n layout: computeCreateLayout(args.dashlets, args.content, args.layoutId),\n config: buildDashletConfig({\n content: args.content,\n objectId: args.objectId,\n }),\n };\n}\n\nexport function buildUpdateBody(\n existing: WireDashlet,\n content: CustomCodeContent,\n): UpdateDashletBody {\n const rawConfig: unknown = existing.config;\n const config = withoutCustomObject(isRecord(rawConfig) ? rawConfig : {});\n\n return {\n config: {\n ...config,\n content,\n },\n };\n}\n\nfunction contentOf(dashlet: WireDashlet): unknown {\n const config: unknown = dashlet.config;\n\n return isRecord(config) ? config.content : undefined;\n}\n\nexport function isCustomCodeDashlet(dashlet: WireDashlet): boolean {\n const config: unknown = dashlet.config;\n\n if (!isRecord(config) || config.chart_type !== 'html') {\n return false;\n }\n\n const content = config.content;\n\n return isRecord(content) && content.kind === 'custom_code';\n}\n\nexport function findCustomCodeDashlets(dashboard: Pick<WireDashboard, 'dashlets'>): WireDashlet[] {\n return dashboard.dashlets.filter(isCustomCodeDashlet);\n}\n\nexport function customCodeName(dashlet: WireDashlet): string {\n const content = contentOf(dashlet);\n\n if (isRecord(content) && typeof content.name === 'string') {\n return content.name;\n }\n\n return dashlet.name;\n}\n\nfunction normalizeEventScripts(value: unknown): EventScriptEntry[] {\n const stringOr = (candidate: unknown): string => (typeof candidate === 'string' ? candidate : '');\n\n if (Array.isArray(value)) {\n return value\n .filter(isRecord)\n .map((entry) => ({ name: stringOr(entry.name), script: stringOr(entry.script) }));\n }\n\n if (isRecord(value)) {\n return Object.entries(value).map(([name, script]) => ({ name, script: stringOr(script) }));\n }\n\n return [];\n}\n\nfunction sortKeysDeep(value: unknown): unknown {\n if (Array.isArray(value)) {\n return value.map(sortKeysDeep);\n }\n\n if (isRecord(value)) {\n const sorted: Record<string, unknown> = {};\n\n for (const key of Object.keys(value).sort()) {\n sorted[key] = sortKeysDeep(value[key]);\n }\n\n return sorted;\n }\n\n return value;\n}\n\nfunction nameOf(value: unknown): string {\n if (typeof value === 'string') {\n return value.trim();\n }\n\n if (typeof value === 'number' || typeof value === 'boolean') {\n return String(value).trim();\n }\n\n return '';\n}\n\nexport function canonicalContentHash(content: unknown): string {\n const source = isRecord(content) ? content : {};\n const canonical = {\n name: nameOf(source.name),\n script: typeof source.script === 'string' ? source.script : '',\n styles: typeof source.styles === 'string' ? source.styles : '',\n event_scripts: normalizeEventScripts(source.event_scripts),\n ...pickDimensions(source),\n ...pickHostChrome(source),\n };\n\n return createHash('sha256')\n .update(JSON.stringify(sortKeysDeep(canonical)))\n .digest('hex');\n}\n\nexport type TargetMatch =\n | { kind: 'map'; dashlet: WireDashlet; entry: PushMapEntry }\n | { kind: 'name'; dashlet: WireDashlet }\n | { kind: 'ambiguous'; dashlets: WireDashlet[] }\n | { kind: 'none' };\n\nexport function matchPushTarget(args: {\n dashboardId: string;\n dashlets: readonly WireDashlet[];\n pluginApiName: string;\n blockApiName: string;\n entry: PushMapEntry | undefined;\n}): TargetMatch {\n const { entry } = args;\n\n if (entry?.dashboardId === args.dashboardId) {\n const mapped = args.dashlets.find((dashlet) => dashlet.id === entry.dashletId);\n\n if (mapped && isCustomCodeDashlet(mapped)) {\n return { kind: 'map', dashlet: mapped, entry };\n }\n }\n\n const key = pushKey(args.pluginApiName, args.blockApiName);\n const named = args.dashlets.filter(\n (dashlet) => dashlet.name === key && isCustomCodeDashlet(dashlet),\n );\n const [first] = named;\n\n if (named.length === 1 && first) {\n return { kind: 'name', dashlet: first };\n }\n\n if (named.length > 1) {\n return { kind: 'ambiguous', dashlets: named };\n }\n\n return { kind: 'none' };\n}\n\nexport function detectDrift(dashlet: WireDashlet, entry: PushMapEntry | undefined): boolean {\n if (entry?.dashletId !== dashlet.id) {\n return false;\n }\n\n return canonicalContentHash(contentOf(dashlet)) !== entry.contentHash;\n}\n\nexport interface PushMapKey {\n environment: string;\n businessId: string;\n pluginApiName: string;\n blockApiName: string;\n}\n\nfunction matchesKey(entry: PushMapKey, key: PushMapKey): boolean {\n return (\n entry.environment === key.environment &&\n entry.businessId === key.businessId &&\n entry.pluginApiName === key.pluginApiName &&\n entry.blockApiName === key.blockApiName\n );\n}\n\nexport function findPushMapEntry(\n entries: readonly PushMapEntry[],\n key: PushMapKey,\n): PushMapEntry | undefined {\n return entries.find((entry) => matchesKey(entry, key));\n}\n\nexport function upsertPushMapEntry(\n entries: readonly PushMapEntry[],\n entry: PushMapEntry,\n): PushMapEntry[] {\n const index = entries.findIndex((candidate) => matchesKey(candidate, entry));\n\n if (index === -1) {\n return [...entries, entry];\n }\n\n return entries.map((candidate, candidateIndex) => (candidateIndex === index ? entry : candidate));\n}\n\nexport function removePushMapEntry(\n entries: readonly PushMapEntry[],\n key: PushMapKey,\n): PushMapEntry[] {\n return entries.filter((entry) => !matchesKey(entry, key));\n}\n\nfunction toPushMapEntry(value: unknown): PushMapEntry | null {\n if (!isRecord(value)) {\n return null;\n }\n\n for (const field of PUSH_MAP_STRING_FIELDS) {\n if (typeof value[field] !== 'string') {\n return null;\n }\n }\n\n const record = value as Record<(typeof PUSH_MAP_STRING_FIELDS)[number], string>;\n\n return {\n environment: record.environment,\n businessId: cleanCredentialId(record.businessId),\n pluginApiName: record.pluginApiName,\n blockApiName: record.blockApiName,\n dashboardId: record.dashboardId,\n dashletId: record.dashletId,\n contentHash: record.contentHash,\n pushedAt: record.pushedAt,\n };\n}\n\nconst pushedAtTime = (entry: PushMapEntry): number => Date.parse(entry.pushedAt) || 0;\n\nfunction latestPerKey(entries: readonly PushMapEntry[]): PushMapEntry[] {\n const byKey = new Map<string, PushMapEntry>();\n\n for (const entry of entries) {\n const id = [entry.environment, entry.businessId, entry.pluginApiName, entry.blockApiName].join(\n '\\u0000',\n );\n const current = byKey.get(id);\n\n if (current === undefined || pushedAtTime(entry) > pushedAtTime(current)) {\n byKey.set(id, entry);\n }\n }\n\n return [...byKey.values()];\n}\n\nconst isMissingFileError = (error: unknown): boolean =>\n error instanceof Error && (error as NodeJS.ErrnoException).code === 'ENOENT';\n\nconst pushMapErrorDetail = (error: unknown): string =>\n error instanceof Error ? error.message : String(error);\n\nexport async function readPushMap(pluginDir: string): Promise<PushMapEntry[]> {\n let raw: string;\n\n try {\n raw = await readFile(join(pluginDir, PUSH_MAP_RELATIVE_PATH), 'utf8');\n } catch (error) {\n if (isMissingFileError(error)) {\n return [];\n }\n\n throw new Error(\n `Couldn't read ${PUSH_MAP_RELATIVE_PATH}: ${pushMapErrorDetail(error)}. Fix its permissions, or delete it to start a fresh push map.`,\n );\n }\n\n let parsed: unknown;\n\n try {\n parsed = JSON.parse(raw);\n } catch (error) {\n throw new Error(\n `${PUSH_MAP_RELATIVE_PATH} is not valid JSON (${pushMapErrorDetail(error)}). Fix it, or delete it to start a fresh push map.`,\n );\n }\n\n if (!Array.isArray(parsed)) {\n throw new Error(\n `${PUSH_MAP_RELATIVE_PATH} must contain a JSON array of push entries. Fix it, or delete it to start a fresh push map.`,\n );\n }\n\n return latestPerKey(\n parsed.map(toPushMapEntry).filter((entry): entry is PushMapEntry => entry !== null),\n );\n}\n\nexport async function writePushMap(\n pluginDir: string,\n entries: readonly PushMapEntry[],\n): Promise<void> {\n const filePath = join(pluginDir, PUSH_MAP_RELATIVE_PATH);\n\n await mkdir(dirname(filePath), { recursive: true });\n await writeFile(filePath, `${JSON.stringify(entries, null, 2)}\\n`, 'utf8');\n}\n\nconst DASHBOARD_TYPE_TO_SURFACE: Record<DashboardType, Surface> = {\n generic_dashboard: 'dashboard',\n homepage: 'homepage',\n chart_group: 'chart_group',\n};\n\nconst SURFACE_TO_DASHBOARD_TYPE: Record<Surface, DashboardType> = {\n dashboard: 'generic_dashboard',\n homepage: 'homepage',\n chart_group: 'chart_group',\n};\n\nexport function dashboardTypeToSurface(type: DashboardType): Surface {\n return DASHBOARD_TYPE_TO_SURFACE[type];\n}\n\nexport function surfaceToDashboardType(surface: Surface): DashboardType {\n return SURFACE_TO_DASHBOARD_TYPE[surface];\n}\n\nexport function buildDashboardUrl(args: {\n appBaseUrl: string;\n surface: Surface;\n dashboardId: string;\n customObject?: { id: string; fetchUrl?: string } | null;\n}): string {\n const base = args.appBaseUrl.replace(/\\/+$/, '');\n const id = args.dashboardId;\n\n if (args.surface === 'homepage') {\n return `${base}/home/${id}`;\n }\n\n if (args.surface === 'chart_group' && args.customObject) {\n if (args.customObject.fetchUrl === 'client') {\n return `${base}/clients/charts/${id}`;\n }\n\n return `${base}/custom-objects/${args.customObject.id}/charts/${id}`;\n }\n\n return `${base}/dashboard/${id}`;\n}\n","import { access, mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { dirname, join, posix } from 'node:path';\nimport type { ScaffoldedFile } from './createArtifacts.js';\nimport { claudeFiles } from './createCopilotFiles.js';\n\nexport const CLAUDE_SKILL_PATH = '.claude/skills/kizen-custom-block/SKILL.md';\n\nexport const STALE_CLAUDE_SKILL_WARNING =\n 'Claude files managed by appbuilder are out of date; run appbuilder setup-claude';\n\nexport type ClaudeFileStatus = 'created' | 'updated' | 'unchanged';\n\nexport interface ClaudeFilePlan {\n path: string;\n status: ClaudeFileStatus;\n}\n\nexport interface ClaudeFs {\n readFile: (path: string) => Promise<string | undefined>;\n writeFile: (path: string, content: string) => Promise<void>;\n exists: (path: string) => Promise<boolean>;\n}\n\nconst isMissing = (error: unknown): boolean =>\n error instanceof Error && 'code' in error && error.code === 'ENOENT';\n\nexport const nodeClaudeFs: ClaudeFs = {\n readFile: async (path) => {\n try {\n return await readFile(path, 'utf-8');\n } catch (error) {\n if (isMissing(error)) {\n return undefined;\n }\n\n throw error;\n }\n },\n writeFile: async (path, content) => {\n await mkdir(dirname(path), { recursive: true });\n await writeFile(path, content, 'utf-8');\n },\n exists: async (path) => {\n try {\n await access(path);\n\n return true;\n } catch {\n return false;\n }\n },\n};\n\nconst normalizeEntryDir = (entry: unknown): string | undefined => {\n if (typeof entry !== 'string' || entry.trim() === '') {\n return undefined;\n }\n\n const normalized = posix.normalize(entry.trim().replaceAll('\\\\', '/')).replace(/\\/+$/, '');\n\n if (normalized === '..' || normalized.startsWith('../') || normalized.startsWith('/')) {\n return undefined;\n }\n\n return normalized === '.' ? '' : normalized;\n};\n\nexport function entryDirsOf(manifest: unknown): string[] {\n const manifests: unknown[] = Array.isArray(manifest) ? manifest : [manifest];\n const entryDirs = manifests\n .map((entry) =>\n typeof entry === 'object' && entry !== null && 'entry' in entry\n ? normalizeEntryDir(entry.entry)\n : undefined,\n )\n .filter((entryDir): entryDir is string => entryDir !== undefined);\n\n return entryDirs.length > 0 ? [...new Set(entryDirs)] : ['src'];\n}\n\nexport async function pluginClaudeFiles(\n dir: string,\n fs: ClaudeFs = nodeClaudeFs,\n): Promise<ScaffoldedFile[]> {\n try {\n const manifest = await fs.readFile(join(dir, 'kizen.json'));\n\n return claudeFiles(manifest === undefined ? undefined : entryDirsOf(JSON.parse(manifest)));\n } catch {\n return claudeFiles();\n }\n}\n\nconst statusOf = (current: string | undefined, bundled: string): ClaudeFileStatus => {\n if (current === undefined) {\n return 'created';\n }\n\n return current === bundled ? 'unchanged' : 'updated';\n};\n\nexport async function planClaudeFiles(\n dir: string,\n fs: ClaudeFs = nodeClaudeFs,\n files: readonly ScaffoldedFile[] = claudeFiles(),\n): Promise<ClaudeFilePlan[]> {\n return Promise.all(\n files.map(async (file) => ({\n path: file.path,\n status: statusOf(await fs.readFile(join(dir, file.path)), file.content),\n })),\n );\n}\n\nexport async function applyClaudeFiles(\n dir: string,\n options: { dryRun?: boolean } = {},\n fs: ClaudeFs = nodeClaudeFs,\n files: readonly ScaffoldedFile[] = claudeFiles(),\n): Promise<ClaudeFilePlan[]> {\n const plan = await planClaudeFiles(dir, fs, files);\n\n if (options.dryRun === true) {\n return plan;\n }\n\n await Promise.all(\n files\n .filter((_file, index) => plan[index]?.status !== 'unchanged')\n .map((file) => fs.writeFile(join(dir, file.path), file.content)),\n );\n\n return plan;\n}\n\nexport async function isClaudeSkillStale(\n dir: string,\n fs: ClaudeFs = nodeClaudeFs,\n files?: readonly ScaffoldedFile[],\n): Promise<boolean> {\n try {\n const managed = files ?? (await pluginClaudeFiles(dir, fs));\n\n if (!managed.some((file) => file.path === CLAUDE_SKILL_PATH)) {\n return false;\n }\n\n if ((await fs.readFile(join(dir, CLAUDE_SKILL_PATH))) === undefined) {\n return false;\n }\n\n const plan = await planClaudeFiles(dir, fs, managed);\n\n return plan.some((entry) => entry.status !== 'unchanged');\n } catch {\n return false;\n }\n}\n\nexport interface SetupClaudeDeps {\n fs: ClaudeFs;\n log: (line: string) => void;\n error: (line: string) => void;\n setExitCode: (code: number) => void;\n}\n\nexport const defaultSetupClaudeDeps: SetupClaudeDeps = {\n fs: nodeClaudeFs,\n log: (line) => {\n console.log(line);\n },\n error: (line) => {\n console.error(line);\n },\n setExitCode: (code) => {\n process.exitCode = code;\n },\n};\n\nconst count = (plan: readonly ClaudeFilePlan[], status: ClaudeFileStatus): string =>\n `${String(plan.filter((entry) => entry.status === status).length)} ${status}`;\n\nexport async function runSetupClaude(\n dir: string,\n options: { dryRun?: boolean },\n deps: SetupClaudeDeps = defaultSetupClaudeDeps,\n files?: readonly ScaffoldedFile[],\n): Promise<void> {\n if (!(await deps.fs.exists(join(dir, 'kizen.json')))) {\n deps.error('Error: kizen.json not found. Run this command from a plugin directory.');\n deps.setExitCode(1);\n\n return;\n }\n\n const dryRun = options.dryRun === true;\n let plan: ClaudeFilePlan[];\n\n try {\n plan = await applyClaudeFiles(\n dir,\n { dryRun },\n deps.fs,\n files ?? (await pluginClaudeFiles(dir, deps.fs)),\n );\n } catch (error) {\n deps.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n deps.setExitCode(1);\n\n return;\n }\n\n for (const entry of plan) {\n deps.log(`${entry.status.padEnd(9)} ${entry.path}`);\n }\n\n const counts = `${count(plan, 'created')}, ${count(plan, 'updated')}, ${count(plan, 'unchanged')}`;\n const managed = 'these files are managed by appbuilder, so local edits to them are replaced';\n\n deps.log(\n dryRun\n ? `Dry run: ${counts}; nothing written (${managed}).`\n : `Claude files: ${counts} (${managed}).`,\n );\n}\n","---\nname: kizen-custom-block\ndescription: Use this skill when the user asks to build, change or publish a Kizen content block, custom block, chart, or dashboard/homepage visualization in this plugin. It covers the block file layout, the plugin engine runtime rules, and the appbuilder validate, preview and push loop.\n---\n\n# Kizen custom blocks\n\nFollow these rules exactly. The runtime is strict, and a push changes a live Kizen dashlet.\n\n## Keep this skill current\n\nAt the start of any block task, run `appbuilder setup-claude` in the plugin directory.\n\n- If it reports `updated` for `.claude/skills/kizen-custom-block/SKILL.md`, your loaded copy of this skill is stale. Re-read `.claude/skills/kizen-custom-block/SKILL.md` before doing anything else, and follow the new copy.\n- If it reports `created` for any file, or `updated` for `.claude/skills/kizen-custom-block/design.md`, read that file before writing any markup or styles.\n- If it reports `created` or `updated` for `lib/kizenData.js` (under the plugin's entry directory, usually `src/`), re-read its exports before using them.\n- If every file line reports `unchanged`, continue.\n- If the command doesn't exist (an older CLI), skip it and continue.\n- If it fails (for example, you aren't in the plugin directory that holds `kizen.json`), switch to that directory and run it once more. If it still fails, continue without it.\n\n`setup-claude` only rewrites the CLI-managed files: the ones in this skill directory and `src/lib/kizenData.js`. It never touches block code, so it's always safe to run.\n\n## What a block is\n\nA block is a directory under `src/blocks/<dir>/`:\n\n- `config.json` (required): `name`, `api_name` (always set it explicitly), `types` (any of `homepages`, `dashboards`, `charts` for chart groups, and `records`; a block only appears on the surfaces it lists), and the optional sizes `min_w`, `max_w`, `min_h`, `max_h`, `default_w` and `default_h`. Widths are grid columns (1 to 12) and heights are grid rows. Each size you set is a positive integer, each `min_*` is no greater than its `max_*`, and each `default_*` falls within whichever of its `min_*` and `max_*` you set. `default_w` and `default_h` are the starting size when `block push` creates a new dashlet; updates never resize an existing dashlet. Only the sizes you write are exported and pushed.\n - `host_chrome` (optional boolean, default `true`): whether the host paints the dashlet card around the block. Omit it unless you are turning chrome off. Only a value you write is exported and pushed, and any value other than `true` or `false` fails validation.\n- `script.js` (required): the render script.\n- `styles.css` (optional).\n- `eventScripts/<name>.js` (optional): one file per interactive handler.\n\nShared helpers live in `src/lib/*.js`. Import them with relative named imports only, for example `import { formatMoney } from '../../lib/format.js';`. No default imports, no bare package names.\n\n`src/lib/kizenData.js` is managed by appbuilder: `setup-claude` and CLI updates replace it. Never edit it. Put your own helpers in another file under `src/lib/`.\n\n### Host chrome\n\nDecide the mode yourself from the request. Ask the user only if they already raised it and their choice is unclear.\n\n- Keep host chrome (omit `host_chrome`) for standard data dashlets such as charts, KPIs, tables and lists that should match native cards.\n- Set `\"host_chrome\": false` for full-bleed heroes, imagery, custom-shaped cards, or any design whose background is part of the visual.\n\nChrome off, in `config.json`:\n\n```json\n{\n \"name\": \"Welcome hero\",\n \"api_name\": \"welcome_hero\",\n \"types\": [\"homepages\", \"dashboards\"],\n \"host_chrome\": false\n}\n```\n\nFollow \"Chrome off\" in `design.md` for the layout rules. In your summary to the user, state which mode you chose and why in one line. `block push --dry-run --json` shows the value as `body.config.content.host_chrome` (absent when chrome is on by default), so check it there. Changing `host_chrome` on a block you already pushed is an ordinary update: validate, then `block push <api_name> --yes --json`.\n\n## Runtime rules\n\nBlocks run in the plugin engine web worker.\n\n- `script.js` is the body of an async function, and `this` is the worker context. Use `await` at the top level.\n- There is no DOM: no `document` or `window`. There are no npm packages. Don't use `eval` or `Function`.\n- Render with `this.outputUI(htmlString)`. The output is sanitized with DOMPurify, so `<script>` tags and `on*` attributes are stripped. Don't rely on them.\n- Charts are hand-built inline SVG strings. There are no chart libraries.\n- Interactivity: put `data-script=\"<eventScriptName>\"` on a `<button>` whose content is text only. Clicking it runs `eventScripts/<eventScriptName>.js` in a fresh worker, so no state carries over from `script.js`.\n- Args:\n - `this.args.dateFilter`: `{ start, end }`, or `undefined`.\n - `this.args.teamFilter`.\n - `this.args.objectId`: set on chart groups.\n - Homepages have no date or team filter. Handle both being absent.\n- Data: read records with the `kizenData.js` helpers (see \"Reading Kizen data\"). They call `this.getWithErrors` and `this.postWithErrors`, which use relative URLs and run as the viewing user.\n- Toasts: `this.showToast(message, options)`. `message` MUST be a string. Passing an object crashes the host app.\n- Styling:\n - The host applies `* { font-size: 10px }`. Set explicit px font sizes on everything.\n - With host chrome (the default), the host paints the card (background, border, border radius and shadow) from the dashboard's style settings, like native dashlets. The block root is transparent, fills the card, and paints no card of its own.\n - With `\"host_chrome\": false`, the host paints nothing: no background, border, radius or shadow. The block root fills the card edge to edge and owns its whole look (see \"Chrome off\" in `design.md`).\n - Put chart labels inside the SVG as `<text>` so they scale with the `viewBox`.\n- The code is stored in a Kizen dashlet. Never include a NUL character or the literal text `{__ref:` anywhere in any file.\n\n## Reading Kizen data\n\nRead records through `src/lib/kizenData.js`. Always import it from `../../lib/kizenData.js`. Its helpers take the worker context as their first argument, so pass `this`.\n\n- `getFields(this, object)` loads an object's fields. `object` is the object's id or name, and Contacts is `client_client`. Match fields by `name`.\n- `blockFilters(this.args, fields)` returns `{ filters, unapplied }`. Always apply `filters`, so the block reacts to the dashboard's date and team filters the way native dashlets do (date on `created`, team on `owner`). When `unapplied` contains `'teamFilter'`, the team filter couldn't be applied (a roles-only selection, or an object with no owner field). Show \"(team filter not applied)\".\n- `dropdownFilter(field, 'Name')` or `dropdownFilter(field, ['A', 'B'])` filters a dropdown by option names.\n- `searchRecords(this, { object, fieldNames, filters })` returns `{ records, count, truncated }`. When `truncated` is true, show \"Showing first N\" with N = `records.length`.\n- `fieldValue(record, name)`, `fieldLabel(record, name)`, `countBy(records, name, field?)`, `sumBy(records, name, valueOf?)` and `formatNumber(n, prefix)` read and summarize the results. `countBy` groups empty values under `key: ''`. Filter that group out, or give it a label.\n- Every record value or label you put into markup goes through `escapeHtml(value)`, including option names, owner names and text fields. `this.outputUI` sanitizes scripts, but it keeps images, links, forms and styles, and the block renders for every viewer. `escapeHtml` is the only escaping helper; never write your own.\n- Never hand-build filter or search JSON when a helper exists. Every helper throws a readable `Error`, so wrap the fetch in `try` and render the error state from `design.md`.\n\nCount Contacts by a dropdown field named `status` for the current dashboard filters. Use a field name from `getFields`:\n\n```js\nimport {\n blockFilters,\n countBy,\n escapeHtml,\n getFields,\n searchRecords,\n} from '../../lib/kizenData.js';\n\ntry {\n const fields = await getFields(this, 'client_client');\n const { filters, unapplied } = blockFilters(this.args, fields);\n const search = { object: 'client_client', fieldNames: ['status'], filters };\n const { records, count, truncated } = await searchRecords(this, search);\n const rows = countBy(records, 'status').filter((row) => row.key !== '');\n const items = rows.map((row) => `<li>${escapeHtml(row.label)}: ${row.count}</li>`).join('');\n const note = truncated ? `Showing first ${records.length} of ${count}. ` : '';\n const team = unapplied.includes('teamFilter') ? '(team filter not applied)' : '';\n this.outputUI(`<ul>${items}</ul><p>${note}${team}</p>`);\n} catch {\n this.outputUI('<div class=\"kz-state kz-state--error\">Couldn\\'t load data.</div>');\n}\n```\n\n## Design\n\nBefore writing any markup or styles, read `design.md` in this skill directory and follow it exactly.\n\n## The loop\n\nRun these exact commands. The flags and JSON keys are the contract. `<api_name>` is the block's `config.json` `api_name`. `block targets` and `block push` both accept `-c/--credentials <path>` and `--profile <name>` to pick the credential.\n\n1. **Validate.** Run `appbuilder block export <api_name>`. Fix every validation error it prints, then run it again until it passes.\n2. **Choose the target with the user (first publish only).**\n - `appbuilder block targets --json` returns `{ surfaces: { dashboard: [...], homepage: [...] }, customObjects: [{ id, objectName, fetchUrl }] }`. Contacts appears in `customObjects` when available.\n - `appbuilder block targets --object <id> --json` returns `{ surfaces: { chart_group: [...] } }` for that object.\n - Only offer rows where `canEdit !== false`. Ask the user which surface and which specific one. Don't pick for them.\n - Optionally run `appbuilder block push <api_name> --dashboard <id> --json` to get a `needs_choice` result listing the existing custom blocks and \"new\".\n3. **Preview.** Run `appbuilder block push <api_name> --dashboard <id> [--dashlet <id> | --create] --dry-run --json`. Show the user the `environment`, `businessId`, `dashboard.name`, `action` and any `warnings`.\n4. **Apply** once the user agrees: run the same command with `--yes` in place of `--dry-run`. Treat the push as done only when `applied === true`. Give the user the returned `url`, then refresh the browser (below).\n5. **Change requests.** Edit the files, validate again (step 1), then run `appbuilder block push <api_name> --yes --json`. With no target flags it updates the remembered dashlet. Refresh the browser (below) after each push. Repeat for each change.\n\nA headless run without `--yes` is always a dry run.\n\n### Refresh the browser after a push\n\nDo this after every applied push, only when Claude-in-Chrome tools are available. Dashlets don't poll, so the user's open tab keeps the old block until it's refreshed. Don't reload the page.\n\n1. List the open tabs (`tabs_context_mcp`) and find the one whose URL has the same origin and path as the result's `url`.\n2. If there is no such tab, open `url` in a new tab (`tabs_create_mcp`) and go to step 5.\n3. If the result has a `refresh` field, run `refresh.script` exactly as given in that tab with the page JavaScript tool (`javascript_tool`). If it has no `refresh` field, navigate that tab to `url` (`navigate`) and go to step 5.\n4. Check what the script returned:\n - `{ refreshed: true, ... }`: the dashboard refetched in place.\n - `undefined`: the refresh hook isn't available on this page. Navigate the tab to `url` instead. Then run `localStorage.getItem('kizen-flag-custom-code-blocks')` in that tab with `javascript_tool`. If it isn't `'true'`, tell the user once per conversation that setting that localStorage key to `'true'` in the Kizen tab enables in-place refresh. Never set it yourself.\n5. Wait a couple of seconds, take a screenshot (`computer`), and check that the block rendered: not blank, and no visible error. Report what you saw to the user. If the block is blank or shows an error, read the console and fix the block before pushing again.\n\nNever run any other injected code in the user's tabs. `refresh.script` is the only script you may run, with one exception: the read-only `localStorage.getItem('kizen-flag-custom-code-blocks')` check above.\n\n### JSON results\n\n- Dry run: `{ ok: true, applied: false, dryRun: true, action: 'create' | 'update', environment, businessId, dashboard: { id, name, type }, dashletId | null, url, method, path, body, warnings }`.\n- Applied: `{ ok: true, applied: true, dryRun: false, action: 'created' | 'updated', ..., dashletId, url, refresh?: { dashboardId, script }, remembered }`. `refresh` is absent when the dashboard id isn't a uuid.\n- If a `block push` result's `warnings` contains `Claude files managed by appbuilder are out of date; run appbuilder setup-claude`, run `appbuilder setup-claude`, re-read `.claude/skills/kizen-custom-block/SKILL.md`, then continue.\n- Error: `{ ok: false, code, message, choice?, choices? }`. `code` is one of `needs_choice`, `validation_failed`, `invalid_block`, `auth_failed`, `forbidden`, `remembered_target_missing`, `drift_detected`, `network_error`, `credentials_invalid`, `production_requires_flag`, `not_found`, `usage_error`, `api_error` or `local_error`.\n\n### `needs_choice`\n\n`choice` is `'profile'`, `'block'`, `'dashboard'` or `'target'`. `choices` is a list of `{ value, label, args, surface?, canEdit?, pushKey?, isFromThisPlugin? }`, where `args` is a string array. Ask the user using each option's `label`, then re-run the same command with the chosen option's `args` appended exactly. Never construct these flags by hand. The \"new\" option is `{ value: 'new', args: ['--dashboard', <id>, '--create'] }`.\n\n## Guardrails\n\n- Never pass `--allow-production` unless the user explicitly asked, in this conversation, to publish to production (`go` or `fmo`).\n- On `drift_detected`, stop and ask the user. Someone edited the block in Kizen since your last push, and `--force` overwrites their changes. Pass `--force` only when the user says to discard them.\n- On `needs_choice`, ask the user using the returned `choices` as described above. Never guess.\n- On `remembered_target_missing`, the remembered dashboard or dashlet is gone. Ask the user where to publish instead, then push with `--dashboard <id>` plus `--create` or a `--dashlet` choice, or use `--forget` to clear the memory. `--create` alone won't work.\n- On `credentials_invalid`, tell the user to fix the credential file named in `message`, or to pass `--profile` or `-c`.\n- On `production_requires_flag`, the target is `go` or `fmo`. Apply the production rule above.\n- Never push to a new target without first showing the user a dry run.\n- Blocks run with the viewing user's permissions for every viewer. Don't write code that creates, updates or deletes data unless the user asked for it.\n","# Designing a Kizen custom block\n\nWith host chrome (the default), a block must look like a native Kizen dashlet. Follow every rule here exactly. Where a rule says \"use judgment\", pick the option that looks most native. A block whose `config.json` sets `\"host_chrome\": false` follows section M for its card and outer box, and skips every rule marked \"with host chrome\".\n\n## A. Card and outer box (with host chrome)\n\nThe host paints the card. Background, border, border radius and drop shadow all come from the dashboard's style settings, the same as native dashlets.\n\n- Never paint a card. The block root has no background (it stays transparent), no border, no `border-radius`, no `box-shadow` and no outer margin.\n- The block's content box starts at the card's top-left corner (0,0) and fills the whole card. The host body padding is 0. The root is always `width: 100%; height: 100%; box-sizing: border-box;`.\n- The host draws a 46px header overlay (`position: absolute`, padding `11px 15px 15px`) over the block's top edge. The dashlet menu appears at its top right on hover. The top-right strip, 60px wide and 46px tall from the card's top edge, must hold no interactive controls and no text. Non-interactive chart marks may pass under it.\n- The native grid has a 10px gap between cards and around the grid. Row height is 105px (100px at the mobile, 2-column breakpoint), so a card is `rows * 105 + (rows - 1) * 10` px tall. Width depends on the breakpoint's column count.\n- Blocks are fluid. Never assume a pixel size. Use percentages, flex or grid, and an SVG `viewBox`.\n- Set `default_w` (columns) and `default_h` (rows) in `config.json` so the content fits comfortably at its starting size: roughly 3×2 for a KPI tile, 6×4 for a chart, and 6×5 for a table or list. A card `rows` tall is `rows * 105 + (rows - 1) * 10` px, so 2 rows is 220px, 4 rows is 440px and 5 rows is 565px. Keep each default within any `min_*` and `max_*` the block sets.\n\n## B. Inner spacing\n\nWith host chrome, measure these insets from the card's edge. With chrome off, measure them from the edge of the block-owned card, or follow section M for full bleed.\n\n- Horizontal inset: 15px left and right, matching the native body padding `0 15px`.\n- With a header, use the native header band (section C). Content under a header starts at 35px from the top. The header overlay still covers the card down to 46px, so the top-right strip 60px wide from 35px to 46px must hold no interactive controls or text.\n- Without a header, use 15px top padding. The same top-right strip, 60px wide down to 46px, stays free of controls and text.\n- Bottom padding: 15px.\n- Major gaps use 15px: between a KPI value and its comparison row, and between sections.\n- Minor gaps use 10px: legend rows, list-row vertical padding, and the padding above a legend.\n\n```css\n.kz-block {\n box-sizing: border-box;\n width: 100%;\n height: 100%;\n padding: 15px;\n display: flex;\n flex-direction: column;\n font-family: var(--font-family-sans-serif);\n color: var(--color-font-primary);\n}\n.kz-block--with-header {\n padding-top: 0;\n}\n```\n\n## C. Header (optional; use judgment)\n\nA block doesn't need a header, and it may use a different kind of header when the content calls for one. When it shows a native-style title, match native exactly:\n\n- A band 35px tall with padding `7.5px 60px 7.5px 15px`. The 60px right padding keeps long titles out from under the hover menu.\n- Title text 12px, weight 100 (Proxima Nova Light), `text-transform: uppercase`, `color: var(--color-font-primary)`, `line-height: 20px`, left-aligned at 15px.\n- Blocks can't read per-dashboard title-style settings, so always use these defaults.\n- Copy `.kz-header` from the example below. Its `margin: 0 -15px` cancels the root's side padding so the title lands at 15px.\n\n## D. Typography\n\n- Font: Proxima Nova through `font-family: var(--font-family-sans-serif)`. The host already loads it.\n- The host applies `* { font-size: 10px; line-height: 1 }`. Set an explicit px `font-size` on every text element.\n- Scale (px): hero 32, header 24, subheader 18, body 14, button 13, label 12, small 11, micro 10.\n- Weights: 100 light, 400 regular, 600 bold, 900 black.\n- Text colors: `var(--color-font-primary)` (#4A5660) for primary text, `var(--color-font-secondary)` (#7E8C98) for secondary text, `var(--color-font-placeholder)` (#A8B3BC) for muted text and captions.\n- Header titles and category or axis labels are uppercase. Legend labels use sentence case.\n\n## E. Color tokens\n\nAlways use CSS custom properties. Never write raw hex, because themes can change the values. The hex values below are reference only.\n\n| Use | Token | Default |\n| ------------------------ | -------------------------------------------- | ------- |\n| Surface | `--color-background-white` | #FFFFFF |\n| Surface | `--color-background-light` | #F5F6F7 |\n| Surface | `--color-background-lighter` | #F9FAFB |\n| Surface | `--color-background-medium` | #D8DDE1 |\n| Surface | `--color-background-dark` | #A8B3BC |\n| Surface | `--color-background-darker` | #4A5660 |\n| Surface | `--color-background-hover` | #D8EAFD |\n| Border, divider | `--color-border-medium` | #D8DDE1 |\n| Border, divider | `--color-border-medium-light` | #ECEEF0 |\n| Border, divider | `--color-border-light` | #F5F6F7 |\n| Links, secondary actions | `--color-button-secondary-default`, `-hover` | #4090F7 |\n| Primary actions | `--color-button-primary-default`, `-hover` | #4BC7B4 |\n| Status good | `--color-viz-cat-1-primary` | #32C055 |\n| Status bad | `--color-viz-cat-7-primary` | #EB272B |\n\nColor SVG through CSS classes in `styles.css`, for example `.bar-1 { fill: var(--color-viz-cat-1-primary); }`. Never use `fill=\"var(...)\"` attributes; they aren't reliable.\n\n## F. Charts\n\nNative dashlets use amCharts 5. Blocks hand-build SVG that mimics it.\n\n- Series palette, in order: `--color-viz-cat-N-primary` for N = 1 to 10 (the tokens native charts read). The paired light shade `--color-viz-cat-N-secondary` is for backgrounds, tracks and comparison series.\n- Defaults (primary / secondary): 1 #32C055 / #ADE6BB, 2 #285DE4 / #6FB2F9, 3 #F3A800 / #FADC99, 4 #4926CC / #B7A6EA, 5 #38B3B9 / #9BD9DB, 6 #F26C56 / #F4A63A, 7 #EB272B / #FF8A8A, 8 #D100A0 / #FF85E2, 9 #AE764A / #D6BAA4, 10 #7A7A7A / #BCBCBC.\n- Axis labels: `fill: var(--color-background-dark)`, 10 to 11 user units, small and muted.\n- Gridlines: `stroke: var(--color-border-medium-light)`, 1px.\n- Tooltip, if you draw one: background `var(--color-background-darker)`, text `var(--color-background-white)`.\n- Donut: 2px white gaps between segments (`stroke: var(--color-background-white); stroke-width: 2;`).\n- Dashed forecast or incomplete segments: `stroke-dasharray: 4 4;`.\n- Legend: 8px circular dots, 10px gap to a 10px label, 20px column gap between items, 10px row gap when wrapping, 10px padding above the legend.\n- Put chart labels inside the SVG as `<text>` so they scale with the `viewBox`.\n\n## G. KPI tiles\n\nThe value is hero 32px, weight 400, `var(--color-font-primary)`, centered when it stands alone. A comparison or delta row sits 15px below it, `var(--color-viz-cat-1-primary)` when good and `var(--color-viz-cat-7-primary)` when bad.\n\n## H. Number formatting\n\nMatch the native `collapseNumber` rules:\n\n- Not a number: `0`.\n- |n| < 1: up to 4 decimals, trailing zeros removed.\n- |n| < 1,000: up to 5 significant digits, trailing zeros removed.\n- 1,000 to 9,999: an integer with a thousands separator.\n- 10,000 and up: round to 4 significant digits first, then show K, M or B.\n- 1 trillion and up: `999B+`, with no sign.\n- Currency: prefix the symbol, for example `$`.\n\nNever copy or rewrite this helper. Import it from the CLI-managed data lib:\n\n```js\nimport { formatNumber } from '../../lib/kizenData.js';\n```\n\n## I. States\n\n- Loading: a centered, subtle \"Loading…\" line on a transparent background (with chrome off, on whatever background the block paints). Render it with `this.outputUI` first, before any data fetch.\n- Empty: centered \"No Data\", 32px, `color: var(--color-background-medium)`.\n- Error: a centered 14px message in `var(--color-font-secondary)`, for example \"Couldn't load data.\" Never show raw error objects.\n\n## J. Icons\n\nInline SVG only, with `fill: currentColor` or a token applied through a class. Icon fonts and host icon classes aren't available.\n\n## K. Scrollbars\n\nEvery scroll container uses the app's expanding scrollbar. Add the `kds-expanding-scrollbar` class to the element that scrolls, for example `<div class=\"kz-list kds-expanding-scrollbar\">`. The host finds these containers on its own, including ones that render later, and attaches the native thin bar that widens on hover.\n\n- Put the class on the element that has `overflow: auto`, not on its parent. Give that element a bounded height, usually a flex child with `flex: 1; min-height: 0`.\n- Never style scrollbars yourself: no `::-webkit-scrollbar` rules, `scrollbar-width` or `scrollbar-color`.\n- Only scroll when the content really is a list. Otherwise fit the content to the card.\n\n## L. Don'ts\n\n- With host chrome, don't paint an outer card, shadow or border.\n- Don't use fixed pixel widths.\n- Don't use raw hex colors.\n- Don't use `em` or `rem` units. The base is 10px, so they surprise.\n- Don't load custom web fonts.\n- Don't put content under the top-right menu area.\n- Don't add a scroll container without `kds-expanding-scrollbar` (section K).\n\n## M. Chrome off (`\"host_chrome\": false`)\n\nThe host paints no background, border, radius or shadow. The block root is still `width: 100%; height: 100%; box-sizing: border-box;` and starts at the card's top-left corner (0,0) with no host padding. Pick one of these layouts:\n\n- Transparent full bleed: the root fills the card edge to edge and the dashboard background shows through wherever the block paints nothing. Use it for heroes and imagery, for example a `background-image` with `background-size: cover` on the root.\n- Block-owned card: the block paints its own card with its own background, `border-radius`, border and `box-shadow`, using tokens. The host card still clips at its edges (`overflow: hidden`), so inset the card from the root by at least its shadow's blur plus offset, usually 8 to 12px (for example `padding: 10px` on the root with the card inside). A card with no inset loses its shadow.\n\nThe host adds no backdrop behind its controls, so keep two areas visually quiet, with no dark or busy art directly under them:\n\n- The top-right menu strip, 60px wide and 46px tall. It still holds no interactive controls and no text.\n- The top-left drag-handle area in edit mode, about 30px square. The handle icon sits 5px from the left and 10px from the top and is 15px tall.\n\nSection A's grid, fluid-size and default-size rules, section C (when you show a native-style header), sections D to K and the rest of section L still apply. Inside a block-owned card, use section B's spacing.\n\n## Example: header, bar chart and legend\n\nThe block counts Contacts by their `status` dropdown for the current dashboard filters, with the helpers from `src/lib/kizenData.js` (see \"Reading Kizen data\" in `SKILL.md`). Swap `OBJECT` and `FIELD` for the object and field the user asked about. The chart's only text is the y-axis labels at the left edge and the category labels along the bottom, so nothing lands in the top-right strip under the menu.\n\n`script.js`:\n\n```js\nimport {\n blockFilters,\n countBy,\n escapeHtml,\n fieldByName,\n formatNumber,\n getFields,\n searchRecords,\n} from '../../lib/kizenData.js';\n\nconst OBJECT = 'client_client';\nconst FIELD = 'status';\n\nconst render = (body) =>\n this.outputUI(\n `<div class=\"kz-block kz-block--with-header\"><div class=\"kz-header\">Contacts by status</div>${body}</div>`,\n );\n\nrender('<div class=\"kz-state\">Loading…</div>');\n\nlet rows;\nlet notes;\ntry {\n const fields = await getFields(this, OBJECT);\n const field = fieldByName(fields, FIELD);\n if (!field) throw new Error(`${OBJECT} has no ${FIELD} field`);\n const { filters, unapplied } = blockFilters(this.args, fields);\n const { records, count, truncated } = await searchRecords(this, {\n object: OBJECT,\n fieldNames: [FIELD],\n filters,\n });\n rows = countBy(records, FIELD, field).filter((row) => row.key !== '');\n notes = [\n truncated ? `Showing first ${formatNumber(records.length)} of ${formatNumber(count)}` : '',\n unapplied.includes('teamFilter') ? '(team filter not applied)' : '',\n ].filter(Boolean);\n} catch {\n render('<div class=\"kz-state kz-state--error\">Couldn\\'t load data.</div>');\n return;\n}\n\nif (rows.length === 0) {\n render('<div class=\"kz-state kz-state--empty\">No Data</div>');\n return;\n}\n\nconst W = 300,\n H = 150,\n left = 36,\n top = 6,\n bottom = 18;\nconst plot = H - top - bottom;\nconst max = Math.max(...rows.map((r) => r.count)) || 1;\nconst y = (v) => top + plot - (v / max) * plot;\nconst step = (W - left) / rows.length;\nconst barW = Math.min(20, step / 2);\n\nconst grid = [0, 0.5, 1]\n .map((f) => f * max)\n .map(\n (t) =>\n `<line class=\"grid\" x1=\"${left}\" x2=\"${W}\" y1=\"${y(t)}\" y2=\"${y(t)}\"/>` +\n `<text class=\"axis\" x=\"${left - 6}\" y=\"${y(t) + 3}\" text-anchor=\"end\">${formatNumber(t)}</text>`,\n )\n .join('');\n\nconst bars = rows\n .map((r, i) => {\n const cx = left + i * step + step / 2;\n return (\n `<rect class=\"bar\" x=\"${cx - barW / 2}\" y=\"${y(r.count)}\" width=\"${barW}\" height=\"${top + plot - y(r.count)}\"/>` +\n `<text class=\"axis\" x=\"${cx}\" y=\"${H - 4}\" text-anchor=\"middle\">${escapeHtml(r.label)}</text>`\n );\n })\n .join('');\n\nrender(\n `<div class=\"kz-chart\"><svg viewBox=\"0 0 ${W} ${H}\">${grid}${bars}</svg></div>` +\n '<div class=\"kz-legend\">' +\n '<span class=\"kz-legend__item\"><span class=\"kz-dot\"></span>Contacts</span>' +\n notes.map((note) => `<span class=\"kz-note\">${escapeHtml(note)}</span>`).join('') +\n '</div>',\n);\n```\n\n`styles.css`:\n\n```css\n.kz-block {\n box-sizing: border-box;\n width: 100%;\n height: 100%;\n padding: 15px;\n display: flex;\n flex-direction: column;\n font-family: var(--font-family-sans-serif);\n color: var(--color-font-primary);\n}\n.kz-block--with-header {\n padding-top: 0;\n}\n.kz-header {\n flex: none;\n box-sizing: border-box;\n height: 35px;\n margin: 0 -15px;\n padding: 7.5px 60px 7.5px 15px;\n font-size: 12px;\n font-weight: 100;\n line-height: 20px;\n text-transform: uppercase;\n color: var(--color-font-primary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.kz-state {\n flex: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n text-align: center;\n font-size: 14px;\n color: var(--color-font-placeholder);\n}\n.kz-state--empty {\n font-size: 32px;\n color: var(--color-background-medium);\n}\n.kz-state--error {\n font-size: 14px;\n color: var(--color-font-secondary);\n}\n.kz-chart {\n flex: 1;\n min-height: 0;\n}\n.kz-chart svg {\n display: block;\n width: 100%;\n height: 100%;\n}\n.grid {\n stroke: var(--color-border-medium-light);\n stroke-width: 1;\n}\n.axis {\n fill: var(--color-background-dark);\n font-size: 10px;\n}\n.bar {\n fill: var(--color-viz-cat-1-primary);\n}\n.kz-legend {\n flex: none;\n display: flex;\n flex-wrap: wrap;\n column-gap: 20px;\n row-gap: 10px;\n padding-top: 10px;\n}\n.kz-legend__item {\n display: flex;\n align-items: center;\n gap: 10px;\n font-size: 10px;\n color: var(--color-font-primary);\n}\n.kz-dot {\n flex: none;\n width: 8px;\n height: 8px;\n border-radius: 50%;\n background: var(--color-viz-cat-1-primary);\n}\n.kz-note {\n font-size: 10px;\n color: var(--color-font-placeholder);\n}\n```\n","# Copilot review instructions for this Kizen plugin\n\nThis repo is a Kizen plugin app: a `kizen.json` manifest plus the artifacts\nthat `@kizenapps/packager` finds by walking the directory tree under the\nmanifest's `entry` (default `src/`). No manifest key lists artifacts. The\ndirectory layout decides what gets packaged.\n\n## Component directories\n\nUnder `entry`, the packager treats these directory names as component types:\n\n- `floatingFrames`\n- `blocks`\n- `dataAdornments`\n- `pages`\n- `views`\n- `toolbarItems`\n- `objectSettingsItems`\n- `actions`\n- `routeScripts`\n- `automationSteps`\n- `calendarSources`\n\nEvery directory under a component type needs a `config.json`. `views/` is the\none exception.\n\n## `api_name` rules\n\n- An `api_name` must match `/^[a-z_][a-z0-9_]+$/`: lowercase letters, digits\n and underscores, starting with a letter or underscore, at least 2 characters.\n- Set `api_name` explicitly in each artifact's `config.json`. The fallback\n lowercases and strips the directory name (`myFrame` becomes `myframe`), and\n that result can collide with another artifact's explicit `api_name`.\n- Data adornments have no `api_name` field. Flag one that adds it as dead\n configuration.\n- Sibling components in the same directory need unique `api_name`s. `pages/`\n and `views/` go further and share one namespace, so a page and a view with\n the same `api_name` collide even though they live in different directories.\n\n## A green build does not mean a correct artifact\n\nThe packager coerces malformed artifact config instead of rejecting it: an\ninvalid `field_type` on a data adornment becomes `phonenumber`, and an invalid\n`minimized_style` on a floating frame becomes `circle`. It also says nothing\nabout a missing required field. Publishing is the real gate. The publish step\ncreates each artifact with no defaulting, so a field the packager never emitted\nis absent and the publish request 400s. Review each\n`config.json` as if the build will not catch mistakes in it, because for these\ncases it does not.\n\nPublishing an app requires these fields per artifact type. An artifact missing\none builds clean and fails to publish:\n\n| Artifact | Required fields |\n| --- | --- |\n| Floating frame | `api_name`, `name`, `title` |\n| Block | `api_name`, `name` |\n| Data adornment | `field_type` (one of `phonenumber`, `date`, `datetime`) |\n| Routable page | `api_name`, `name` |\n| Toolbar item | `api_name`, `label`, and a non-blank `script.js` |\n| Object settings item | `api_name`, `label`, and a non-blank `script.js` |\n| JS action | `api_name`, `name`, `hint_object_name` (non-blank) |\n\nA floating frame whose `default_position` ends in `-fixed` must set\n`minimized_style: \"circle\"` or omit `minimized_style`. Any other value fails\nthe build with `structure/fixed-frame-minimized-style`.\n\n## Publishing\n\nPublishing an app requires exactly one `thumbnail.png`, and it must sit inside\nthe `entry` directory (`src/thumbnail.png` by default). The packager never sees\na thumbnail at the repo root, and publishing then fails with \"Thumbnail is\nrequired for publishing\".\n\n## Scope\n\nThis file covers repo structure and general review. Two path-scoped files\ncover the rest: `.github/instructions/security.instructions.md` for\nsecurity-sensitive patterns and\n`.github/instructions/version-discipline.instructions.md` for manifest version\nbumps.\n","---\napplyTo: \"src/**/*.js,kizen.json\"\n---\n\n# Security review rules for plugin scripts\n\nThese rules mirror the `security/*` validation rules in `@kizenapps/packager`.\nFlag violations the way the packager would, and also flag the patterns listed\nhere that its static scan cannot detect.\n\n## `__dangerouslySkipProxy`\n\nThe packager lets `__dangerouslySkipProxy` through with the build WARNING\n`security/dangerously-skip-proxy`. Flag every occurrence for human review\nanyway, because the request leaves the browser directly instead of passing\nthrough the Kizen proxy.\n\n## Plaintext credentials\n\nIn `kizen.json`, a service's `auth_credentials.token`,\n`auth_credentials.password` and `auth_credentials.client_secret` must each be\none of:\n\n- an encrypted envelope (`{ \"encrypted\": true, \"value\": \"...\" }`) that\n `appbuilder encrypt` produced\n- a `{{secret.KEY}}` reference, with `KEY` declared in `base_config.secrets`\n- a reference through `auth_credentials.integration_secret_api_name`\n\nA raw literal in any of those three fields is the build ERROR\n`security/plaintext-credential`. Treat a credential that reaches a commit in\nplaintext as compromised and rotate it; deleting the line does not undo the\nexposure.\n\n`client_id` is excluded from this rule on purpose. Public client ids are not\nsensitive, so do not flag them.\n\n## Undeclared secret references\n\nA `{{secret.KEY}}` reference whose `KEY` is missing from `base_config.secrets`\nis the build ERROR `security/undeclared-secret-reference`, because nothing\nwould supply the value at install time.\n\n## Dynamic code execution\n\n`eval(...)`, `new Function(...)` or `Function(...)`, and a string argument to\n`setTimeout` or `setInterval` are the build ERROR `security/dynamic-code`.\n\nThis rule catches direct, literal usage only. The packager's scan is\nparser-based, so a call built through a computed property or a reassigned\nreference gets past it. Obfuscated dynamic code stays a human-review concern.\n\n## Secret logging and exfiltration\n\nThe packager has no static check for a secret that gets logged, sent to an\nunexpected endpoint, or otherwise exfiltrated. Review for this by hand: look\nfor credentials or decrypted secret values flowing into `console.log`, error\nmessages, analytics calls, or outbound requests to anything other than the\nservice they belong to.\n\n## Handling secrets in this repo\n\nEncrypt secrets locally with `appbuilder encrypt` before committing them. Do\nnot commit a plaintext secret value in any form; a comment, a script fixture,\nand a commit you intend to rewrite later all count.\n","---\napplyTo: \"kizen.json\"\n---\n\n# Version-bump discipline for `kizen.json`\n\n## What a wrong bump breaks\n\nA business that installs this plugin accumulates its own stored state\n(automation runs, config values, references to entities) shaped by what was\npublished at the time. Publishing is additive: it never rewrites a business's\nstored rows, and the plugin author has no way to migrate that state for them.\nA change is breaking when it invalidates an assumption the business's existing\ndata already depends on.\n\nA MINOR or PATCH republish applies at once to a business's running automations\nand installed artifacts. Only a new MAJOR version waits for the business to\nupgrade explicitly. A change that needed MAJOR but shipped as MINOR or PATCH\ntherefore breaks the business with no upgrade gate in between.\n\nTwo kinds of change get MAJOR because they fail without an error:\n\n- Renaming a config field, changing its type, or adding a required key. A\n template reference like `{{config.key}}` for a key that no longer exists\n resolves to a literal `null`, and the artifact renders wrong or does\n nothing.\n- Removing or renaming a JS action. A business's automation and UI\n associations key on the action's `api_name` as a plain string, with no\n foreign key. After a rename or removal those associations stop firing.\n\nReview every `kizen.json` diff against the table below before approving the\nversion bump in the same PR.\n\n## Bump matrix\n\n| Resource | Change | Required bump |\n| --- | --- | --- |\n| Plugin | change `api_name` | **HARD-BLOCK**: identity can never change |\n| Service | add | MINOR |\n| Service | remove | MAJOR |\n| Service | change auth type or `auth_level` | MAJOR |\n| Service | change `auth_credentials` (client id/secret, scopes, authorize/token URLs) | MAJOR |\n| Service | change base URL or other non-auth field | PATCH |\n| Service | rename `api_name` | MAJOR |\n| Secret | add | MINOR |\n| Secret | remove | MINOR |\n| Secret | rename key | MAJOR |\n| Secret | re-encrypt value only | PATCH |\n| Automation step | add | MINOR |\n| Automation step | remove entire step | MAJOR |\n| Automation step | remove an input or output | MAJOR |\n| Automation step | change input/output `data_type` | MAJOR |\n| Automation step | add required input | MAJOR |\n| Automation step | add optional input | MINOR |\n| Automation step | change python runtime | PATCH |\n| Automation step | edit script body only | PATCH |\n| Artifact (frame, block, adornment, page, route script, toolbar/object-settings item, calendar source) | add | MINOR |\n| Artifact | remove | MINOR |\n| Artifact | rename `api_name` | MINOR |\n| Artifact | edit script or behavior | PATCH |\n| JS action | add | MINOR |\n| JS action | remove | MAJOR |\n| JS action | rename `api_name` | MAJOR |\n| JS action | change `hint_object_name` or script | PATCH |\n| Config field | add optional (with default) | MINOR |\n| Config field | add required (no default) | MAJOR |\n| Config field | remove | MINOR |\n| Config field | rename | MAJOR |\n| Config field | change type | MAJOR |\n| Config field | change default or label | PATCH |\n| `required_entitlement` | add gating | MINOR |\n| `required_entitlement` | change or remove | PATCH |\n| Manifest metadata (`name`, `description`, `entry`, `release_branches`, `release_environments`, `published`, `developer_business_id`) | any change | PATCH |\n","const MAX_PAGE_SIZE = 1000;\nconst DEFAULT_MAX_PAGES = 10;\n\nconst fieldCache = new Map();\n\nexport const formatNumber = (input, prefix = '') => {\n const n = Number.isNaN(Number(input)) ? 0 : Number(input);\n const abs = Math.abs(n);\n const sign = n < 0 ? '-' : '';\n if (abs < 1) return `${sign}${prefix}${Number(abs.toFixed(4))}`;\n if (abs < 1000) return `${sign}${prefix}${Number(abs.toPrecision(5))}`;\n if (abs < 10000) return `${sign}${prefix}${Math.round(abs).toLocaleString()}`;\n const rounded = Number(abs.toPrecision(4));\n if (rounded >= 1e12) return `${prefix}999B+`;\n const [unit, suffix] = rounded >= 1e9 ? [1e9, 'B'] : rounded >= 1e6 ? [1e6, 'M'] : [1e3, 'K'];\n return `${sign}${prefix}${Number((rounded / unit).toPrecision(4))}${suffix}`;\n};\n\nconst HTML_ESCAPES = { '&': '&', '<': '<', '>': '>', '\"': '"', \"'\": ''' };\n\nexport const escapeHtml = (value) =>\n value === null || value === undefined\n ? ''\n : String(value).replace(/[&<>\"']/g, (char) => HTML_ESCAPES[char]);\n\nconst describeError = (error) => {\n if (typeof error === 'string') return error;\n if (error instanceof Error) return error.message;\n if (error && typeof error === 'object') {\n if (typeof error.message === 'string') return error.message;\n try {\n return JSON.stringify(error);\n } catch {\n return String(error);\n }\n }\n return String(error);\n};\n\nconst loadFields = async (ctx, object) => {\n const [data, error] = await ctx.getWithErrors(\n `/custom-objects/${encodeURIComponent(object)}/fields`,\n );\n if (error) {\n throw new Error(`Couldn't load fields for ${object}: ${describeError(error)}`);\n }\n if (!Array.isArray(data)) {\n throw new Error(`Couldn't load fields for ${object}: the response was not a list of fields`);\n }\n return data;\n};\n\nexport const getFields = (ctx, object) => {\n if (!fieldCache.has(object)) {\n const pending = loadFields(ctx, object);\n fieldCache.set(object, pending);\n pending.catch(() => {\n if (fieldCache.get(object) === pending) fieldCache.delete(object);\n });\n }\n return fieldCache.get(object);\n};\n\nexport const fieldByName = (fields, name) => fields.find((field) => field.name === name);\n\nconst nonCustomFilter = (field, condition, value) => ({\n type: 'fields_v2',\n subtype: 'non_custom',\n field,\n condition,\n value,\n});\n\nexport const blockFilters = (args, fields) => {\n const filters = [];\n const unapplied = [];\n const dateFilter = args?.dateFilter;\n const teamFilter = args?.teamFilter;\n\n if (dateFilter) {\n if (dateFilter.start && dateFilter.end) {\n filters.push(nonCustomFilter('created', 'between', [dateFilter.start, dateFilter.end]));\n } else {\n unapplied.push('dateFilter');\n }\n }\n\n const teamMembers = teamFilter?.teamMembers ?? [];\n const roles = teamFilter?.roles ?? [];\n\n if (teamMembers.length > 0) {\n if (fieldByName(fields, 'owner')) {\n filters.push(nonCustomFilter('owner', 'is_any_of', [...teamMembers]));\n } else {\n unapplied.push('teamFilter');\n }\n } else if (roles.length > 0) {\n unapplied.push('teamFilter');\n }\n\n return { filters, unapplied };\n};\n\nexport const dropdownFilter = (field, optionNameOrNames) => {\n const names = Array.isArray(optionNameOrNames) ? optionNameOrNames : [optionNameOrNames];\n const ids = names.map((name) => {\n const option = (field.options ?? []).find((candidate) => candidate.name === name);\n if (!option) {\n throw new Error(`${field.display_name ?? field.name} has no option named \"${name}\"`);\n }\n return option.id;\n });\n const multiple = Array.isArray(optionNameOrNames);\n return {\n type: 'fields_v2',\n subtype: 'custom',\n field: `custom::${field.id}`,\n condition: multiple ? 'is_any_of' : '=',\n value: multiple ? ids : ids[0],\n };\n};\n\nexport const searchRecords = async (\n ctx,\n {\n object,\n fieldNames,\n filters = [],\n pageSize = MAX_PAGE_SIZE,\n maxPages = DEFAULT_MAX_PAGES,\n ordering,\n },\n) => {\n const size = Number.isFinite(Number(pageSize))\n ? Math.max(1, Math.min(MAX_PAGE_SIZE, Math.floor(Number(pageSize))))\n : MAX_PAGE_SIZE;\n const pages = Number.isFinite(Number(maxPages))\n ? Math.max(1, Math.floor(Number(maxPages)))\n : DEFAULT_MAX_PAGES;\n const body = {\n field_names: fieldNames,\n query: Array.isArray(filters) && filters.length > 0 ? [{ and: true, filters }] : [],\n };\n const orderingParam = ordering ? `&ordering=${encodeURIComponent(ordering)}` : '';\n const records = [];\n let count = 0;\n let hasMore = false;\n\n for (let page = 1; page <= pages; page += 1) {\n const [data, error] = await ctx.postWithErrors(\n `/records/${encodeURIComponent(object)}/search?page_size=${size}&page=${page}${orderingParam}`,\n body,\n );\n if (error) {\n throw new Error(`Couldn't search ${object}: ${describeError(error)}`);\n }\n const results = Array.isArray(data?.results) ? data.results : [];\n records.push(...results);\n count = typeof data?.count === 'number' ? data.count : records.length;\n hasMore = Boolean(data?.next) && results.length > 0;\n if (!hasMore) break;\n }\n\n return { records, count, truncated: hasMore || count > records.length };\n};\n\nconst fieldEntry = (record, name) =>\n Object.values(record?.fields ?? {}).find((entry) => entry?.name === name);\n\nexport const fieldValue = (record, name) => fieldEntry(record, name)?.value;\n\nconst labelOf = (value) => {\n if (value === null || value === undefined || value === '') return '';\n if (Array.isArray(value)) return value.map(labelOf).filter(Boolean).join(', ');\n if (typeof value === 'object') {\n if ('amount' in value) {\n if (value.amount === null || value.amount === undefined || value.amount === '') return '';\n return formatNumber(Number(value.amount), value.symbol ?? '');\n }\n if ('first_name' in value || 'last_name' in value) {\n const fullName = [value.first_name, value.last_name].filter(Boolean).join(' ');\n return fullName || value.email || '';\n }\n return String(value.name ?? value.display_name ?? '');\n }\n return String(value);\n};\n\nexport const fieldLabel = (record, name) => labelOf(fieldValue(record, name));\n\nconst keyOf = (value) => {\n if (value === null || value === undefined) return '';\n if (typeof value === 'object') return String(value.id ?? labelOf(value));\n return String(value);\n};\n\nconst valuesOf = (value) => {\n if (Array.isArray(value)) return value.length > 0 ? value : [null];\n return [value];\n};\n\nexport const countBy = (records, name, field) => {\n const groups = new Map();\n\n for (const record of records) {\n for (const value of valuesOf(fieldValue(record, name))) {\n const key = keyOf(value);\n const group = groups.get(key);\n if (group) {\n group.count += 1;\n } else {\n groups.set(key, { key, label: labelOf(value), count: 1 });\n }\n }\n }\n\n const order = new Map(\n (field?.options ?? [])\n .filter((option) => typeof option.order === 'number' && Number.isFinite(option.order))\n .map((option) => [String(option.id), option.order]),\n );\n const rank = (key) => (order.has(key) ? order.get(key) : Number.POSITIVE_INFINITY);\n\n return [...groups.values()].sort((a, b) => {\n if (b.count !== a.count) return b.count - a.count;\n const ra = rank(a.key);\n const rb = rank(b.key);\n return ra === rb ? 0 : ra < rb ? -1 : 1;\n });\n};\n\nconst numberOf = (value) => {\n if (value === null || value === undefined || value === '') return 0;\n const raw = typeof value === 'object' ? value.amount : value;\n if (raw === null || raw === undefined || raw === '') return 0;\n const n = Number(raw);\n return Number.isFinite(n) ? n : 0;\n};\n\nexport const sumBy = (records, name, valueOf) =>\n records.reduce(\n (total, record) =>\n total + (valueOf ? numberOf(valueOf(record)) : numberOf(fieldValue(record, name))),\n 0,\n );\n","import kizenCustomBlockSkill from '../templates/claude/skills/kizen-custom-block/SKILL.md?raw';\nimport kizenCustomBlockDesign from '../templates/claude/skills/kizen-custom-block/design.md?raw';\nimport copilotInstructions from '../templates/github/copilot-instructions.md?raw';\nimport securityInstructions from '../templates/github/instructions/security.instructions.md?raw';\nimport versionDisciplineInstructions from '../templates/github/instructions/version-discipline.instructions.md?raw';\nimport kizenDataLib from '../templates/plugin/lib/kizenData.js?raw';\nimport type { ScaffoldedFile } from './createArtifacts.js';\n\nexport function copilotFiles(): ScaffoldedFile[] {\n return [\n { path: '.github/copilot-instructions.md', content: copilotInstructions },\n { path: '.github/instructions/security.instructions.md', content: securityInstructions },\n {\n path: '.github/instructions/version-discipline.instructions.md',\n content: versionDisciplineInstructions,\n },\n ];\n}\n\nexport const KIZEN_DATA_LIB_FILE = 'lib/kizenData.js';\n\nexport const kizenDataLibPath = (entryDir = 'src'): string =>\n entryDir === '' ? KIZEN_DATA_LIB_FILE : `${entryDir}/${KIZEN_DATA_LIB_FILE}`;\n\nexport function claudeFiles(entryDirs: readonly string[] = ['src']): ScaffoldedFile[] {\n return [\n { path: '.claude/skills/kizen-custom-block/SKILL.md', content: kizenCustomBlockSkill },\n { path: '.claude/skills/kizen-custom-block/design.md', content: kizenCustomBlockDesign },\n ...[...new Set(entryDirs)].map((entryDir) => ({\n path: kizenDataLibPath(entryDir),\n content: kizenDataLib,\n })),\n ];\n}\n","import {\n useEffect,\n useState,\n type Dispatch,\n type FC,\n type ReactNode,\n type SetStateAction,\n} from 'react';\nimport { Box, Text, useApp, useInput } from 'ink';\nimport { type ValidationIssue } from '@kizenapps/packager';\nimport { type Credentials } from '../lib/credentials.js';\nimport { formatValidationIssues } from '../lib/formatValidationIssues.js';\nimport { type Surface } from '../lib/kizenTypes.js';\nimport {\n findPushMapEntry,\n matchPushTarget,\n removePushMapEntry,\n surfaceToDashboardType,\n} from '../lib/pushBlock.js';\nimport {\n apiFailure,\n applyPlan,\n buildBrowserRefresh,\n buildPlan,\n buildTargetChoices,\n forgetRemembered,\n formatSummaryLines,\n pushMapKeyOf,\n headlessWriteGate,\n listPushableObjects,\n resolveBlock,\n resolveCredentials,\n resolveTarget,\n toTargetRow,\n type AppliedPush,\n type PushChoice,\n type PushCommandOptions,\n type PushContext,\n type PushDeps,\n type PushPlan,\n type ResolvedBlock,\n type ResolvedTarget,\n type TargetCustomObject,\n type TargetRow,\n} from '../lib/pushHeadless.js';\nimport { AppHeader } from './AppHeader.js';\nimport { SelectList, type SelectItem } from './SelectList.js';\nimport { Spinner } from './Spinner.js';\n\nexport interface PushUIProps {\n apiName?: string;\n options: PushCommandOptions;\n deps: PushDeps;\n}\n\ninterface ErrorView {\n message: string;\n hint?: string;\n choices?: PushChoice[];\n issues?: ValidationIssue[];\n}\n\ninterface Session {\n credentials: Credentials | null;\n warnings: ValidationIssue[];\n notices: string[];\n}\n\ninterface Resolving {\n options: PushCommandOptions;\n context: PushContext;\n}\n\ntype Phase =\n | { type: 'loading'; label: string }\n | { type: 'profile-select'; options: PushCommandOptions; choices: PushChoice[] }\n | { type: 'packaging' }\n | {\n type: 'block-select';\n options: PushCommandOptions;\n credentials: Credentials;\n choices: PushChoice[];\n }\n | ({ type: 'surface-select' } & Resolving)\n | ({ type: 'object-select'; objects: TargetCustomObject[]; back: Phase } & Resolving)\n | ({\n type: 'dashboard-select';\n surface: Surface;\n objectId: string | null;\n title: string;\n rows: TargetRow[];\n back: Phase;\n } & Resolving)\n | ({\n type: 'target-select';\n dashboardId: string;\n title: string;\n message: string | null;\n choices: PushChoice[];\n matchedId: string | null;\n back: Phase | null;\n } & Resolving)\n | ({ type: 'confirm'; kind: 'drift'; message: string; target: ResolvedTarget } & Resolving)\n | ({ type: 'confirm'; kind: 'push'; plan: PushPlan } & Resolving)\n | { type: 'applying'; plan: PushPlan }\n | { type: 'done'; plan: PushPlan; applied: AppliedPush | null }\n | { type: 'error'; view: ErrorView };\n\ntype Setter<T> = Dispatch<SetStateAction<T>>;\n\nconst SURFACE_ITEMS: readonly (SelectItem & { key: Surface })[] = [\n { key: 'dashboard', label: 'Dashboard' },\n { key: 'homepage', label: 'Homepage' },\n { key: 'chart_group', label: 'Chart group' },\n];\n\nconst SURFACE_NOUNS: Record<Surface, string> = {\n dashboard: 'dashboard',\n homepage: 'homepage',\n chart_group: 'chart group',\n};\n\nconst DRIFT_WARNING =\n 'The block was edited in Kizen since your last push. Overwriting discards those edits.';\n\nconst isCreateChoice = (choice: PushChoice): boolean => choice.args.includes('--create');\n\nfunction orderTargetChoices(choices: PushChoice[], matchedId: string | null): PushChoice[] {\n const matched = choices.filter((choice) => choice.value === matchedId);\n const creates = choices.filter(isCreateChoice);\n const rest = choices.filter((choice) => choice.value !== matchedId && !isCreateChoice(choice));\n\n return matched.length > 0 ? [...matched, ...rest, ...creates] : [...creates, ...rest];\n}\n\nfunction targetItem(choice: PushChoice, matchedId: string | null): SelectItem {\n if (isCreateChoice(choice)) {\n return { key: choice.value, label: choice.label };\n }\n\n if (choice.value === matchedId) {\n return { key: choice.value, label: `Update \"${choice.label}\" (last pushed here)` };\n }\n\n const description = choice.isFromThisPlugin ? 'pushed from this plugin' : choice.pushKey;\n\n return {\n key: choice.value,\n label: `Update \"${choice.label}\"`,\n ...(description ? { description } : {}),\n };\n}\n\nfunction dashboardItem(row: TargetRow): SelectItem {\n const label =\n row.dashletsCount === null ? row.name : `${row.name} (${String(row.dashletsCount)} dashlets)`;\n\n if (row.canEdit === false) {\n return { key: row.id, label, description: 'no edit access', disabled: true };\n }\n\n const description = [row.employeeAccess, row.hidden ? 'hidden' : null]\n .filter((part) => part !== null && part !== '')\n .join(' · ');\n\n return { key: row.id, label, ...(description === '' ? {} : { description }) };\n}\n\nfunction withTarget(\n options: PushCommandOptions,\n dashboardId: string,\n choice: PushChoice,\n): PushCommandOptions {\n const next: PushCommandOptions = { ...options, dashboard: dashboardId };\n\n delete next.dashlet;\n delete next.create;\n\n return isCreateChoice(choice) ? { ...next, create: true } : { ...next, dashlet: choice.value };\n}\n\nfunction createPushFlow(\n apiName: string | undefined,\n deps: PushDeps,\n setPhase: Setter<Phase>,\n setSession: Setter<Session>,\n): {\n start: (options: PushCommandOptions) => void;\n pickProfile: (phase: Extract<Phase, { type: 'profile-select' }>, choice: PushChoice) => void;\n pickBlock: (phase: Extract<Phase, { type: 'block-select' }>, choice: PushChoice) => void;\n pickSurface: (phase: Extract<Phase, { type: 'surface-select' }>, surface: Surface) => void;\n pickObject: (\n phase: Extract<Phase, { type: 'object-select' }>,\n object: TargetCustomObject,\n ) => void;\n pickDashboard: (phase: Extract<Phase, { type: 'dashboard-select' }>, row: TargetRow) => void;\n pickTarget: (phase: Extract<Phase, { type: 'target-select' }>, choice: PushChoice) => void;\n acceptDrift: (phase: Extract<Phase, { type: 'confirm'; kind: 'drift' }>) => void;\n acceptPush: (phase: Extract<Phase, { type: 'confirm'; kind: 'push' }>) => void;\n cancel: () => void;\n} {\n const fail = (view: ErrorView): void => {\n deps.setExitCode(1);\n setPhase({ type: 'error', view });\n };\n\n const guard = (task: () => Promise<void>): void => {\n task().catch((error: unknown) => {\n fail(apiFailure(error));\n });\n };\n\n const apply = async (context: PushContext, plan: PushPlan): Promise<void> => {\n setPhase({ type: 'applying', plan });\n\n const step = await applyPlan(context, plan, deps);\n\n if (!step.ok) {\n fail(step);\n\n return;\n }\n\n setPhase({ type: 'done', plan, applied: step.value });\n };\n\n const plan = async (\n context: PushContext,\n target: ResolvedTarget,\n options: PushCommandOptions,\n ): Promise<void> => {\n setPhase({ type: 'loading', label: 'Preparing the push…' });\n\n const step = await buildPlan(context, target, options, deps);\n\n if (!step.ok) {\n if (step.code === 'drift_detected') {\n setPhase({\n type: 'confirm',\n kind: 'drift',\n message: step.message,\n target,\n options,\n context,\n });\n\n return;\n }\n\n fail(step);\n\n return;\n }\n\n if (options.dryRun) {\n setPhase({ type: 'done', plan: step.value, applied: null });\n\n return;\n }\n\n if (options.yes) {\n const gate = headlessWriteGate(options, context.credentials.environment);\n\n if (gate.ok && gate.value.kind === 'apply') {\n await apply(context, step.value);\n\n return;\n }\n }\n\n setPhase({ type: 'confirm', kind: 'push', plan: step.value, options, context });\n };\n\n const resolve = async (\n context: PushContext,\n options: PushCommandOptions,\n back: Phase | null,\n ): Promise<void> => {\n setPhase({ type: 'loading', label: 'Resolving the target…' });\n\n const step = await resolveTarget(context, options);\n\n if (step.ok) {\n await plan(context, step.value, options);\n\n return;\n }\n\n const dashboardId = options.dashboard ?? context.entry?.dashboardId;\n const pickable =\n (step.code === 'needs_choice' && step.choice === 'target') ||\n step.code === 'remembered_target_missing';\n\n if (pickable && step.choices && step.choices.length > 0 && dashboardId !== undefined) {\n setPhase({\n type: 'target-select',\n dashboardId,\n title: 'Choose a block to update, or create a new one',\n message: step.message,\n choices: orderTargetChoices(step.choices, null),\n matchedId: null,\n back,\n options,\n context,\n });\n\n return;\n }\n\n fail(step);\n };\n\n const prepare = async (\n options: PushCommandOptions,\n credentials: Credentials,\n block: ResolvedBlock,\n ): Promise<void> => {\n const key = pushMapKeyOf({ credentials, block });\n let pushMap = await deps.readPushMap(deps.cwd);\n\n if (options.forget && (await forgetRemembered({ credentials, block, pushMap }, deps))) {\n pushMap = removePushMapEntry(pushMap, key);\n setSession((session) => ({\n ...session,\n notices: [...session.notices, `Forgot the remembered target for ${block.block.api_name}.`],\n }));\n }\n\n const context: PushContext = {\n client: deps.createClient(credentials),\n credentials,\n block,\n pushMap,\n entry: findPushMapEntry(pushMap, key),\n };\n\n if (options.dashboard !== undefined || context.entry) {\n await resolve(context, options, null);\n\n return;\n }\n\n setPhase({ type: 'surface-select', options, context });\n };\n\n const packageBlock = async (\n options: PushCommandOptions,\n credentials: Credentials,\n name: string | undefined,\n ): Promise<void> => {\n setPhase({ type: 'packaging' });\n\n const step = await resolveBlock(name, deps);\n\n if (!step.ok) {\n if (step.choice === 'block' && step.choices) {\n setPhase({ type: 'block-select', options, credentials, choices: step.choices });\n\n return;\n }\n\n fail(step);\n\n return;\n }\n\n setSession((session) => ({ ...session, warnings: step.value.warnings }));\n await prepare(options, credentials, step.value);\n };\n\n const loadCredentials = async (options: PushCommandOptions): Promise<void> => {\n setPhase({ type: 'loading', label: 'Loading credentials…' });\n\n const step = await resolveCredentials(options, deps);\n\n if (!step.ok) {\n if (step.choice === 'profile' && step.choices) {\n setPhase({ type: 'profile-select', options, choices: step.choices });\n\n return;\n }\n\n fail(step);\n\n return;\n }\n\n const { credentials } = step.value;\n\n setSession((session) => ({ ...session, credentials }));\n await packageBlock(options, credentials, apiName);\n };\n\n const listDashboards = async (\n { options, context }: Resolving,\n surface: Surface,\n object: TargetCustomObject | null,\n back: Phase,\n ): Promise<void> => {\n const noun = SURFACE_NOUNS[surface];\n\n setPhase({ type: 'loading', label: `Loading ${noun}s…` });\n\n const summaries = await context.client.listDashboards(\n surfaceToDashboardType(surface),\n object?.id,\n );\n const rows = summaries.map((summary) => toTargetRow(summary, surface));\n const { environment, businessId } = context.credentials;\n\n if (rows.length === 0) {\n fail({\n message: `No ${noun}s found${object ? ` on ${object.objectName}` : ''} for business ${businessId} (${environment}).`,\n });\n\n return;\n }\n\n setPhase({\n type: 'dashboard-select',\n surface,\n objectId: object?.id ?? null,\n title: object ? `Choose a chart group on ${object.objectName}` : `Choose a ${noun}`,\n rows,\n back,\n options,\n context,\n });\n };\n\n return {\n start: (options) => {\n guard(() => loadCredentials(options));\n },\n pickProfile: (phase, choice) => {\n guard(() => loadCredentials({ ...phase.options, profile: choice.value }));\n },\n pickBlock: (phase, choice) => {\n guard(() => packageBlock(phase.options, phase.credentials, choice.value));\n },\n pickSurface: (phase, surface) => {\n guard(async () => {\n if (surface !== 'chart_group') {\n await listDashboards(phase, surface, null, phase);\n\n return;\n }\n\n setPhase({ type: 'loading', label: 'Loading custom objects…' });\n\n const objects = await listPushableObjects(phase.context.client);\n\n if (objects.length === 0) {\n fail({ message: 'No custom objects found, so there are no chart groups to push to.' });\n\n return;\n }\n\n setPhase({\n type: 'object-select',\n objects,\n back: phase,\n options: phase.options,\n context: phase.context,\n });\n });\n },\n pickObject: (phase, object) => {\n guard(() => listDashboards(phase, 'chart_group', object, phase));\n },\n pickDashboard: (phase, row) => {\n guard(async () => {\n const { context } = phase;\n const options: PushCommandOptions = { ...phase.options, dashboard: row.id };\n\n if (options.dashlet !== undefined || options.create) {\n await resolve(context, options, phase);\n\n return;\n }\n\n setPhase({ type: 'loading', label: `Loading \"${row.name}\"…` });\n\n const dashboard = await context.client.getDashboard(row.id);\n const match = matchPushTarget({\n dashboardId: dashboard.id,\n dashlets: dashboard.dashlets,\n pluginApiName: context.block.pluginApiName,\n blockApiName: context.block.block.api_name,\n entry: context.entry,\n });\n const matchedId = match.kind === 'map' || match.kind === 'name' ? match.dashlet.id : null;\n\n setPhase({\n type: 'target-select',\n dashboardId: dashboard.id,\n title: `Choose what to push to on \"${dashboard.name}\"`,\n message: null,\n choices: orderTargetChoices(buildTargetChoices(dashboard, context.block), matchedId),\n matchedId,\n back: phase,\n options,\n context,\n });\n });\n },\n pickTarget: (phase, choice) => {\n guard(() =>\n resolve(phase.context, withTarget(phase.options, phase.dashboardId, choice), phase),\n );\n },\n acceptDrift: (phase) => {\n guard(() => plan(phase.context, phase.target, { ...phase.options, force: true }));\n },\n acceptPush: (phase) => {\n guard(() => apply(phase.context, phase.plan));\n },\n cancel: () => {\n fail({ message: 'Cancelled.' });\n },\n };\n}\n\ninterface ConfirmPromptProps {\n prompt: string;\n strict: boolean;\n onAccept: () => void;\n onCancel: () => void;\n}\n\nconst ConfirmPrompt: FC<ConfirmPromptProps> = ({ prompt, strict, onAccept, onCancel }) => {\n useInput((input, key) => {\n if (key.ctrl) {\n return;\n }\n\n const answer = input.toLowerCase();\n\n if (answer === 'y' || (!strict && key.return)) {\n onAccept();\n } else if (strict || answer === 'n' || key.escape) {\n onCancel();\n }\n });\n\n return <Text bold>{prompt}</Text>;\n};\n\nconst Lines: FC<{ lines: readonly string[]; color?: 'yellow' | 'red' }> = ({ lines, color }) => (\n <Box flexDirection=\"column\">\n {lines.map((line, index) => (\n <Text key={`${String(index)}-${line}`} {...(color && { color })}>\n {line}\n </Text>\n ))}\n </Box>\n);\n\nconst PlanSummary: FC<{ plan: PushPlan }> = ({ plan }) => (\n <Box flexDirection=\"column\">\n <Lines lines={formatSummaryLines(plan.summary)} />\n <Text>URL: {plan.url}</Text>\n </Box>\n);\n\nconst Working: FC<{ label: string }> = ({ label }) => (\n <Box gap={1}>\n <Spinner />\n <Text dimColor>{label}</Text>\n </Box>\n);\n\nconst ErrorFrame: FC<{ view: ErrorView }> = ({ view }) => (\n <Box flexDirection=\"column\" gap={1}>\n <Box gap={1}>\n <Text color=\"red\">✗</Text>\n <Text color=\"red\">\n {view.issues && view.issues.length > 0 ? formatValidationIssues(view.issues) : view.message}\n </Text>\n </Box>\n {view.hint !== undefined && <Text dimColor>Hint: {view.hint}</Text>}\n {view.choices && view.choices.length > 0 && (\n <Box flexDirection=\"column\">\n <Text>Choices:</Text>\n <Lines lines={view.choices.map((choice) => ` ${choice.label}`)} />\n </Box>\n )}\n </Box>\n);\n\nconst DoneFrame: FC<{ plan: PushPlan; applied: AppliedPush | null }> = ({ plan, applied }) => {\n const refresh = buildBrowserRefresh(plan.dashboard.id);\n\n if (applied === null) {\n return (\n <Box flexDirection=\"column\" gap={1}>\n <Text color=\"yellow\">Dry run: nothing was written.</Text>\n <PlanSummary plan={plan} />\n {plan.warnings.length > 0 && (\n <Lines lines={plan.warnings.map((warning) => `Warning: ${warning}`)} color=\"yellow\" />\n )}\n <Box flexDirection=\"column\">\n <Text bold>\n {plan.method} {plan.path}\n </Text>\n <Text>{JSON.stringify(plan.body, null, 2)}</Text>\n </Box>\n </Box>\n );\n }\n\n return (\n <Box flexDirection=\"column\" gap={1}>\n <Box gap={1}>\n <Text color=\"green\">✓</Text>\n <Text bold>\n {plan.action === 'create' ? 'Created' : 'Updated'} {plan.summary.blockName} on \"\n {plan.dashboard.name}\"\n </Text>\n </Box>\n <Box flexDirection=\"column\">\n <Text>URL: {plan.url}</Text>\n {refresh && <Text dimColor>Refresh an open tab: {refresh.script}</Text>}\n </Box>\n {applied.warnings.length > 0 && (\n <Lines lines={applied.warnings.map((warning) => `Warning: ${warning}`)} color=\"yellow\" />\n )}\n </Box>\n );\n};\n\nexport const PushUI: FC<PushUIProps> = ({ apiName, options, deps }) => {\n const app = useApp();\n const [phase, setPhase] = useState<Phase>({ type: 'loading', label: 'Loading credentials…' });\n const [session, setSession] = useState<Session>({\n credentials: null,\n warnings: [],\n notices: [],\n });\n const [flow] = useState(() => createPushFlow(apiName, deps, setPhase, setSession));\n const [initialOptions] = useState(options);\n\n useEffect(() => {\n flow.start(initialOptions);\n }, [flow, initialOptions]);\n\n useEffect(() => {\n if (phase.type === 'done' || phase.type === 'error') {\n app.exit();\n }\n }, [phase, app]);\n\n useInput((input, key) => {\n if (key.ctrl && input === 'c' && phase.type !== 'done' && phase.type !== 'error') {\n deps.setExitCode(130);\n app.exit();\n }\n });\n\n const frame = (children: ReactNode): ReactNode => (\n <Box flexDirection=\"column\" paddingY={1} paddingX={2} gap={1}>\n <AppHeader />\n {session.credentials && (\n <Text dimColor>\n Environment: {session.credentials.environment} · Business:{' '}\n {session.credentials.businessId}\n </Text>\n )}\n {session.warnings.length > 0 && (\n <Text dimColor>{formatValidationIssues(session.warnings)}</Text>\n )}\n {session.notices.length > 0 && <Lines lines={session.notices} />}\n {children}\n </Box>\n );\n\n switch (phase.type) {\n case 'loading':\n return frame(<Working label={phase.label} />);\n case 'packaging':\n return frame(<Working label=\"Packaging blocks…\" />);\n case 'applying':\n return frame(\n <Working\n label={`Pushing ${phase.plan.summary.blockName} to \"${phase.plan.dashboard.name}\"…`}\n />,\n );\n case 'profile-select':\n return frame(\n <SelectList\n key=\"profile\"\n title=\"Credential profile\"\n items={phase.choices.map((choice) => ({ key: choice.value, label: choice.label }))}\n onSelect={(_item, index) => {\n const choice = phase.choices[index];\n\n if (choice) {\n flow.pickProfile(phase, choice);\n }\n }}\n onCancel={flow.cancel}\n />,\n );\n case 'block-select':\n return frame(\n <SelectList\n key=\"block\"\n title=\"Block to push\"\n items={phase.choices.map((choice) => ({ key: choice.value, label: choice.label }))}\n onSelect={(_item, index) => {\n const choice = phase.choices[index];\n\n if (choice) {\n flow.pickBlock(phase, choice);\n }\n }}\n onCancel={flow.cancel}\n />,\n );\n case 'surface-select':\n return frame(\n <SelectList\n key=\"surface\"\n title=\"Where should the block go?\"\n items={SURFACE_ITEMS}\n onSelect={(_item, index) => {\n const item = SURFACE_ITEMS[index];\n\n if (item) {\n flow.pickSurface(phase, item.key);\n }\n }}\n onCancel={flow.cancel}\n />,\n );\n case 'object-select':\n return frame(\n <SelectList\n key=\"object\"\n title=\"Custom object\"\n items={phase.objects.map((object) => ({ key: object.id, label: object.objectName }))}\n onSelect={(_item, index) => {\n const object = phase.objects[index];\n\n if (object) {\n flow.pickObject(phase, object);\n }\n }}\n onCancel={() => {\n setPhase(phase.back);\n }}\n hint=\"↑/↓ to move, Enter to select, Esc to go back\"\n />,\n );\n case 'dashboard-select':\n return frame(\n <SelectList\n key={`dashboards-${phase.surface}-${phase.objectId ?? ''}`}\n title={phase.title}\n items={phase.rows.map(dashboardItem)}\n onSelect={(_item, index) => {\n const row = phase.rows[index];\n\n if (row) {\n flow.pickDashboard(phase, row);\n }\n }}\n onCancel={() => {\n setPhase(phase.back);\n }}\n hint=\"↑/↓ to move, Enter to select, Esc to go back\"\n />,\n );\n case 'target-select': {\n const { back } = phase;\n\n return frame(\n <>\n {phase.message !== null && <Text color=\"yellow\">{phase.message}</Text>}\n <SelectList\n key={`targets-${phase.dashboardId}`}\n title={phase.title}\n items={phase.choices.map((choice) => targetItem(choice, phase.matchedId))}\n onSelect={(_item, index) => {\n const choice = phase.choices[index];\n\n if (choice) {\n flow.pickTarget(phase, choice);\n }\n }}\n onCancel={\n back\n ? () => {\n setPhase(back);\n }\n : flow.cancel\n }\n {...(back && { hint: '↑/↓ to move, Enter to select, Esc to go back' })}\n />\n </>,\n );\n }\n\n case 'confirm':\n if (phase.kind === 'drift') {\n return frame(\n <Box flexDirection=\"column\" gap={1}>\n <Text color=\"yellow\">{DRIFT_WARNING}</Text>\n <Text dimColor>{phase.message}</Text>\n <ConfirmPrompt\n key=\"drift\"\n prompt=\"Type y to overwrite (y/N)\"\n strict\n onAccept={() => {\n flow.acceptDrift(phase);\n }}\n onCancel={flow.cancel}\n />\n </Box>,\n );\n }\n\n return frame(\n <Box flexDirection=\"column\" gap={1}>\n <PlanSummary plan={phase.plan} />\n {phase.plan.warnings.length > 0 && (\n <Lines\n lines={phase.plan.warnings.map((warning) => `Warning: ${warning}`)}\n color=\"yellow\"\n />\n )}\n {phase.plan.summary.isProduction && (\n <Text color=\"red\" bold>\n PRODUCTION\n </Text>\n )}\n <ConfirmPrompt\n key=\"push\"\n prompt={\n phase.plan.summary.isProduction ? 'Type y to push to production (y/N)' : 'Push? (Y/n)'\n }\n strict={phase.plan.summary.isProduction}\n onAccept={() => {\n flow.acceptPush(phase);\n }}\n onCancel={flow.cancel}\n />\n </Box>,\n );\n case 'done':\n return frame(<DoneFrame plan={phase.plan} applied={phase.applied} />);\n case 'error':\n return frame(<ErrorFrame view={phase.view} />);\n }\n};\n","import type { FC } from 'react';\nimport { Box, Text } from 'ink';\nimport { Logo } from './Logo.js';\n\ninterface AppHeaderProps {\n marginBottom?: number;\n}\n\nexport const AppHeader: FC<AppHeaderProps> = ({ marginBottom = 0 }) => (\n <>\n <Logo />\n <Box flexDirection=\"column\" marginTop={1} marginBottom={marginBottom}>\n <Text bold color=\"cyan\">\n Kizen App Development Toolkit\n </Text>\n </Box>\n </>\n);\n","import type { FC } from 'react';\nimport { Box, Text } from 'ink';\n\nconst LOGO_LINES = [\n ' :::::::: ',\n ' :::::: ::::::::::: ',\n ' :::::: :::::::::: ',\n ' :::::: :::::: ::::::: ',\n ' ::::: :::::: ::::::::::::::::: ',\n ' ::::: ::::: ::::::::::::::::::: ',\n ' ::::: ::::: :::::: ::::: ',\n ':::: ::::: ::: ::::: :: ',\n '::::: :::::: :::::::::: ',\n '::::: :::::: ::::::::::: ',\n ' ::::: ::: ::::::: ',\n ' ::::::: ::: ::::: ',\n ' ::::::::::: :::::: :::::',\n ' :::::::::: :::::: :::::',\n ' :: ::::: ::: ::::: ::::',\n ' ::::: :::::: ::::: ::::: ::: ',\n ' ::::::::::::::::::: ::::: ::::: ',\n ' ::::::::::::::::: ::::: ::::: ',\n ' ::::::::: :::::: :::::: ',\n ' :::::::::: :::::: ',\n ' ::::::::::: :::::: ',\n ' :::::::: ',\n];\n\nexport const Logo: FC = () => (\n <Box flexDirection=\"column\">\n {LOGO_LINES.map((line, i) => (\n <Text key={i} color=\"cyan\">\n {line}\n </Text>\n ))}\n </Box>\n);\n","import type { FC } from 'react';\nimport { useMemo, useState } from 'react';\nimport { Box, Text, useInput } from 'ink';\nimport { moveCursor, visibleWindow } from '../lib/moveCursor.js';\n\nexport interface SelectItem {\n key: string;\n label: string;\n description?: string;\n disabled?: boolean;\n}\n\nexport interface SelectListProps {\n title: string;\n items: readonly SelectItem[];\n onSelect: (item: SelectItem, index: number) => void;\n onCancel?: () => void;\n hint?: string;\n initialIndex?: number;\n windowSize?: number;\n isActive?: boolean;\n}\n\nconst DEFAULT_HINT = '↑/↓ to move, Enter to select, Esc to cancel';\nconst DEFAULT_WINDOW_SIZE = 10;\n\nconst initialCursor = (items: readonly SelectItem[], initialIndex: number): number => {\n const clamped = moveCursor(initialIndex, items.length, 0);\n\n if (items[clamped]?.disabled !== true) {\n return clamped;\n }\n\n const firstEnabled = items.findIndex((item) => item.disabled !== true);\n\n return firstEnabled === -1 ? clamped : firstEnabled;\n};\n\nexport const SelectList: FC<SelectListProps> = ({\n title,\n items,\n onSelect,\n onCancel,\n hint = DEFAULT_HINT,\n initialIndex = 0,\n windowSize = DEFAULT_WINDOW_SIZE,\n isActive = true,\n}) => {\n const [cursorState, setCursorState] = useState(() => initialCursor(items, initialIndex));\n const disabled = useMemo(() => items.map((item) => item.disabled === true), [items]);\n const cursor = moveCursor(cursorState, items.length, 0);\n const pageSize = Math.max(1, Math.floor(windowSize));\n\n useInput(\n (input, key) => {\n const move = (delta: number): void => {\n setCursorState(moveCursor(cursor, items.length, delta, { disabled }));\n };\n\n if (key.upArrow || input === 'k') {\n move(-1);\n } else if (key.downArrow || input === 'j') {\n move(1);\n } else if (key.pageUp) {\n move(-pageSize);\n } else if (key.pageDown) {\n move(pageSize);\n } else if (key.return) {\n const item = items[cursor];\n\n if (item !== undefined && item.disabled !== true) {\n onSelect(item, cursor);\n }\n } else if (key.escape) {\n onCancel?.();\n }\n },\n { isActive },\n );\n\n const { start, end } = visibleWindow(cursor, items.length, pageSize);\n const above = start;\n const below = items.length - end;\n\n return (\n <Box flexDirection=\"column\" gap={1}>\n <Text bold>{title}</Text>\n <Box flexDirection=\"column\">\n {above > 0 && <Text dimColor>{` ↑ ${String(above)} more`}</Text>}\n {items.slice(start, end).map((item, offset) => {\n const index = start + offset;\n const selected = index === cursor;\n const itemDisabled = item.disabled === true;\n const highlight = selected && !itemDisabled;\n\n return (\n <Box key={item.key} gap={2}>\n <Text {...(highlight && { color: 'cyan' as const })} dimColor={itemDisabled}>\n {selected ? '❯' : ' '}\n </Text>\n <Text\n bold={highlight}\n dimColor={itemDisabled}\n {...(highlight && { color: 'cyan' as const })}\n >\n {item.label}\n </Text>\n {item.description !== undefined && <Text dimColor>{item.description}</Text>}\n </Box>\n );\n })}\n {below > 0 && <Text dimColor>{` ↓ ${String(below)} more`}</Text>}\n </Box>\n <Text dimColor>{hint}</Text>\n </Box>\n );\n};\n","export interface MoveCursorOptions {\n disabled?: readonly boolean[];\n}\n\nexport interface VisibleWindow {\n start: number;\n end: number;\n}\n\nconst clamp = (value: number, min: number, max: number): number =>\n Math.min(Math.max(value, min), max);\n\nexport function moveCursor(\n cursor: number,\n length: number,\n delta: number,\n options: MoveCursorOptions = {},\n): number {\n if (length <= 0) {\n return 0;\n }\n\n const current = clamp(Math.trunc(cursor) || 0, 0, length - 1);\n const isEnabled = (index: number): boolean => options.disabled?.[index] !== true;\n\n if (delta === 0) {\n return current;\n }\n\n const step = delta > 0 ? 1 : -1;\n\n if (Math.abs(delta) === 1) {\n for (let offset = 1; offset <= length; offset++) {\n const index = (((current + step * offset) % length) + length) % length;\n\n if (isEnabled(index)) {\n return index;\n }\n }\n\n return current;\n }\n\n const target = clamp(current + Math.trunc(delta), 0, length - 1);\n\n for (let index = target; index >= 0 && index < length; index += step) {\n if (isEnabled(index)) {\n return index;\n }\n }\n\n for (let index = target - step; index >= 0 && index < length; index -= step) {\n if (isEnabled(index)) {\n return index;\n }\n }\n\n return current;\n}\n\nexport function visibleWindow(cursor: number, length: number, size = 10): VisibleWindow {\n if (length <= 0) {\n return { start: 0, end: 0 };\n }\n\n const rows = Math.max(1, Math.floor(size));\n\n if (length <= rows) {\n return { start: 0, end: length };\n }\n\n const current = clamp(Math.trunc(cursor) || 0, 0, length - 1);\n const start = clamp(current - Math.floor(rows / 2), 0, length - rows);\n\n return { start, end: start + rows };\n}\n","import type { FC } from 'react';\nimport { useEffect, useState } from 'react';\nimport { Text } from 'ink';\n\nexport const SPINNER_FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];\n\nexport const Spinner: FC = () => {\n const [frame, setFrame] = useState(0);\n\n useEffect(() => {\n const id = setInterval(() => {\n setFrame((prev) => (prev + 1) % SPINNER_FRAMES.length);\n }, 80);\n\n return () => {\n clearInterval(id);\n };\n }, []);\n\n return <Text color=\"cyan\">{SPINNER_FRAMES[frame] ?? '⠋'}</Text>;\n};\n","import { createElement } from 'react';\nimport { render } from 'ink';\nimport type { Command } from 'commander';\nimport { BuildUI } from '../ui/BuildUI.js';\nimport { ensureGitignore } from '../lib/gitignore.js';\n\nexport function buildCommand(program: Command): void {\n program\n .command('build')\n .description('Bundle the plugin app into .kizenapp directory')\n .action(async () => {\n const pluginDir = process.cwd();\n const outputDir = `${pluginDir}/.kizenapp`;\n\n ensureGitignore(pluginDir);\n\n const { waitUntilExit } = render(createElement(BuildUI, { outputDir, pluginDir }));\n\n await waitUntilExit();\n });\n}\n","import type { FC } from 'react';\nimport { useEffect, useState } from 'react';\nimport { Box, Text, useApp } from 'ink';\nimport { PluginValidationError } from '@kizenapps/packager';\nimport type { ValidationIssue } from '@kizenapps/packager';\nimport { runBuild } from '../lib/runBuild.js';\nimport type { BuildStepName } from '../lib/runBuild.js';\nimport { formatBytes } from '../../shared/lib/formatBytes.js';\nimport { AppHeader } from './AppHeader.js';\nimport { Spinner } from './Spinner.js';\nimport { ValidationIssues } from './ValidationIssues.js';\n\ntype BuildStep = BuildStepName | 'done';\n\ninterface BuildUIProps {\n outputDir: string;\n pluginDir: string;\n}\n\nconst STEPS: BuildStepName[] = [\n 'creating-dir',\n 'reading-files',\n 'validating',\n 'minifying',\n 'packaging',\n 'writing-bundle',\n];\n\nconst STEP_LABELS: Record<BuildStepName, string> = {\n 'creating-dir': 'Creating .kizenapp directory',\n 'reading-files': 'Reading plugin files',\n validating: 'Validating plugin app',\n minifying: 'Minifying scripts',\n packaging: 'Packaging plugin',\n 'writing-bundle': 'Writing bundle.json',\n};\n\nexport const BuildUI: FC<BuildUIProps> = ({ outputDir, pluginDir }) => {\n const app = useApp();\n const [step, setStep] = useState<BuildStep>('creating-dir');\n const [failed, setFailed] = useState(false);\n const [issues, setIssues] = useState<ValidationIssue[] | null>(null);\n const [errorMessage, setErrorMessage] = useState<string | null>(null);\n const [bundleSize, setBundleSize] = useState<number | null>(null);\n\n useEffect(() => {\n void runBuild(pluginDir, outputDir, setStep)\n .then(({ bundleSize: size }) => {\n setBundleSize(size);\n setStep('done');\n })\n .catch((err: unknown) => {\n if (err instanceof PluginValidationError) {\n setIssues(err.issues);\n } else {\n setErrorMessage(err instanceof Error ? err.message : String(err));\n }\n\n // Leave `step` on the step that was running so the ✗ lands on it.\n setFailed(true);\n process.exitCode = 1;\n });\n }, [outputDir, pluginDir]);\n\n // Exit only once the terminal frame has been committed and written to the\n // terminal. Calling app.exit() in the same tick as the state updates would\n // unmount ink before it paints the done/error frame, leaving the spinner as\n // the last thing on screen.\n useEffect(() => {\n if (step === 'done' || failed) {\n app.exit();\n }\n }, [step, failed, app]);\n\n const currentIndex = STEPS.indexOf(step as BuildStepName);\n const isDone = step === 'done';\n\n return (\n <Box flexDirection=\"column\" paddingY={1} paddingX={2}>\n <AppHeader marginBottom={1} />\n\n <Box flexDirection=\"column\" gap={0}>\n {STEPS.map((s, i) => {\n const isActive = step === s;\n const isStepDone = isDone || currentIndex > i;\n const isFailed = failed && i === currentIndex;\n\n return (\n <Box key={s} gap={1}>\n {isFailed ? (\n <Text color=\"red\">✗ {STEP_LABELS[s]}</Text>\n ) : isStepDone ? (\n <Text color=\"green\">✓ {STEP_LABELS[s]}</Text>\n ) : isActive ? (\n <>\n <Spinner />\n <Text>{STEP_LABELS[s]}</Text>\n </>\n ) : (\n <Text dimColor> {STEP_LABELS[s]}</Text>\n )}\n </Box>\n );\n })}\n\n {isDone && bundleSize !== null && (\n <Box marginTop={1} gap={1}>\n <Text color=\"green\">✓ bundle — {formatBytes(bundleSize)}</Text>\n </Box>\n )}\n\n {issues !== null && <ValidationIssues issues={issues} />}\n\n {errorMessage !== null && (\n <Box marginTop={1} borderStyle=\"single\" borderColor=\"red\" paddingX={1}>\n <Text color=\"red\">{errorMessage}</Text>\n </Box>\n )}\n </Box>\n </Box>\n );\n};\n","export function formatBytes(n: number): string {\n if (n < 1024) {\n return `${String(n)} B`;\n }\n\n if (n < 1024 * 1024) {\n return `${(n / 1024).toFixed(1)} KB`;\n }\n\n return `${(n / (1024 * 1024)).toFixed(2)} MB`;\n}\n","import type { FC } from 'react';\nimport { Box, Text } from 'ink';\nimport type { ValidationIssue } from '@kizenapps/packager';\n\nconst groupIssuesByPath = (issues: ValidationIssue[]): Map<string, ValidationIssue[]> => {\n const groups = new Map<string, ValidationIssue[]>();\n\n for (const issue of issues) {\n const key = issue.path ?? issue.pluginApiName ?? 'general';\n const group = groups.get(key) ?? [];\n\n group.push(issue);\n groups.set(key, group);\n }\n\n return groups;\n};\n\ninterface ValidationIssuesProps {\n issues: ValidationIssue[];\n}\n\nexport const ValidationIssues: FC<ValidationIssuesProps> = ({ issues }) => {\n // The build only throws on error-severity issues, but `issues` also carries\n // any warnings; the header must count errors only, not the whole array.\n const errorCount = issues.filter((issue) => issue.severity === 'error').length;\n\n return (\n <Box flexDirection=\"column\" marginTop={1}>\n <Text color=\"red\">\n ✗ {errorCount} validation {errorCount === 1 ? 'error' : 'errors'}\n </Text>\n\n {[...groupIssuesByPath(issues)].map(([path, group]) => (\n <Box key={path} flexDirection=\"column\" marginTop={1}>\n <Text bold>{path}</Text>\n\n {group.map((issue, i) => (\n <Box key={`${issue.rule}-${String(i)}`} paddingLeft={2}>\n <Text color={issue.severity === 'error' ? 'red' : 'yellow'}>\n {issue.severity === 'error' ? '✗' : '⚠'} {issue.message}{' '}\n <Text dimColor>({issue.rule})</Text>\n </Text>\n </Box>\n ))}\n </Box>\n ))}\n </Box>\n );\n};\n","import { createElement } from 'react';\nimport { render } from 'ink';\nimport type { Command } from 'commander';\nimport { CreateUI } from '../ui/CreateUI.js';\nimport { loadGlobalCredentials } from '../lib/credentials.js';\nimport { createPlugin, precheckTargetDir } from '../lib/createPlugin.js';\nimport { runHeadlessCreate } from '../lib/createHeadless.js';\nimport type { CreateOptions } from '../lib/createHeadless.js';\nimport { ARTIFACT_TYPES } from '../lib/createArtifacts.js';\nimport { ENVIRONMENTS } from '../../shared/lib/credentials.js';\n\nexport function createCommand(program: Command): void {\n program\n .command('create')\n .description('Scaffold a new Kizen plugin project')\n .option('-n, --name <name>', 'plugin display name (implies a non-interactive run)')\n .option('-a, --api-name <name>', 'plugin api_name (inferred from --name when omitted)')\n .option('-d, --description <text>', 'plugin description')\n .option('-l, --external-link <url>', 'external link shown on the plugin listing')\n .option('-b, --business-id <id>', 'developer business id (defaults to saved credentials)')\n .option(\n '-e, --environment <env>',\n `environment the business id belongs to: ${ENVIRONMENTS.join(', ')} (defaults to saved credentials)`,\n )\n .option(\n '--artifacts <list>',\n `comma-separated artifact types, or \"all\" / \"none\" (default: all). Types: ${ARTIFACT_TYPES.join(', ')}`,\n )\n .action(async (options: CreateOptions) => {\n const parentDir = process.cwd();\n const globalCreds = await loadGlobalCredentials();\n const defaultBusinessId = globalCreds?.businessId ?? '';\n const defaultEnvironment = globalCreds?.environment ?? 'go';\n\n const suppliedFlags = Object.values(options).some((value) => value !== undefined);\n\n const isNonInteractive = !process.stdin.isTTY || !process.stdout.isTTY || suppliedFlags;\n\n if (isNonInteractive) {\n await runHeadlessCreate(\n options,\n { businessId: defaultBusinessId, environment: defaultEnvironment },\n parentDir,\n {\n precheckTargetDir,\n createPlugin,\n writeStdout: (text) => {\n process.stdout.write(text);\n },\n writeStderr: (text) => {\n process.stderr.write(text);\n },\n setExitCode: (code) => {\n process.exitCode = code;\n },\n },\n );\n\n return;\n }\n\n const { waitUntilExit } = render(\n createElement(CreateUI, { parentDir, defaultBusinessId, defaultEnvironment }),\n { exitOnCtrlC: false },\n );\n\n await waitUntilExit();\n });\n}\n","import type { FC } from 'react';\nimport { useCallback, useState } from 'react';\nimport { Box, Text, useApp, useInput } from 'ink';\nimport { join } from 'node:path';\nimport {\n buildManifest,\n createPlugin,\n findAvailableSubDir,\n precheckTargetDir,\n} from '../lib/createPlugin.js';\nimport type { PrecheckResult } from '../lib/createPlugin.js';\nimport {\n emptyValues,\n FIELD_LABELS,\n FIELDS,\n inferApiName,\n normalizeFieldValue,\n REQUIRED_FIELDS,\n toggleArtifactSelection,\n validateField,\n} from '../lib/createForm.js';\nimport type { FieldValues } from '../lib/createForm.js';\nimport { ARTIFACT_LABELS, ARTIFACT_TYPES } from '../lib/createArtifacts.js';\nimport type { ArtifactType } from '../lib/createArtifacts.js';\nimport type { Environment } from '../../shared/lib/credentials.js';\nimport { AppHeader } from './AppHeader.js';\n\ntype Mode = 'in-place' | 'sub-dir';\n\ntype Phase =\n | { type: 'target-select'; cursor: 0 | 1 }\n | { type: 'precheck-error'; targetDir: string; reason: PrecheckResult }\n | { type: 'field-entry'; field: number; values: FieldValues; fieldError?: string }\n | {\n type: 'artifact-select';\n values: FieldValues;\n cursor: number;\n selected: readonly ArtifactType[];\n }\n | { type: 'resolving-target' }\n | { type: 'confirm'; values: FieldValues; artifacts: readonly ArtifactType[] }\n | { type: 'writing' }\n | { type: 'done'; targetDir: string }\n | { type: 'error'; message: string };\n\ninterface CreateUIProps {\n parentDir: string;\n defaultBusinessId: string;\n defaultEnvironment: Environment;\n}\n\nconst Hint: FC<{ text: string }> = ({ text }) => <Text dimColor>{text}</Text>;\n\nexport const CreateUI: FC<CreateUIProps> = ({\n parentDir,\n defaultBusinessId,\n defaultEnvironment,\n}) => {\n const app = useApp();\n const [phase, setPhase] = useState<Phase>({ type: 'target-select', cursor: 0 });\n const [mode, setMode] = useState<Mode>('in-place');\n const [values, setValues] = useState<FieldValues>(() => emptyValues(defaultBusinessId));\n const [artifacts, setArtifacts] = useState<readonly ArtifactType[]>(() => [...ARTIFACT_TYPES]);\n const [inputBuffer, setInputBuffer] = useState('');\n const [targetDir, setTargetDir] = useState<string>(parentDir);\n\n const enterFieldEntry = useCallback((nextMode: Mode, initialValues: FieldValues): void => {\n setMode(nextMode);\n\n setInputBuffer(initialValues.name);\n\n setPhase({ type: 'field-entry', field: 0, values: initialValues });\n }, []);\n\n const runPrecheck = useCallback(\n async (dir: string): Promise<void> => {\n const result = await precheckTargetDir(dir);\n\n if (result !== 'ok') {\n setPhase({ type: 'precheck-error', targetDir: dir, reason: result });\n\n return;\n }\n\n setTargetDir(dir);\n\n enterFieldEntry('in-place', values);\n },\n [values, enterFieldEntry],\n );\n\n const resolveSubDirAndConfirm = useCallback(\n async (finalValues: FieldValues, artifacts: readonly ArtifactType[]): Promise<void> => {\n try {\n const dir = await findAvailableSubDir(parentDir, finalValues.apiName);\n\n setTargetDir(dir);\n\n setPhase({ type: 'confirm', values: finalValues, artifacts });\n } catch (err) {\n setPhase({\n type: 'error',\n message: err instanceof Error ? err.message : String(err),\n });\n }\n },\n [parentDir],\n );\n\n const runWrite = useCallback(\n async (\n finalValues: FieldValues,\n dir: string,\n artifacts: readonly ArtifactType[],\n ): Promise<void> => {\n try {\n await createPlugin({\n targetDir: dir,\n name: finalValues.name,\n apiName: finalValues.apiName,\n externalLink: finalValues.externalLink,\n description: finalValues.description,\n developerBusinessId: finalValues.developerBusinessId,\n developerEnvironment: defaultEnvironment,\n artifacts,\n });\n\n setPhase({ type: 'done', targetDir: dir });\n } catch (err) {\n setPhase({\n type: 'error',\n message: err instanceof Error ? err.message : String(err),\n });\n }\n },\n [defaultEnvironment],\n );\n\n useInput((input, key) => {\n if (key.ctrl && input === 'c') {\n app.exit();\n\n return;\n }\n\n if (phase.type === 'target-select') {\n if (key.upArrow) {\n setPhase({ type: 'target-select', cursor: 0 });\n } else if (key.downArrow) {\n setPhase({ type: 'target-select', cursor: 1 });\n } else if (key.return) {\n if (phase.cursor === 0) {\n void runPrecheck(parentDir);\n } else {\n enterFieldEntry('sub-dir', values);\n }\n } else if (key.escape) {\n app.exit();\n }\n\n return;\n }\n\n if (phase.type === 'precheck-error') {\n if (key.return || key.escape) {\n app.exit();\n }\n\n return;\n }\n\n if (phase.type === 'field-entry') {\n const { field, values: current } = phase;\n const fieldName = FIELDS[field];\n\n if (!fieldName) {\n return;\n }\n\n if (key.escape) {\n app.exit();\n\n return;\n }\n\n if (key.backspace || key.delete) {\n setInputBuffer((prev) => prev.slice(0, -1));\n\n return;\n }\n\n if (key.upArrow && field > 0) {\n const updated = { ...current, [fieldName]: inputBuffer };\n const prevField = field - 1;\n const prevName = FIELDS[prevField];\n\n setPhase({ type: 'field-entry', field: prevField, values: updated });\n\n setValues(updated);\n\n setInputBuffer(prevName ? updated[prevName] : '');\n\n return;\n }\n\n if (key.return || key.tab || key.downArrow) {\n const fieldError = validateField(fieldName, inputBuffer);\n\n if (fieldError !== undefined) {\n setPhase({ type: 'field-entry', field, values: current, fieldError });\n\n return;\n }\n\n const valueToStore = normalizeFieldValue(fieldName, inputBuffer);\n const updated = { ...current, [fieldName]: valueToStore };\n\n setValues(updated);\n\n const nextField = field + 1;\n\n if (nextField >= FIELDS.length) {\n setInputBuffer('');\n\n setPhase({\n type: 'artifact-select',\n values: updated,\n cursor: 0,\n selected: artifacts,\n });\n } else {\n const nextName = FIELDS[nextField];\n const existing = nextName ? updated[nextName] : '';\n const nextBuffer =\n nextName === 'apiName' && !existing ? inferApiName(updated.name) : existing;\n\n setPhase({ type: 'field-entry', field: nextField, values: updated });\n\n setInputBuffer(nextBuffer);\n }\n\n return;\n }\n\n if (input && !key.ctrl && !key.meta) {\n setInputBuffer((prev) => prev + input);\n }\n\n return;\n }\n\n if (phase.type === 'artifact-select') {\n const { cursor, selected, values: current } = phase;\n\n if (key.escape) {\n const lastField = FIELDS.length - 1;\n const lastName = FIELDS[lastField];\n\n setPhase({ type: 'field-entry', field: lastField, values: current });\n\n setInputBuffer(lastName ? current[lastName] : '');\n\n return;\n }\n\n if (key.upArrow) {\n setPhase({ ...phase, cursor: Math.max(0, cursor - 1) });\n\n return;\n }\n\n if (key.downArrow) {\n setPhase({ ...phase, cursor: Math.min(ARTIFACT_TYPES.length - 1, cursor + 1) });\n\n return;\n }\n\n if (input === ' ') {\n const type = ARTIFACT_TYPES[cursor];\n\n if (type) {\n const next = toggleArtifactSelection(selected, type);\n\n setArtifacts(next);\n\n setPhase({ ...phase, selected: next });\n }\n\n return;\n }\n\n if (input === 'a') {\n setArtifacts([...ARTIFACT_TYPES]);\n\n setPhase({ ...phase, selected: [...ARTIFACT_TYPES] });\n\n return;\n }\n\n if (input === 'n') {\n setArtifacts([]);\n\n setPhase({ ...phase, selected: [] });\n\n return;\n }\n\n if (key.return) {\n if (mode === 'sub-dir') {\n setPhase({ type: 'resolving-target' });\n\n void resolveSubDirAndConfirm(current, selected);\n } else {\n setPhase({ type: 'confirm', values: current, artifacts: selected });\n }\n }\n\n return;\n }\n\n if (phase.type === 'confirm') {\n if (key.escape) {\n setPhase({\n type: 'artifact-select',\n values: phase.values,\n cursor: 0,\n selected: phase.artifacts,\n });\n\n return;\n }\n\n if (key.return) {\n setPhase({ type: 'writing' });\n\n void runWrite(phase.values, targetDir, phase.artifacts);\n }\n\n return;\n }\n\n if (phase.type === 'done' || phase.type === 'error') {\n if (key.return || key.escape) {\n app.exit();\n }\n }\n });\n\n if (phase.type === 'target-select') {\n const options = [\n { label: 'Use current directory', desc: parentDir },\n { label: 'Create new sub-directory', desc: `${parentDir}/<inferred from API name>` },\n ];\n\n return (\n <Box flexDirection=\"column\" paddingY={1} paddingX={2} gap={1}>\n <AppHeader />\n <Box flexDirection=\"column\" gap={0}>\n <Text bold>Where should the new plugin live?</Text>\n {options.map((opt, i) => {\n const selected = phase.cursor === i;\n\n return (\n <Box key={opt.label} gap={2}>\n <Text {...(selected && { color: 'cyan' as const })}>{selected ? '❯' : ' '}</Text>\n <Text bold={selected} {...(selected && { color: 'cyan' as const })}>\n {opt.label}\n </Text>\n <Text dimColor>{opt.desc}</Text>\n </Box>\n );\n })}\n </Box>\n <Hint text=\"↑↓ to move · Enter to select · Esc to cancel\" />\n </Box>\n );\n }\n\n if (phase.type === 'precheck-error') {\n const { targetDir: dir, reason } = phase;\n const conflict = reason === 'has-manifest' ? 'kizen.json' : '.kizenapp/';\n\n return (\n <Box flexDirection=\"column\" paddingY={1} paddingX={2} gap={1}>\n <AppHeader />\n <Text color=\"red\" bold>\n Cannot create plugin\n </Text>\n <Box flexDirection=\"column\" gap={0}>\n <Text>\n {dir} already contains <Text bold>{conflict}</Text>.\n </Text>\n <Text dimColor>\n Remove the conflicting file/directory or choose a different target to avoid overwriting\n an existing plugin.\n </Text>\n </Box>\n <Hint text=\"Enter or Esc to exit\" />\n </Box>\n );\n }\n\n if (phase.type === 'field-entry') {\n const { field: activeField, fieldError } = phase;\n const targetLine =\n mode === 'sub-dir'\n ? `Target: sub-directory of ${parentDir} (inferred from API name)`\n : `Target: ${targetDir}`;\n\n return (\n <Box flexDirection=\"column\" paddingY={1} paddingX={2} gap={1}>\n <AppHeader />\n <Box flexDirection=\"column\" gap={0}>\n <Text bold>Plugin details</Text>\n <Text dimColor>{targetLine}</Text>\n </Box>\n {fieldError !== undefined && <Text color=\"red\">Error: {fieldError}</Text>}\n <Box flexDirection=\"column\" gap={0}>\n {FIELDS.map((name, i) => {\n const isActive = activeField === i;\n const displayValue = isActive ? inputBuffer : values[name];\n const isRequired = REQUIRED_FIELDS.includes(name);\n const label = `${FIELD_LABELS[name]}${isRequired ? '' : ' (optional)'}`;\n\n return (\n <Box key={name} gap={2}>\n <Box width={24}>\n <Text bold={isActive} {...(isActive && { color: 'cyan' as const })}>\n {label}\n </Text>\n </Box>\n <Text {...(isActive && { color: 'cyan' as const })}>{'>'}</Text>\n <Text>{displayValue}</Text>\n {isActive && <Text color=\"cyan\">{'█'}</Text>}\n </Box>\n );\n })}\n </Box>\n <Hint text=\"Enter/Tab/↓ next · ↑ previous · Backspace delete · Esc cancel\" />\n </Box>\n );\n }\n\n if (phase.type === 'artifact-select') {\n const { cursor, selected } = phase;\n\n return (\n <Box flexDirection=\"column\" paddingY={1} paddingX={2} gap={1}>\n <AppHeader />\n <Box flexDirection=\"column\" gap={0}>\n <Text bold>Which artifacts should we scaffold?</Text>\n <Text dimColor>Each one gets a directory with a config.json and a script that runs.</Text>\n </Box>\n <Box flexDirection=\"column\" gap={0}>\n {ARTIFACT_TYPES.map((type, i) => {\n const active = cursor === i;\n const checked = selected.includes(type);\n\n return (\n <Box key={type} gap={1}>\n <Text {...(active && { color: 'cyan' as const })}>{active ? '❯' : ' '}</Text>\n <Text {...(checked && { color: 'green' as const })}>{checked ? '◉' : '◯'}</Text>\n <Text bold={active} {...(active && { color: 'cyan' as const })}>\n {ARTIFACT_LABELS[type]}\n </Text>\n </Box>\n );\n })}\n </Box>\n <Hint text=\"↑↓ move · Space toggle · a all · n none · Enter continue · Esc back\" />\n </Box>\n );\n }\n\n if (phase.type === 'confirm') {\n const manifest = buildManifest({\n targetDir,\n name: phase.values.name,\n apiName: phase.values.apiName,\n externalLink: phase.values.externalLink,\n description: phase.values.description,\n developerBusinessId: phase.values.developerBusinessId,\n developerEnvironment: defaultEnvironment,\n });\n\n return (\n <Box flexDirection=\"column\" paddingY={1} paddingX={2} gap={1}>\n <AppHeader />\n <Box flexDirection=\"column\" gap={0}>\n <Text bold>Ready to create</Text>\n <Text dimColor>Target: {targetDir}</Text>\n </Box>\n <Box flexDirection=\"column\" gap={0}>\n <Text bold>kizen.json preview</Text>\n <Text>{JSON.stringify(manifest, null, 2)}</Text>\n </Box>\n <Box flexDirection=\"column\" gap={0}>\n <Text bold>Artifacts</Text>\n {phase.artifacts.length === 0 ? (\n <Text dimColor>{' '}none (src/ will hold only thumbnail.png)</Text>\n ) : (\n phase.artifacts.map((type) => (\n <Text key={type} dimColor>\n {' '}\n {ARTIFACT_LABELS[type]}\n </Text>\n ))\n )}\n </Box>\n <Box flexDirection=\"column\" gap={0}>\n <Text dimColor>Also creates:</Text>\n <Text dimColor>\n {' '}\n {join(targetDir, 'src/')}\n </Text>\n <Text dimColor>\n {' '}\n {join(targetDir, 'src/thumbnail.png')} (generated placeholder)\n </Text>\n <Text dimColor>\n {' '}\n {join(targetDir, 'releaseNotes/')}\n </Text>\n <Text dimColor>\n {' '}\n {join(targetDir, '.gitignore')} (adds .kizenapp/)\n </Text>\n </Box>\n <Hint text=\"Enter to create · Esc to go back\" />\n </Box>\n );\n }\n\n if (phase.type === 'resolving-target') {\n return (\n <Box paddingY={1} paddingX={2}>\n <Text dimColor>Finding available sub-directory…</Text>\n </Box>\n );\n }\n\n if (phase.type === 'writing') {\n return (\n <Box paddingY={1} paddingX={2}>\n <Text dimColor>Creating plugin…</Text>\n </Box>\n );\n }\n\n if (phase.type === 'done') {\n return (\n <Box flexDirection=\"column\" paddingY={1} paddingX={2} gap={1}>\n <AppHeader />\n <Text color=\"green\" bold>\n Plugin created at {phase.targetDir}\n </Text>\n <Box flexDirection=\"column\" gap={0}>\n <Text dimColor>Next steps:</Text>\n <Text>\n {' '}cd {phase.targetDir}\n </Text>\n <Text>{' '}npx --yes @kizenapps/cli dev</Text>\n <Text dimColor>{' '}Replace src/thumbnail.png with real artwork before publishing.</Text>\n </Box>\n <Hint text=\"Enter or Esc to exit\" />\n </Box>\n );\n }\n\n // error\n return (\n <Box flexDirection=\"column\" paddingY={1} paddingX={2} gap={1}>\n <AppHeader />\n <Text color=\"red\" bold>\n Failed to create plugin\n </Text>\n <Text>{phase.message}</Text>\n <Hint text=\"Enter or Esc to exit\" />\n </Box>\n );\n};\n","import { access, mkdir, writeFile } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\nimport { ensureGitignore } from './gitignore.js';\nimport { scaffoldArtifactFiles } from './createArtifacts.js';\nimport type { ArtifactType, ScaffoldedFile } from './createArtifacts.js';\nimport { claudeFiles, copilotFiles } from './createCopilotFiles.js';\nimport { thumbnailBytes } from './createThumbnail.js';\nimport type { Environment } from '../../shared/lib/credentials.js';\n\nconst THUMBNAIL_PATH = 'src/thumbnail.png';\n\nconst PROD_ENVIRONMENTS: readonly Environment[] = ['go', 'fmo'];\n\nexport interface CreatePluginInput {\n targetDir: string;\n name: string;\n apiName: string;\n externalLink: string;\n description: string;\n developerBusinessId: string;\n developerEnvironment: Environment;\n artifacts?: readonly ArtifactType[];\n}\n\nexport type PrecheckResult = 'ok' | 'has-manifest' | 'has-kizenapp';\n\nasync function pathExists(path: string): Promise<boolean> {\n try {\n await access(path);\n\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function precheckTargetDir(dir: string): Promise<PrecheckResult> {\n if (await pathExists(join(dir, 'kizen.json'))) {\n return 'has-manifest';\n }\n\n if (await pathExists(join(dir, '.kizenapp'))) {\n return 'has-kizenapp';\n }\n\n return 'ok';\n}\n\nexport async function findAvailableSubDir(parentDir: string, baseName: string): Promise<string> {\n const base = join(parentDir, baseName);\n\n if (!(await pathExists(base))) {\n return base;\n }\n\n for (let i = 1; i < 1000; i++) {\n const candidate = join(parentDir, `${baseName}-${String(i)}`);\n\n if (!(await pathExists(candidate))) {\n return candidate;\n }\n }\n\n throw new Error(`Could not find an available directory name for \"${baseName}\"`);\n}\n\nexport function buildManifest(input: CreatePluginInput): Record<string, unknown> {\n const businessId = input.developerBusinessId.trim();\n\n const targetEnvironments =\n businessId !== '' && !PROD_ENVIRONMENTS.includes(input.developerEnvironment)\n ? [input.developerEnvironment]\n : ['prod'];\n\n return {\n name: input.name,\n version: '1.0.0',\n published: true,\n api_name: input.apiName,\n external_link: input.externalLink,\n description: input.description,\n entry: 'src/',\n engine: '1.0.0',\n release_notes_directory: 'releaseNotes/',\n release_environments: targetEnvironments,\n config_template: {},\n base_config: {},\n ...(businessId ? { developer_business_id: { [input.developerEnvironment]: businessId } } : {}),\n };\n}\n\nasync function writeScaffoldedFiles(\n targetDir: string,\n scaffolded: readonly ScaffoldedFile[],\n): Promise<void> {\n const files = scaffolded.map((file) => ({\n fullPath: join(targetDir, ...file.path.split('/')),\n content: file.content,\n }));\n\n const directories = new Set(files.map((file) => dirname(file.fullPath)));\n\n await Promise.all([...directories].map((dir) => mkdir(dir, { recursive: true })));\n\n await Promise.all(files.map((file) => writeFile(file.fullPath, file.content, 'utf-8')));\n}\n\nexport async function createPlugin(input: CreatePluginInput): Promise<void> {\n await mkdir(input.targetDir, { recursive: true });\n\n const manifest = buildManifest(input);\n\n await writeFile(\n join(input.targetDir, 'kizen.json'),\n JSON.stringify(manifest, null, 2) + '\\n',\n 'utf-8',\n );\n\n await mkdir(join(input.targetDir, 'src'), { recursive: true });\n\n await mkdir(join(input.targetDir, 'releaseNotes'), { recursive: true });\n\n await Promise.all([\n writeScaffoldedFiles(input.targetDir, scaffoldArtifactFiles(input.artifacts ?? [])),\n writeScaffoldedFiles(input.targetDir, copilotFiles()),\n writeScaffoldedFiles(input.targetDir, claudeFiles()),\n writeFile(join(input.targetDir, ...THUMBNAIL_PATH.split('/')), thumbnailBytes(input.apiName)),\n ]);\n\n ensureGitignore(input.targetDir);\n}\n","{\n \"name\": \"Hello Frame\",\n \"api_name\": \"hello_frame\",\n \"title\": \"Hello Frame\",\n \"default_position\": \"bottom-right\",\n \"minimized_style\": \"circle\",\n \"height\": 320,\n \"width\": 280\n}\n","this.outputUI(`\n <div class=\"hello-frame\">\n <h2 class=\"hello-frame__title\">Hello from a floating frame</h2>\n <p class=\"hello-frame__body\">Edit src/floatingFrames/helloFrame/script.js to change this.</p>\n </div>\n`);\n",".hello-frame {\n padding: 16px;\n font-family: system-ui, sans-serif;\n}\n\n.hello-frame__title {\n margin: 0 0 8px;\n font-size: 16px;\n}\n\n.hello-frame__body {\n margin: 0;\n color: #555;\n}\n","{\n \"name\": \"Hello Block\",\n \"api_name\": \"hello_block\",\n \"types\": [\"dashboards\"]\n}\n","this.outputUI(`\n <div class=\"hello-block\">\n <h2 class=\"hello-block__title\">Hello from a block</h2>\n <p class=\"hello-block__body\">Edit src/blocks/helloBlock/script.js to change this.</p>\n </div>\n`);\n",".hello-block {\n padding: 16px;\n font-family: system-ui, sans-serif;\n background: #f8fafc;\n border-radius: 6px;\n}\n\n.hello-block__title {\n margin: 0 0 8px;\n font-size: 16px;\n}\n\n.hello-block__body {\n margin: 0;\n color: #555;\n}\n","{\n \"icon\": \"phone\",\n \"color\": \"#0ea5e9\",\n \"tooltip\": \"Hello adornment\",\n \"field_type\": \"phonenumber\"\n}\n","this.showToast('Hello from a data adornment.', { variant: 'success' });\n","{\n \"name\": \"Hello Page\",\n \"api_name\": \"hello_page\"\n}\n","this.outputUI(`\n <div class=\"hello-page\">\n <p class=\"hello-page__loading\">Loading…</p>\n </div>\n`);\n\nthis.runEventScript('greet');\n",".hello-page {\n padding: 24px;\n font-family: system-ui, sans-serif;\n}\n\n.hello-page__title {\n margin: 0 0 8px;\n font-size: 20px;\n}\n\n.hello-page__body {\n margin: 0 0 16px;\n color: #555;\n}\n\n.hello-page__loading {\n margin: 0;\n color: #94a3b8;\n}\n\n.hello-page__actions {\n display: flex;\n gap: 8px;\n}\n\n.hello-page__button {\n padding: 6px 12px;\n font: inherit;\n color: #0f172a;\n background: #e2e8f0;\n border: 0;\n border-radius: 4px;\n cursor: pointer;\n}\n\n.hello-page__button:hover {\n background: #cbd5e1;\n}\n","const tone = this.args?.formData?.tone?.[0] ?? 'plain';\n\nconst greeting = tone === 'cheer' ? 'Hello, and good to see you!' : 'Hello from a routable page.';\n\nthis.outputUI(`\n <div class=\"hello-page\">\n <h1 class=\"hello-page__title\">${greeting}</h1>\n <p class=\"hello-page__body\">\n This markup came from eventScripts/greet.js. Either button re-runs it and\n repaints the page with a different greeting.\n </p>\n <div class=\"hello-page__actions\">\n <form data-script=\"greet\">\n <input type=\"hidden\" name=\"tone\" value=\"plain\" />\n <button class=\"hello-page__button\" type=\"submit\">Plain</button>\n </form>\n <form data-script=\"greet\">\n <input type=\"hidden\" name=\"tone\" value=\"cheer\" />\n <button class=\"hello-page__button\" type=\"submit\">Cheerful</button>\n </form>\n </div>\n </div>\n`);\n","{\n \"api_name\": \"hello_toolbar_item\",\n \"label\": \"Hello Toolbar Item\",\n \"icon\": \"star\",\n \"color\": \"#0ea5e9\"\n}\n","this.showToast('Hello from a toolbar item.', { variant: 'success' });\n","{\n \"api_name\": \"hello_object_settings_item\",\n \"label\": \"Hello Object Settings\"\n}\n","this.showToast('Hello from an object settings item.', { variant: 'success' });\n","{\n \"name\": \"Hello Action\",\n \"api_name\": \"hello_action\",\n \"hint_object_name\": \"client_client\"\n}\n","this.showToast('Hello from a JS action.', { variant: 'success' });\n","import helloFrameConfig from '../templates/artifacts/floatingFrames/helloFrame/config.json?raw';\nimport helloFrameScript from '../templates/artifacts/floatingFrames/helloFrame/script.js?raw';\nimport helloFrameStyles from '../templates/artifacts/floatingFrames/helloFrame/styles.css?raw';\nimport helloBlockConfig from '../templates/artifacts/blocks/helloBlock/config.json?raw';\nimport helloBlockScript from '../templates/artifacts/blocks/helloBlock/script.js?raw';\nimport helloBlockStyles from '../templates/artifacts/blocks/helloBlock/styles.css?raw';\nimport helloAdornmentConfig from '../templates/artifacts/dataAdornments/helloAdornment/config.json?raw';\nimport helloAdornmentScript from '../templates/artifacts/dataAdornments/helloAdornment/script.js?raw';\nimport helloPageConfig from '../templates/artifacts/pages/helloPage/config.json?raw';\nimport helloPageScript from '../templates/artifacts/pages/helloPage/script.js?raw';\nimport helloPageStyles from '../templates/artifacts/pages/helloPage/styles.css?raw';\nimport helloPageGreet from '../templates/artifacts/pages/helloPage/eventScripts/greet.js?raw';\nimport helloToolbarItemConfig from '../templates/artifacts/toolbarItems/helloToolbarItem/config.json?raw';\nimport helloToolbarItemScript from '../templates/artifacts/toolbarItems/helloToolbarItem/script.js?raw';\nimport helloObjectSettingsItemConfig from '../templates/artifacts/objectSettingsItems/helloObjectSettingsItem/config.json?raw';\nimport helloObjectSettingsItemScript from '../templates/artifacts/objectSettingsItems/helloObjectSettingsItem/script.js?raw';\nimport helloActionConfig from '../templates/artifacts/actions/helloAction/config.json?raw';\nimport helloActionScript from '../templates/artifacts/actions/helloAction/script.js?raw';\n\nexport const ARTIFACT_TYPES = [\n 'floatingFrame',\n 'block',\n 'dataAdornment',\n 'page',\n 'toolbarItem',\n 'objectSettingsItem',\n 'jsAction',\n] as const;\n\nexport type ArtifactType = (typeof ARTIFACT_TYPES)[number];\n\nexport const ARTIFACT_LABELS: Record<ArtifactType, string> = {\n floatingFrame: 'Floating frame',\n block: 'Block',\n dataAdornment: 'Data adornment',\n page: 'Routable page',\n toolbarItem: 'Toolbar item',\n objectSettingsItem: 'Object settings item',\n jsAction: 'JS action',\n};\n\nexport interface ScaffoldedFile {\n path: string;\n content: string;\n}\n\ninterface ArtifactTemplate {\n directory: string;\n component: string;\n files: Readonly<Record<string, string>>;\n}\n\nconst TEMPLATES: Record<ArtifactType, ArtifactTemplate> = {\n floatingFrame: {\n directory: 'floatingFrames',\n component: 'helloFrame',\n files: {\n 'config.json': helloFrameConfig,\n 'script.js': helloFrameScript,\n 'styles.css': helloFrameStyles,\n },\n },\n\n block: {\n directory: 'blocks',\n component: 'helloBlock',\n files: {\n 'config.json': helloBlockConfig,\n 'script.js': helloBlockScript,\n 'styles.css': helloBlockStyles,\n },\n },\n\n dataAdornment: {\n directory: 'dataAdornments',\n component: 'helloAdornment',\n files: {\n 'config.json': helloAdornmentConfig,\n 'script.js': helloAdornmentScript,\n },\n },\n\n page: {\n directory: 'pages',\n component: 'helloPage',\n files: {\n 'config.json': helloPageConfig,\n 'script.js': helloPageScript,\n 'styles.css': helloPageStyles,\n 'eventScripts/greet.js': helloPageGreet,\n },\n },\n\n toolbarItem: {\n directory: 'toolbarItems',\n component: 'helloToolbarItem',\n files: {\n 'config.json': helloToolbarItemConfig,\n 'script.js': helloToolbarItemScript,\n },\n },\n\n objectSettingsItem: {\n directory: 'objectSettingsItems',\n component: 'helloObjectSettingsItem',\n files: {\n 'config.json': helloObjectSettingsItemConfig,\n 'script.js': helloObjectSettingsItemScript,\n },\n },\n\n jsAction: {\n directory: 'actions',\n component: 'helloAction',\n files: {\n 'config.json': helloActionConfig,\n 'script.js': helloActionScript,\n },\n },\n};\n\nexport function artifactFiles(type: ArtifactType, entryDir = 'src'): ScaffoldedFile[] {\n const { directory, component, files } = TEMPLATES[type];\n\n return Object.entries(files).map(([relativePath, content]) => ({\n path: `${entryDir}/${directory}/${component}/${relativePath}`,\n content,\n }));\n}\n\nexport function scaffoldArtifactFiles(\n types: readonly ArtifactType[],\n entryDir = 'src',\n): ScaffoldedFile[] {\n return [...new Set(types)].flatMap((type) => artifactFiles(type, entryDir));\n}\n","import { deflateSync } from 'node:zlib';\n\nexport const THUMBNAIL_SIZE = 512;\n\nconst BODY_HALF_SIZE = 150;\n\nconst BODY_CORNER_RADIUS = 26;\n\nconst KNOB_RADIUS = 46;\n\nconst KNOB_OFFSET_RATIO = 0.6;\n\nconst NECK_HALF_WIDTH = KNOB_RADIUS * 0.55;\n\nconst SATURATION = 0.55;\n\nconst LIGHTNESS = 0.47;\n\nexport interface ThumbnailStyle {\n hue: number;\n quarterTurns: 0 | 1 | 2 | 3;\n}\n\nfunction fnv1a(text: string): number {\n let hash = 0x811c9dc5;\n\n for (let i = 0; i < text.length; i += 1) {\n hash ^= text.charCodeAt(i);\n\n hash = (hash + ((hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24))) >>> 0;\n }\n\n return hash;\n}\n\nexport function thumbnailStyle(apiName: string): ThumbnailStyle {\n const hash = fnv1a(apiName);\n\n return {\n hue: hash % 360,\n quarterTurns: ((hash >>> 16) % 4) as 0 | 1 | 2 | 3,\n };\n}\n\nfunction hslToRgb(hue: number, saturation: number, lightness: number): [number, number, number] {\n const chroma = (1 - Math.abs(2 * lightness - 1)) * saturation;\n const sector = hue / 60;\n const secondary = chroma * (1 - Math.abs((sector % 2) - 1));\n const match = lightness - chroma / 2;\n\n const [r, g, b] =\n sector < 1\n ? [chroma, secondary, 0]\n : sector < 2\n ? [secondary, chroma, 0]\n : sector < 3\n ? [0, chroma, secondary]\n : sector < 4\n ? [0, secondary, chroma]\n : sector < 5\n ? [secondary, 0, chroma]\n : [chroma, 0, secondary];\n\n return [\n Math.round((r + match) * 255),\n Math.round((g + match) * 255),\n Math.round((b + match) * 255),\n ];\n}\n\nfunction roundedBoxDistance(\n x: number,\n y: number,\n halfW: number,\n halfH: number,\n radius: number,\n): number {\n const qx = Math.abs(x) - halfW + radius;\n const qy = Math.abs(y) - halfH + radius;\n\n return Math.hypot(Math.max(qx, 0), Math.max(qy, 0)) + Math.min(Math.max(qx, qy), 0) - radius;\n}\n\nfunction circleDistance(x: number, y: number, cx: number, cy: number, radius: number): number {\n return Math.hypot(x - cx, y - cy) - radius;\n}\n\nfunction puzzlePieceDistance(x: number, y: number): number {\n const s = BODY_HALF_SIZE;\n const k = KNOB_RADIUS;\n const offset = k * KNOB_OFFSET_RATIO;\n const neckHalf = NECK_HALF_WIDTH;\n\n let d = roundedBoxDistance(x, y, s, s, BODY_CORNER_RADIUS);\n\n const topKnob = Math.min(\n circleDistance(x, y, 0, -s - offset, k),\n roundedBoxDistance(x, y + s + offset / 2, neckHalf, offset / 2 + 1, 0),\n );\n\n const rightKnob = Math.min(\n circleDistance(x, y, s + offset, 0, k),\n roundedBoxDistance(x - s - offset / 2, y, offset / 2 + 1, neckHalf, 0),\n );\n\n d = Math.min(d, topKnob, rightKnob);\n\n const bottomSocket = Math.min(\n circleDistance(x, y, 0, s - offset, k),\n roundedBoxDistance(x, y - s + offset / 2, neckHalf, offset / 2 + 1, 0),\n );\n\n const leftSocket = Math.min(\n circleDistance(x, y, -s + offset, 0, k),\n roundedBoxDistance(x + s - offset / 2, y, offset / 2 + 1, neckHalf, 0),\n );\n\n return Math.max(d, -bottomSocket, -leftSocket);\n}\n\nfunction renderPixels(style: ThumbnailStyle): Uint8Array {\n const size = THUMBNAIL_SIZE;\n const pixels = new Uint8Array(size * size * 4);\n const [r, g, b] = hslToRgb(style.hue, SATURATION, LIGHTNESS);\n\n const knobExtension = KNOB_RADIUS * (1 + KNOB_OFFSET_RATIO);\n const centre = (size - 1) / 2;\n const shift = knobExtension / 2;\n\n for (let py = 0; py < size; py += 1) {\n for (let px = 0; px < size; px += 1) {\n let x = px - centre;\n let y = py - centre;\n\n for (let turn = 0; turn < style.quarterTurns; turn += 1) {\n [x, y] = [-y, x];\n }\n\n const d = puzzlePieceDistance(x + shift, y - shift);\n\n const coverage = Math.min(1, Math.max(0, 0.5 - d));\n\n if (coverage <= 0) {\n continue;\n }\n\n const i = (py * size + px) * 4;\n\n pixels[i] = r;\n pixels[i + 1] = g;\n pixels[i + 2] = b;\n pixels[i + 3] = Math.round(coverage * 255);\n }\n }\n\n return pixels;\n}\n\nconst CRC_TABLE = new Uint32Array(256).map((_, n) => {\n let c = n;\n\n for (let k = 0; k < 8; k += 1) {\n c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;\n }\n\n return c >>> 0;\n});\n\nfunction crc32(bytes: Uint8Array): number {\n let crc = 0xffffffff;\n\n for (const byte of bytes) {\n crc = (CRC_TABLE[(crc ^ byte) & 0xff] ?? 0) ^ (crc >>> 8);\n }\n\n return (crc ^ 0xffffffff) >>> 0;\n}\n\nfunction pngChunk(type: string, data: Uint8Array): Buffer {\n const typeBytes = Buffer.from(type, 'latin1');\n const length = Buffer.alloc(4);\n\n length.writeUInt32BE(data.length);\n\n const crc = Buffer.alloc(4);\n\n crc.writeUInt32BE(crc32(Buffer.concat([typeBytes, data])));\n\n return Buffer.concat([length, typeBytes, data, crc]);\n}\n\nconst PNG_SIGNATURE = Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]);\n\nexport function encodePng(width: number, height: number, rgba: Uint8Array): Buffer {\n if (rgba.length !== width * height * 4) {\n throw new Error(\n `encodePng: expected ${String(width * height * 4)} bytes of RGBA for ${String(width)}x${String(height)}, got ${String(rgba.length)}`,\n );\n }\n\n const ihdr = Buffer.alloc(13);\n\n ihdr.writeUInt32BE(width, 0);\n ihdr.writeUInt32BE(height, 4);\n ihdr[8] = 8;\n ihdr[9] = 6;\n\n const stride = width * 4;\n const raw = Buffer.alloc((stride + 1) * height);\n\n for (let y = 0; y < height; y += 1) {\n raw.set(rgba.subarray(y * stride, (y + 1) * stride), y * (stride + 1) + 1);\n }\n\n return Buffer.concat([\n PNG_SIGNATURE,\n pngChunk('IHDR', ihdr),\n pngChunk('IDAT', deflateSync(raw, { level: 9 })),\n pngChunk('IEND', new Uint8Array(0)),\n ]);\n}\n\nexport function thumbnailBytes(apiName: string): Buffer {\n return encodePng(THUMBNAIL_SIZE, THUMBNAIL_SIZE, renderPixels(thumbnailStyle(apiName)));\n}\n","import { ARTIFACT_TYPES } from './createArtifacts.js';\nimport type { ArtifactType } from './createArtifacts.js';\n\nexport const FIELDS = [\n 'name',\n 'apiName',\n 'externalLink',\n 'description',\n 'developerBusinessId',\n] as const;\n\nexport type FieldName = (typeof FIELDS)[number];\n\nexport const FIELD_LABELS: Record<FieldName, string> = {\n name: 'Name',\n apiName: 'API name',\n externalLink: 'External link',\n description: 'Description',\n developerBusinessId: 'Business ID',\n};\n\nexport const REQUIRED_FIELDS: readonly FieldName[] = ['name', 'apiName', 'description'];\n\nexport type FieldValues = Record<FieldName, string>;\n\nexport const API_NAME_PATTERN = /^[a-z_][a-z0-9_]+$/;\n\nexport const API_NAME_HINT =\n 'must start with a letter or underscore and contain only lowercase letters, numbers, or underscores (minimum 2 characters)';\n\nexport function inferApiName(name: string): string {\n return name\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '_')\n .replace(/^_+|_+$/g, '');\n}\n\nexport function emptyValues(defaultBusinessId: string): FieldValues {\n return {\n name: '',\n apiName: '',\n externalLink: '',\n description: '',\n developerBusinessId: defaultBusinessId,\n };\n}\n\nexport function validateField(fieldName: FieldName, inputBuffer: string): string | undefined {\n const value = inputBuffer.trim();\n\n if (REQUIRED_FIELDS.includes(fieldName) && !value) {\n return `${FIELD_LABELS[fieldName]} is required`;\n }\n\n if (fieldName === 'apiName' && !API_NAME_PATTERN.test(value)) {\n return `${FIELD_LABELS[fieldName]} ${API_NAME_HINT}`;\n }\n\n return undefined;\n}\n\nexport function normalizeFieldValue(fieldName: FieldName, inputBuffer: string): string {\n return fieldName === 'description' ? inputBuffer : inputBuffer.trim();\n}\n\nexport function toggleArtifactSelection(\n selected: readonly ArtifactType[],\n type: ArtifactType,\n): ArtifactType[] {\n const next = new Set(selected);\n\n if (next.has(type)) {\n next.delete(type);\n } else {\n next.add(type);\n }\n\n return ARTIFACT_TYPES.filter((candidate) => next.has(candidate));\n}\n","import { ARTIFACT_TYPES } from './createArtifacts.js';\nimport type { ArtifactType } from './createArtifacts.js';\nimport { API_NAME_HINT, API_NAME_PATTERN, inferApiName } from './createForm.js';\nimport type { CreatePluginInput, PrecheckResult } from './createPlugin.js';\nimport { ENVIRONMENTS } from '../../shared/lib/credentials.js';\nimport type { Environment } from '../../shared/lib/credentials.js';\n\nexport const PLACEHOLDER_DESCRIPTION = 'A hello-world Kizen plugin.';\n\nexport interface CreateOptions {\n name?: string;\n apiName?: string;\n description?: string;\n externalLink?: string;\n businessId?: string;\n environment?: string;\n artifacts?: string;\n}\n\nexport interface HeadlessDefaults {\n businessId: string;\n environment: Environment;\n}\n\nexport function parseArtifactSelection(raw: string | undefined): ArtifactType[] {\n if (raw === undefined || raw.trim() === '' || raw.trim() === 'all') {\n return [...ARTIFACT_TYPES];\n }\n\n if (raw.trim() === 'none') {\n return [];\n }\n\n const requested = raw\n .split(',')\n .map((part) => part.trim())\n .filter((part) => part !== '');\n\n const unknown = requested.filter((part) => !ARTIFACT_TYPES.includes(part as ArtifactType));\n\n if (unknown.length > 0) {\n throw new Error(\n `Unknown artifact type(s): ${unknown.join(', ')}. Valid types: ${ARTIFACT_TYPES.join(', ')}, or \"all\" / \"none\".`,\n );\n }\n\n return [...new Set(requested as ArtifactType[])];\n}\n\nexport function resolveHeadlessInput(\n options: CreateOptions,\n defaults: HeadlessDefaults,\n targetDir: string,\n): CreatePluginInput {\n const name = options.name?.trim() ?? '';\n\n if (name === '') {\n throw new Error('--name is required for a non-interactive run.');\n }\n\n const apiName = (options.apiName?.trim() ?? '') || inferApiName(name);\n\n if (!API_NAME_PATTERN.test(apiName)) {\n throw new Error(`api_name \"${apiName}\" is invalid: ${API_NAME_HINT}. Pass --api-name.`);\n }\n\n const description = options.description?.trim();\n\n const developerBusinessId = options.businessId?.trim() ?? defaults.businessId;\n const developerEnvironment = resolveEnvironment(options, defaults);\n\n return {\n targetDir,\n name,\n apiName,\n externalLink: options.externalLink?.trim() ?? '',\n description:\n description === undefined || description === '' ? PLACEHOLDER_DESCRIPTION : description,\n developerBusinessId,\n developerEnvironment,\n artifacts: parseArtifactSelection(options.artifacts),\n };\n}\n\nfunction isEnvironment(value: string): value is Environment {\n return (ENVIRONMENTS as readonly string[]).includes(value);\n}\n\nfunction resolveEnvironment(options: CreateOptions, defaults: HeadlessDefaults): Environment {\n const requested = options.environment?.trim();\n\n if (requested !== undefined && requested !== '') {\n if (!isEnvironment(requested)) {\n throw new Error(\n `Unknown environment \"${requested}\". Valid environments: ${ENVIRONMENTS.join(', ')}.`,\n );\n }\n\n return requested;\n }\n\n if (options.businessId !== undefined && defaults.businessId === '') {\n throw new Error(\n '--environment is required alongside --business-id when no credentials are saved, so the id is keyed to the environment that issued it.',\n );\n }\n\n return defaults.environment;\n}\n\nexport interface HeadlessDeps {\n precheckTargetDir: (dir: string) => Promise<PrecheckResult>;\n createPlugin: (input: CreatePluginInput) => Promise<void>;\n writeStdout: (text: string) => void;\n writeStderr: (text: string) => void;\n setExitCode: (code: number) => void;\n}\n\nexport async function runHeadlessCreate(\n options: CreateOptions,\n defaults: HeadlessDefaults,\n targetDir: string,\n deps: HeadlessDeps,\n): Promise<void> {\n let input: CreatePluginInput;\n\n try {\n input = resolveHeadlessInput(options, defaults, targetDir);\n } catch (err) {\n deps.writeStderr(`Error: ${err instanceof Error ? err.message : String(err)}\\n`);\n\n deps.setExitCode(1);\n\n return;\n }\n\n const precheck = await deps.precheckTargetDir(targetDir);\n\n if (precheck !== 'ok') {\n const conflict = precheck === 'has-manifest' ? 'kizen.json' : '.kizenapp/';\n\n deps.writeStderr(\n `Error: ${targetDir} already contains ${conflict}. Refusing to overwrite an existing plugin.\\n`,\n );\n\n deps.setExitCode(1);\n\n return;\n }\n\n try {\n await deps.createPlugin(input);\n } catch (err) {\n deps.writeStderr(`Error: ${err instanceof Error ? err.message : String(err)}\\n`);\n\n deps.setExitCode(1);\n\n return;\n }\n\n const artifactSummary =\n input.artifacts && input.artifacts.length > 0 ? input.artifacts.join(', ') : 'none';\n\n deps.writeStdout(`Created plugin ${input.apiName} at ${targetDir}\\n`);\n\n deps.writeStdout(`Artifacts: ${artifactSummary}\\n`);\n\n deps.writeStdout(\n 'Thumbnail: src/thumbnail.png (generated placeholder; replace it before publishing)\\n',\n );\n\n if (input.developerBusinessId.trim() === '') {\n deps.writeStderr(\n 'Warning: no developer_business_id configured, so this plugin cannot be preview-published yet.\\n',\n );\n }\n}\n","import { createElement } from 'react';\nimport { render } from 'ink';\nimport type { Command } from 'commander';\nimport { DevUI } from '../ui/DevUI.js';\nimport { CredentialSetupUI } from '../ui/CredentialSetupUI.js';\nimport type { CredentialMode, CredentialSetupResult } from '../ui/CredentialSetupUI.js';\nimport {\n loadCredentialProfile,\n loadCredentialsFromFile,\n loadGlobalCredentials,\n} from '../lib/credentials.js';\nimport type { Credentials } from '../lib/credentials.js';\nimport { loadConfig, saveConfig } from '../lib/config.js';\nimport { ensureGitignore } from '../lib/gitignore.js';\n\nasync function runSetupUI(initialMode?: CredentialMode): Promise<CredentialSetupResult> {\n return new Promise((resolve) => {\n let unmountFn: (() => void) | null = null;\n const handleComplete = (result: CredentialSetupResult): void => {\n unmountFn?.();\n\n resolve(result);\n };\n\n const { unmount } = render(\n createElement(CredentialSetupUI, {\n ...(initialMode !== undefined && { initialMode }),\n onComplete: handleComplete,\n }),\n { exitOnCtrlC: false },\n );\n\n unmountFn = unmount;\n });\n}\n\nexport function devCommand(program: Command): void {\n program\n .command('dev')\n .description('Start the plugin viewer dev server')\n .option('-p, --port <port>', 'port to listen on', '3121')\n .option('-c, --credentials <path>', 'path to a credentials JSON file')\n .option('-d, --debug', 'Enable CDP lifecycle logs in the TUI')\n .option('-v, --verbose', 'Log every CDP event and handled error (implies --debug)')\n .option('--no-viewer', \"Don't auto-launch the viewer on startup (press [v] to launch manually)\")\n .option('--no-cache', 'Disable the network proxy cache (always fetch upstream)')\n .action(\n async (options: {\n port: string;\n credentials?: string;\n debug?: boolean;\n verbose?: boolean;\n viewer?: boolean;\n cache?: boolean;\n }) => {\n const port = parseInt(options.port, 10);\n const pluginDir = process.cwd();\n const outputDir = `${pluginDir}/.kizenapp`;\n\n ensureGitignore(pluginDir);\n\n let credentials: Credentials | null = null;\n let credentialMode: CredentialMode | undefined;\n let activeCredentialProfile: string | undefined;\n const { lastPath } = await loadConfig(outputDir);\n\n if (options.credentials) {\n credentials = await loadCredentialsFromFile(options.credentials);\n } else {\n const config = await loadConfig(outputDir);\n\n if (config.credentialMode === 'local') {\n credentialMode = 'local';\n } else if (config.credentialMode === 'global') {\n credentialMode = 'global';\n\n activeCredentialProfile = config.activeCredentialProfile;\n\n // Load silently — only show TUI if the file was deleted since last run\n if (activeCredentialProfile) {\n credentials = await loadCredentialProfile(activeCredentialProfile);\n\n if (!credentials) {\n // Named profile file missing, fall back to default\n credentials = await loadGlobalCredentials();\n\n activeCredentialProfile = undefined;\n }\n } else {\n credentials = await loadGlobalCredentials();\n }\n\n if (!credentials) {\n const result = await runSetupUI('global');\n\n credentials = result.credentials;\n\n activeCredentialProfile = result.profileName;\n }\n } else {\n // First run — show full mode selection TUI\n const result = await runSetupUI();\n\n credentials = result.credentials;\n\n credentialMode = result.mode;\n\n activeCredentialProfile = result.profileName;\n\n const profile = result.profileName;\n\n await saveConfig(outputDir, {\n credentialMode: result.mode,\n ...(profile !== undefined && { activeCredentialProfile: profile }),\n });\n }\n }\n\n const verbose = options.verbose === true;\n const debug = verbose || options.debug === true;\n const autoViewer = options.viewer !== false;\n const cacheEnabled = options.cache !== false;\n\n const { waitUntilExit } = render(\n createElement(DevUI, {\n port,\n pluginDir,\n outputDir,\n credentials,\n ...(credentialMode !== undefined && { credentialMode }),\n ...(activeCredentialProfile !== undefined && { activeCredentialProfile }),\n ...(lastPath !== undefined && { lastPath }),\n debug,\n verbose,\n autoViewer,\n cacheEnabled,\n }),\n { exitOnCtrlC: false },\n );\n\n await waitUntilExit();\n },\n );\n}\n","import type { FC } from 'react';\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport { Box, Text, useInput } from 'ink';\nimport { PluginValidationError } from '@kizenapps/packager';\nimport type { ValidationIssue } from '@kizenapps/packager';\nimport { watch } from 'node:fs';\nimport type { FSWatcher } from 'node:fs';\nimport { createServer } from 'node:http';\nimport type { Server } from 'node:http';\nimport { join } from 'node:path';\nimport { type WebSocket, WebSocketServer } from 'ws';\nimport {\n createRequestHandler,\n fileExists,\n getViewerPath,\n type ProxyLogEntry,\n proxyLogEntryToString,\n} from '../server/requestHandler.js';\nimport { launchChromeViewer, type ChromeViewerHandle } from '../chrome/launcher.js';\nimport { runBuild } from '../lib/runBuild.js';\nimport type { Credentials } from '../lib/credentials.js';\nimport { saveConfig } from '../lib/config.js';\nimport { LOG_LIMIT, LOG_DISPLAY, FILE_WATCH_DEBOUNCE_MS } from '../lib/constants.js';\nimport { formatBytes } from '../../shared/lib/formatBytes.js';\nimport { useLogHistory } from '../hooks/useLogHistory.js';\nimport { CredentialSetupUI } from './CredentialSetupUI.js';\nimport type { CredentialMode, CredentialSetupResult } from './CredentialSetupUI.js';\nimport { AppHeader } from './AppHeader.js';\nimport { Spinner } from './Spinner.js';\nimport { ValidationIssues } from './ValidationIssues.js';\n\ntype ServerStatus = 'starting' | 'running' | 'error';\ntype BuildStatus = 'pending' | 'building' | 'done' | 'error';\n\nconst SKIP_WATCH_PREFIXES = ['.kizenapp', '.git'];\n\ninterface DevUIProps {\n port: number;\n pluginDir: string;\n outputDir: string;\n credentials: Credentials | null;\n credentialMode?: CredentialMode;\n activeCredentialProfile?: string;\n lastPath?: string;\n debug?: boolean;\n verbose?: boolean;\n autoViewer?: boolean;\n cacheEnabled?: boolean;\n}\n\nexport const DevUI: FC<DevUIProps> = ({\n port,\n pluginDir,\n outputDir,\n credentials: initialCredentials,\n credentialMode: initialCredentialMode,\n activeCredentialProfile: initialActiveProfile,\n lastPath: initialLastPath,\n debug = false,\n verbose = false,\n autoViewer = true,\n cacheEnabled = true,\n}) => {\n const credentialsRef = useRef<Credentials | null>(initialCredentials);\n const activeProfileRef = useRef<string | undefined>(initialActiveProfile);\n const lastPathRef = useRef<string | undefined>(initialLastPath);\n const [credMode, setCredMode] = useState<'main' | 'editing'>('main');\n const [credentialMode, setCredentialMode] = useState<CredentialMode | undefined>(\n initialCredentialMode,\n );\n\n const [status, setStatus] = useState<ServerStatus>('starting');\n const [errorMessage, setErrorMessage] = useState<string | null>(null);\n const [serverLogHistory, appendServerLog] = useLogHistory(LOG_LIMIT);\n const [buildLogHistory, appendBuildLog] = useLogHistory(LOG_LIMIT);\n const [cdpLogHistory, appendCdpLog] = useLogHistory(LOG_LIMIT);\n const [proxyLogHistory, setProxyLogHistory] = useState<string[]>([]);\n const [buildStatus, setBuildStatus] = useState<BuildStatus>('pending');\n const [buildError, setBuildError] = useState<string | null>(null);\n const [buildIssues, setBuildIssues] = useState<ValidationIssue[] | null>(null);\n const [lastBuilt, setLastBuilt] = useState<Date | null>(null);\n const [lastBundleSize, setLastBundleSize] = useState<number | null>(null);\n const [wsClientCount, setWsClientCount] = useState(0);\n const [proxyCacheSize, setProxyCacheSize] = useState(0);\n const [proxyCacheHits, setProxyCacheHits] = useState(0);\n const [proxyCacheMisses, setProxyCacheMisses] = useState(0);\n\n const buildingRef = useRef(false);\n const viewerLaunchedRef = useRef(false);\n const chromeHandleRef = useRef<ChromeViewerHandle | null>(null);\n const debounceTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const wsClientsRef = useRef<Set<WebSocket>>(new Set());\n const pendingMessagesRef = useRef<string[]>([]);\n\n const broadcast = useCallback((msg: object): void => {\n const json = JSON.stringify(msg);\n\n if (wsClientsRef.current.size === 0) {\n pendingMessagesRef.current = [...pendingMessagesRef.current, json].slice(-LOG_LIMIT);\n\n return;\n }\n\n let pruned = false;\n\n for (const client of wsClientsRef.current) {\n if (client.readyState !== 1) {\n continue;\n }\n\n try {\n client.send(json);\n } catch {\n // Socket died between readyState check and send — drop it so one\n // dead client can't break the loop and silently disconnect the rest.\n wsClientsRef.current.delete(client);\n pruned = true;\n }\n }\n\n if (pruned) {\n setWsClientCount(wsClientsRef.current.size);\n }\n }, []);\n\n const createServerLog = appendServerLog;\n\n const launchChromeViewerCb = useCallback(() => {\n chromeHandleRef.current?.kill();\n\n chromeHandleRef.current = null;\n\n void launchChromeViewer({\n port,\n userDataDir: join(outputDir, '.chrome'),\n broadcast,\n onWarn: (msg) => {\n appendServerLog(`⚠ ${msg}`);\n },\n ...(lastPathRef.current !== undefined && { path: lastPathRef.current }),\n ...(debug && { debugLog: appendCdpLog }),\n ...(verbose && { verbose: true }),\n }).then((handle) => {\n chromeHandleRef.current = handle;\n });\n }, [port, outputDir, broadcast, debug, verbose, appendCdpLog, appendServerLog]);\n\n useEffect(() => {\n const onExit = (): void => {\n chromeHandleRef.current?.kill();\n };\n\n process.on('exit', onExit);\n\n return () => {\n process.off('exit', onExit);\n };\n }, []);\n\n useInput(\n (input, key) => {\n if (input === 'q' || (key.ctrl && input === 'c')) {\n process.exit(0);\n }\n\n if (input === 'c') {\n setCredMode('editing');\n }\n\n if (input === 'v') {\n launchChromeViewerCb();\n }\n },\n { isActive: credMode === 'main' },\n );\n\n useEffect(() => {\n if (status !== 'running' || viewerLaunchedRef.current || !autoViewer) {\n return;\n }\n\n viewerLaunchedRef.current = true;\n\n launchChromeViewerCb();\n }, [status, autoViewer, launchChromeViewerCb]);\n\n const handleCredentialsDone = useCallback(\n (result: CredentialSetupResult): void => {\n credentialsRef.current = result.credentials;\n\n activeProfileRef.current = result.profileName;\n\n setCredMode('main');\n\n setCredentialMode(result.mode);\n\n const profile = result.profileName;\n\n void saveConfig(outputDir, {\n credentialMode: result.mode,\n ...(profile !== undefined && { activeCredentialProfile: profile }),\n });\n\n broadcast({ type: 'credentials-updated', credentials: result.credentials });\n },\n [outputDir, broadcast],\n );\n\n const createProxyLog = useCallback(\n (entry: ProxyLogEntry): void => {\n setProxyLogHistory((h) =>\n [...h, `${new Date().toLocaleTimeString()}: ${proxyLogEntryToString(entry)}`].slice(\n -LOG_LIMIT,\n ),\n );\n\n if (entry.kind === 'request') {\n if (entry.fromCache) {\n setProxyCacheHits((n) => n + 1);\n } else {\n setProxyCacheMisses((n) => n + 1);\n }\n }\n\n broadcast({ type: 'proxy-log', entry });\n },\n [broadcast],\n );\n\n const createBuildLog = useCallback(\n (message: string): void => {\n appendBuildLog(message);\n\n broadcast({ type: 'log', message });\n },\n [appendBuildLog, broadcast],\n );\n\n const triggerBuild = useCallback(() => {\n if (buildingRef.current) {\n return;\n }\n\n buildingRef.current = true;\n setBuildStatus('building');\n setBuildError(null);\n setBuildIssues(null);\n createBuildLog('Build started');\n\n void runBuild(pluginDir, outputDir)\n .then(({ bundleSize }) => {\n createBuildLog(`Build finished — bundle: ${formatBytes(bundleSize)}`);\n setBuildStatus('done');\n setLastBuilt(new Date());\n setLastBundleSize(bundleSize);\n createBuildLog('Notifying viewers to reload');\n broadcast({ type: 'rebuild' });\n })\n .catch((err: unknown) => {\n if (err instanceof PluginValidationError) {\n setBuildIssues(err.issues);\n setBuildError(null);\n } else {\n setBuildError(err instanceof Error ? err.message : String(err));\n setBuildIssues(null);\n }\n\n setBuildStatus('error');\n })\n .finally(() => {\n buildingRef.current = false;\n });\n }, [pluginDir, outputDir, createBuildLog, broadcast]);\n\n useEffect(() => {\n triggerBuild();\n\n const watcher: FSWatcher = watch(pluginDir, { recursive: true }, (_, filename) => {\n if (!filename) {\n return;\n }\n\n const normalized = filename.replace(/\\\\/g, '/');\n\n if (SKIP_WATCH_PREFIXES.some((prefix) => normalized.startsWith(prefix))) {\n return;\n }\n\n createBuildLog(`File change detected: ${filename}`);\n\n if (debounceTimerRef.current !== null) {\n clearTimeout(debounceTimerRef.current);\n }\n\n debounceTimerRef.current = setTimeout(triggerBuild, FILE_WATCH_DEBOUNCE_MS);\n });\n\n // fs.watch silently dies on e.g. macOS inode-limit pressure — surface it so\n // developers know rebuilds have stopped rather than wondering why their\n // edits aren't reflected in the viewer.\n watcher.on('error', (err: Error) => {\n createBuildLog(`File watcher error — rebuilds have stopped: ${err.message}`);\n });\n\n return () => {\n watcher.close();\n\n if (debounceTimerRef.current !== null) {\n clearTimeout(debounceTimerRef.current);\n }\n };\n }, [pluginDir, triggerBuild, createBuildLog]);\n\n useEffect(() => {\n const viewerPath = getViewerPath();\n\n void fileExists(join(viewerPath, 'index.html')).then((viewerBuilt) => {\n if (!viewerBuilt) {\n setErrorMessage(\"Viewer not built. Run 'pnpm build:viewer' first.\");\n setStatus('error');\n\n return;\n }\n\n const handler = createRequestHandler(\n viewerPath,\n createServerLog,\n createProxyLog,\n credentialsRef,\n activeProfileRef,\n outputDir,\n broadcast,\n setProxyCacheSize,\n lastPathRef,\n pluginDir,\n cacheEnabled,\n );\n const server: Server = createServer(handler);\n const wss = new WebSocketServer({ server });\n\n wss.on('connection', (ws: WebSocket) => {\n for (const json of pendingMessagesRef.current) {\n if (ws.readyState === 1) {\n ws.send(json);\n }\n }\n\n pendingMessagesRef.current = [];\n createServerLog('Viewer connected for live reload');\n wsClientsRef.current.add(ws);\n setWsClientCount(wsClientsRef.current.size);\n\n ws.on('close', () => {\n wsClientsRef.current.delete(ws);\n setWsClientCount(wsClientsRef.current.size);\n });\n });\n\n server.listen(port, '127.0.0.1', () => {\n setStatus('running');\n createServerLog(`Server started on 127.0.0.1:${String(port)}`);\n });\n\n server.on('error', (err: Error) => {\n setErrorMessage(err.message);\n setStatus('error');\n });\n\n return () => {\n wss.close();\n server.close();\n };\n });\n }, [port, createServerLog, createProxyLog, broadcast, outputDir, pluginDir, cacheEnabled]);\n\n if (credMode === 'editing') {\n return (\n <CredentialSetupUI\n {...(credentialMode !== undefined && { initialMode: credentialMode })}\n showProfileManager={credentialMode === 'global'}\n onComplete={handleCredentialsDone}\n onCancel={() => {\n setCredMode('main');\n }}\n />\n );\n }\n\n const elapsedSeconds =\n lastBuilt !== null ? Math.round((Date.now() - lastBuilt.getTime()) / 1000) : null;\n\n const elapsedLabel =\n elapsedSeconds === null\n ? ''\n : elapsedSeconds < 5\n ? ' (just now)'\n : ` (${String(elapsedSeconds)}s ago)`;\n\n const buildErrorCount = buildIssues?.filter((issue) => issue.severity === 'error').length ?? 0;\n\n return (\n <Box flexDirection=\"column\" paddingY={1} paddingX={2}>\n <AppHeader marginBottom={1} />\n\n {/* Build panel */}\n <Box flexDirection=\"column\">\n <Box gap={2} marginBottom={0}>\n <Text bold dimColor>\n App Build\n </Text>\n {buildStatus === 'pending' && <Text dimColor>waiting…</Text>}\n {buildStatus === 'building' && (\n <Box gap={1}>\n <Spinner />\n <Text>Building plugin package…</Text>\n </Box>\n )}\n {buildStatus === 'done' && (\n <Box gap={1}>\n <Text color=\"green\">✓ Built</Text>\n {lastBuilt !== null && (\n <Text dimColor>\n at {lastBuilt.toLocaleTimeString()}\n {elapsedLabel}\n </Text>\n )}\n {lastBundleSize !== null && (\n <Text dimColor>· bundle: {formatBytes(lastBundleSize)}</Text>\n )}\n </Box>\n )}\n {buildStatus === 'error' &&\n (buildIssues !== null ? (\n <Text color=\"red\">\n ✗ {buildErrorCount} validation {buildErrorCount === 1 ? 'error' : 'errors'}\n </Text>\n ) : (\n <Text color=\"red\">✗ {buildError ?? 'unknown error'}</Text>\n ))}\n </Box>\n {buildIssues !== null && <ValidationIssues issues={buildIssues} />}\n <Box\n flexDirection=\"column\"\n height={LOG_DISPLAY + 2}\n borderStyle=\"single\"\n borderColor=\"gray\"\n overflow=\"hidden\"\n >\n {buildLogHistory.slice(-LOG_DISPLAY).map((log, index) => (\n <Text key={index} dimColor wrap=\"truncate\">\n {log}\n </Text>\n ))}\n </Box>\n </Box>\n\n {/* Server panel */}\n <Box marginTop={1} flexDirection=\"column\">\n <Box gap={2}>\n <Text bold dimColor>\n Web Server\n </Text>\n {status === 'starting' && <Text dimColor>starting…</Text>}\n {status === 'running' && (\n <Box gap={2}>\n <Text color=\"green\">✓ Running</Text>\n <Text dimColor>\n ● {wsClientCount} viewer{wsClientCount !== 1 ? 's' : ''}\n </Text>\n </Box>\n )}\n {status === 'error' && <Text color=\"red\">✗ {errorMessage ?? 'Server error'}</Text>}\n </Box>\n <Box\n flexDirection=\"column\"\n height={LOG_DISPLAY + 2}\n borderStyle=\"single\"\n borderColor=\"gray\"\n overflow=\"hidden\"\n >\n {serverLogHistory.slice(-LOG_DISPLAY).map((log, index) => (\n <Text key={index} dimColor wrap=\"truncate\">\n {log}\n </Text>\n ))}\n </Box>\n </Box>\n\n {/* Proxy panel */}\n <Box marginTop={1} flexDirection=\"column\">\n <Box gap={2}>\n <Text bold dimColor>\n Network Proxy\n </Text>\n <Text color=\"green\">✓ Active</Text>\n <Text dimColor>\n {cacheEnabled\n ? `● ${String(proxyCacheSize)} key${proxyCacheSize !== 1 ? 's' : ''} in the network cache · ${String(proxyCacheHits)} hit · ${String(proxyCacheMisses)} miss`\n : `● network cache disabled · ${String(proxyCacheMisses)} request${proxyCacheMisses !== 1 ? 's' : ''}`}\n </Text>\n </Box>\n <Box\n flexDirection=\"column\"\n height={LOG_DISPLAY + 2}\n borderStyle=\"single\"\n borderColor=\"gray\"\n overflow=\"hidden\"\n >\n {proxyLogHistory.length === 0 ? (\n <Text dimColor> No requests yet.</Text>\n ) : (\n proxyLogHistory.slice(-LOG_DISPLAY).map((log, i) => (\n <Text key={i} dimColor wrap=\"truncate\">\n {log}\n </Text>\n ))\n )}\n </Box>\n </Box>\n\n {debug && (\n <Box marginTop={1} flexDirection=\"column\">\n <Box gap={2}>\n <Text bold dimColor>\n CDP Debug\n </Text>\n <Text dimColor>● {cdpLogHistory.length} event(s)</Text>\n </Box>\n <Box\n flexDirection=\"column\"\n height={LOG_DISPLAY + 2}\n borderStyle=\"single\"\n borderColor=\"gray\"\n overflow=\"hidden\"\n >\n {cdpLogHistory.length === 0 ? (\n <Text dimColor> No CDP events yet.</Text>\n ) : (\n cdpLogHistory.slice(-LOG_DISPLAY).map((log, i) => (\n <Text key={i} dimColor wrap=\"truncate\">\n {log}\n </Text>\n ))\n )}\n </Box>\n </Box>\n )}\n\n {/* Footer */}\n <Box marginTop={1} gap={1}>\n <Text dimColor>[</Text>\n <Text>q</Text>\n <Text dimColor>] quit [</Text>\n <Text>c</Text>\n <Text dimColor>] credentials [</Text>\n <Text>v</Text>\n <Text dimColor>] {wsClientCount === 0 ? 'open viewer' : 'relaunch viewer'}</Text>\n </Box>\n </Box>\n );\n};\n","import { createReadStream, realpathSync } from 'node:fs';\nimport { access, readdir, readFile, realpath, stat } from 'node:fs/promises';\nimport type { IncomingMessage, ServerResponse } from 'node:http';\nimport { dirname, extname, join, resolve, sep } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport {\n createProxyCache,\n MAX_PROXY_BYTES,\n ProxyResponseTooLargeError,\n readBodyWithLimit,\n sanitizeUpstreamHeaders,\n} from '../lib/proxyCache.js';\nimport { MIME_TYPES } from '../lib/constants.js';\nimport type { Credentials } from '../lib/credentials.js';\nimport {\n listCredentialProfiles,\n loadCredentialProfile,\n loadGlobalCredentials,\n} from '../lib/credentials.js';\nimport { loadConfig, saveConfig } from '../lib/config.js';\nimport { resolveWizardBase } from '../lib/wizardUrl.js';\nimport { executePythonStep } from './pythonExecutor.js';\nimport { SKIP_DIRS } from '../lib/readFiles.js';\nimport { TEXT_EXTENSIONS } from '../../shared/lib/fileExtensions.js';\nimport { normalizeStepInputs } from '../../shared/lib/execution.js';\nimport {\n CRYPTO_ALG,\n CRYPTO_VERSION,\n deserializeEnvelope,\n encrypt,\n serializeEnvelope,\n} from '@kizenapps/packager';\n\nconst SOURCE_FILE_MAX_BYTES = 2 * 1024 * 1024;\n\nconst SKIP_FILES = new Set(['.DS_Store', '.gitignore']);\n\nfunction isLocalHost(host: string | undefined): boolean {\n if (host === undefined || host === '') {\n return false;\n }\n\n // Strip the port. This is a host header, so IPv6 would arrive as \"[::1]:port\"\n // — we don't serve ::1 (Node binds to 127.0.0.1), but the guard is permissive\n // enough to survive that even if the bind address changes later.\n const hostname = host.startsWith('[')\n ? host.slice(0, host.indexOf(']') + 1)\n : (host.split(':')[0] ?? '');\n\n return hostname === 'localhost' || hostname === '127.0.0.1' || hostname === '[::1]';\n}\n\nconst PROXY_ALLOWED_DOMAINS = ['kizen.com', 'kizen.dev'];\n\n/**\n * Guards the resolved encryption-API host. The wizard proxy forwards the\n * caller's Kizen credential headers, so a fat-fingered PLUGIN_WIZARD_URL* env\n * var must not be able to leak them to an arbitrary origin. Allows a\n * locally-running wizard (any localhost/loopback) plus https on a Kizen domain.\n */\nfunction isAllowedWizardTarget(target: string): boolean {\n let url: URL;\n\n try {\n url = new URL(target);\n } catch {\n return false;\n }\n\n const hostname = url.hostname.toLowerCase();\n\n // URL.hostname returns IPv6 literals bracketed, e.g. '[::1]'.\n if (hostname === 'localhost' || hostname === '127.0.0.1' || hostname === '[::1]') {\n return true;\n }\n\n if (url.protocol !== 'https:') {\n return false;\n }\n\n return PROXY_ALLOWED_DOMAINS.some(\n (domain) => hostname === domain || hostname.endsWith('.' + domain),\n );\n}\n\nfunction isAllowedProxyTarget(target: string): boolean {\n let url: URL;\n\n try {\n url = new URL(target);\n } catch {\n return false;\n }\n\n if (url.protocol !== 'https:') {\n return false;\n }\n\n const hostname = url.hostname.toLowerCase();\n\n return PROXY_ALLOWED_DOMAINS.some(\n (domain) => hostname === domain || hostname.endsWith('.' + domain),\n );\n}\n\nfunction isLocalOrigin(origin: string | undefined): boolean {\n if (origin === undefined || origin === '') {\n return false;\n }\n\n try {\n const { hostname } = new URL(origin);\n\n return hostname === 'localhost' || hostname === '127.0.0.1' || hostname === '::1';\n } catch {\n return false;\n }\n}\n\nasync function resolveSafePath(realPluginDir: string, relParam: string): Promise<string | null> {\n if (relParam.includes('\\0')) {\n return null;\n }\n\n const rel = relParam.replace(/^\\/+/, '');\n const abs = resolve(realPluginDir, rel);\n\n // Syntactic .. traversal check — fails fast before touching the filesystem.\n if (abs !== realPluginDir && !abs.startsWith(realPluginDir + sep)) {\n return null;\n }\n\n // Symlink-aware check: a symlink inside the plugin dir can still escape it\n // (e.g. a link to ~/.ssh/id_rsa resolves to a path that passes the string\n // check above but reads arbitrary files). Realpath the target and re-verify.\n // If the target doesn't exist realpath throws — reject rather than guess.\n try {\n const realAbs = await realpath(abs);\n\n if (realAbs !== realPluginDir && !realAbs.startsWith(realPluginDir + sep)) {\n return null;\n }\n\n return realAbs;\n } catch {\n return null;\n }\n}\n\nfunction isInsideSkippedDir(pluginDir: string, abs: string): boolean {\n const rel = abs === pluginDir ? '' : abs.slice(pluginDir.length + 1);\n\n if (rel === '') {\n return false;\n }\n\n const segments = rel.split(sep);\n\n return segments.some((segment) => SKIP_DIRS.has(segment));\n}\n\nexport type { ProxyLogEntry } from '../../shared/lib/proxy.js';\nexport { proxyLogEntryToString } from '../../shared/lib/proxy.js';\nimport { type ProxyLogEntry } from '../../shared/lib/proxy.js';\n\nexport function getViewerPath(): string {\n const filename = fileURLToPath(import.meta.url);\n\n return join(dirname(filename), 'viewer');\n}\n\n/**\n * Calls to Kizen's `/external-integrations/proxy` endpoint wrap the third-party\n * API's status in the response body (`status_code`) and return HTTP 200 even\n * when the upstream call failed. Pull that real status out so the network log\n * can surface it instead of the misleading proxy status.\n */\nfunction extractUpstreamStatus(\n upstreamPath: string,\n headers: Record<string, string>,\n body: Buffer,\n): number | undefined {\n if (!upstreamPath.includes('/external-integrations/proxy')) {\n return undefined;\n }\n\n if (!headers['content-type']?.includes('application/json')) {\n return undefined;\n }\n\n try {\n const parsed = JSON.parse(body.toString('utf8')) as { status_code?: unknown };\n\n return typeof parsed.status_code === 'number' ? parsed.status_code : undefined;\n } catch {\n return undefined;\n }\n}\n\nexport async function fileExists(filePath: string): Promise<boolean> {\n try {\n await access(filePath);\n\n return true;\n } catch {\n return false;\n }\n}\n\nexport function createRequestHandler(\n viewerPath: string,\n createServerLog: (message: string) => void,\n createProxyLog: (entry: ProxyLogEntry) => void,\n credentialsRef: { current: Credentials | null },\n activeProfileRef: { current: string | undefined },\n outputDir: string,\n broadcast: (msg: object) => void,\n onProxyCacheChange: (size: number) => void,\n lastPathRef: { current: string | undefined },\n pluginDir: string,\n cacheEnabled: boolean,\n): (req: IncomingMessage, res: ServerResponse) => void {\n const proxyCache = createProxyCache({ onChange: onProxyCacheChange, enabled: cacheEnabled });\n // Resolve the plugin dir once so every source-path check compares against\n // the canonical path (handles macOS /var → /private/var, pnpm workspace\n // symlinks, etc.). Done synchronously at handler creation since pluginDir\n // is process.cwd() and must already exist.\n const realPluginDir = realpathSync(pluginDir);\n\n return (req, res) => {\n void (async () => {\n const url = req.url ?? '/';\n\n try {\n // Even though we bind to 127.0.0.1, a browser tab on\n // a malicious origin can point its DNS at our loopback address. The\n // Host header still carries the original hostname, so rejecting\n // anything that isn't localhost/127.0.0.1 closes the hole.\n if (!isLocalHost(req.headers.host)) {\n res.writeHead(403, { 'Content-Type': 'application/json; charset=utf-8' });\n res.end(JSON.stringify({ error: 'Forbidden' }));\n\n return;\n }\n\n const isWrite = req.method === 'POST' || req.method === 'PATCH' || req.method === 'DELETE';\n\n if (isWrite && !isLocalOrigin(req.headers.origin)) {\n res.writeHead(403, { 'Content-Type': 'application/json; charset=utf-8' });\n res.end(JSON.stringify({ error: 'Forbidden' }));\n\n return;\n }\n\n createServerLog(`Received request: ${url}`);\n\n if (url === '/api/credentials') {\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });\n\n res.end(\n JSON.stringify({\n credentials: credentialsRef.current ?? null,\n activeProfile: activeProfileRef.current ?? null,\n }),\n );\n\n return;\n }\n\n if (url === '/api/credential-profiles' && req.method === 'GET') {\n const profiles = await listCredentialProfiles();\n\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });\n\n res.end(JSON.stringify({ profiles, active: activeProfileRef.current }));\n\n return;\n }\n\n if (url === '/api/credentials/switch' && req.method === 'POST') {\n const chunks: Buffer[] = [];\n\n for await (const chunk of req) {\n chunks.push(chunk as Buffer);\n }\n\n const body = JSON.parse(Buffer.concat(chunks).toString('utf-8') || '{}') as {\n profile?: string;\n };\n const profileName = body.profile;\n const creds =\n profileName === undefined || profileName === ''\n ? await loadGlobalCredentials()\n : await loadCredentialProfile(profileName);\n\n if (creds !== null) {\n credentialsRef.current = creds;\n\n activeProfileRef.current = profileName ?? undefined;\n\n const active = activeProfileRef.current;\n const currentConfig = await loadConfig(outputDir);\n\n await saveConfig(outputDir, {\n ...currentConfig,\n credentialMode: 'global',\n ...(active !== undefined && { activeCredentialProfile: active }),\n });\n\n broadcast({\n type: 'credentials-updated',\n credentials: creds,\n activeProfile: activeProfileRef.current ?? null,\n });\n }\n\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });\n\n res.end(JSON.stringify({ ok: creds !== null }));\n\n return;\n }\n\n if (url === '/api/bundle') {\n const bundlePath = join(process.cwd(), '.kizenapp', 'bundle.json');\n\n try {\n const content = await readFile(bundlePath, 'utf-8');\n\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });\n\n res.end(content);\n } catch {\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });\n\n res.end('{}');\n }\n\n return;\n }\n\n if (url === '/api/last-path' && req.method === 'POST') {\n const chunks: Buffer[] = [];\n\n for await (const chunk of req) {\n chunks.push(chunk as Buffer);\n }\n\n const body = JSON.parse(Buffer.concat(chunks).toString('utf-8') || '{}') as {\n path?: string;\n };\n\n if (typeof body.path === 'string') {\n lastPathRef.current = body.path;\n\n const currentConfig = await loadConfig(outputDir);\n\n await saveConfig(outputDir, { ...currentConfig, lastPath: body.path });\n }\n\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });\n\n res.end('{\"ok\":true}');\n\n return;\n }\n\n if (url === '/api/encryption-target' && req.method === 'GET') {\n const config = await loadConfig(outputDir);\n // Default to 'prod' when unset. Anything that isn't an explicit 'dev'\n // (incl. a legacy 'auto' from before the heuristic was dropped) maps to\n // 'prod', so the API only ever returns a concrete target.\n const target = config.encryptionTarget === 'dev' ? 'dev' : 'prod';\n\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });\n res.end(JSON.stringify({ target }));\n\n return;\n }\n\n if (url === '/api/encryption-target' && req.method === 'POST') {\n const chunks: Buffer[] = [];\n\n for await (const chunk of req) {\n chunks.push(chunk as Buffer);\n }\n\n const parsed: unknown = JSON.parse(Buffer.concat(chunks).toString('utf-8') || '{}');\n const body: { target?: string } =\n parsed !== null && typeof parsed === 'object' ? (parsed as { target?: string }) : {};\n\n if (body.target !== 'dev' && body.target !== 'prod') {\n res.writeHead(400, { 'Content-Type': 'application/json; charset=utf-8' });\n res.end(JSON.stringify({ error: \"target must be one of: 'dev', 'prod'\" }));\n\n return;\n }\n\n const currentConfig = await loadConfig(outputDir);\n\n // body.target is narrowed to 'dev' | 'prod' by the guard above.\n await saveConfig(outputDir, { ...currentConfig, encryptionTarget: body.target });\n\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });\n res.end('{\"ok\":true}');\n\n return;\n }\n\n if (url === '/api/execute-step' && req.method === 'POST') {\n const chunks: Buffer[] = [];\n\n for await (const chunk of req) {\n chunks.push(chunk as Buffer);\n }\n\n const body = JSON.parse(Buffer.concat(chunks).toString('utf-8') || '{}') as {\n script?: string;\n scriptRuntime?: string;\n inputs?: Record<string, unknown>;\n secrets?: Record<string, string>;\n timeout?: number;\n };\n\n if (typeof body.script !== 'string') {\n res.writeHead(400, { 'Content-Type': 'application/json; charset=utf-8' });\n\n res.end(JSON.stringify({ error: 'Missing required field: script' }));\n\n return;\n }\n\n const stepParams: Parameters<typeof executePythonStep>[0] = {\n script: body.script,\n // Matches the production Kizen code-runner service's default runtime\n // (\"python-3-13\"). Only used when a caller omits a runtime; real\n // plugin steps send their own \"python-3-NN\" value.\n scriptRuntime: body.scriptRuntime ?? 'python-3-13',\n inputs: normalizeStepInputs(body.inputs),\n secrets: body.secrets ?? {},\n onInstallProgress: (event) => {\n if (event.kind === 'start') {\n broadcast({ type: 'venv-install-start' });\n } else if (event.kind === 'log') {\n broadcast({\n type: 'venv-install-log',\n line: event.line,\n stream: event.stream,\n });\n } else if (event.kind === 'complete') {\n broadcast({ type: 'venv-install-complete' });\n } else {\n broadcast({ type: 'venv-install-error', message: event.message });\n }\n },\n };\n\n if (typeof body.timeout === 'number' && body.timeout > 0) {\n // Cap at 5 minutes so a runaway request can't hang the Python\n // runner indefinitely. Default (30s) still applies if omitted.\n stepParams.timeout = Math.min(body.timeout, 5 * 60 * 1000);\n }\n\n const result = await executePythonStep(stepParams);\n\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });\n\n res.end(JSON.stringify(result));\n\n return;\n }\n\n if (url === '/api/proxy-cache/clear') {\n proxyCache.clear();\n\n createProxyLog({ kind: 'info', message: 'Proxy cache cleared' });\n\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });\n\n res.end('{\"ok\":true}');\n\n return;\n }\n\n if (url === '/api/local/encrypt' && req.method === 'POST') {\n const chunks: Buffer[] = [];\n\n for await (const chunk of req) {\n chunks.push(chunk as Buffer);\n }\n\n const body = JSON.parse(Buffer.concat(chunks).toString('utf-8') || '{}') as {\n publicKeyPem?: string;\n value?: string;\n };\n\n if (typeof body.publicKeyPem !== 'string' || typeof body.value !== 'string') {\n res.writeHead(400, { 'Content-Type': 'application/json; charset=utf-8' });\n res.end(JSON.stringify({ error: 'Missing required fields: publicKeyPem, value' }));\n\n return;\n }\n\n try {\n const envelope = encrypt(body.value, body.publicKeyPem);\n const serialized = serializeEnvelope(envelope);\n\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });\n res.end(JSON.stringify(serialized));\n } catch (err) {\n res.writeHead(400, { 'Content-Type': 'application/json; charset=utf-8' });\n res.end(JSON.stringify({ error: (err as Error).message }));\n }\n\n return;\n }\n\n if (url === '/api/local/validate' && req.method === 'POST') {\n const chunks: Buffer[] = [];\n\n for await (const chunk of req) {\n chunks.push(chunk as Buffer);\n }\n\n const body = JSON.parse(Buffer.concat(chunks).toString('utf-8') || '{}') as {\n value?: string;\n };\n\n if (typeof body.value !== 'string') {\n res.writeHead(400, { 'Content-Type': 'application/json; charset=utf-8' });\n res.end(JSON.stringify({ error: 'Missing required field: value' }));\n\n return;\n }\n\n interface CheckResult {\n label: string;\n expected: string;\n actual: string;\n pass: boolean;\n }\n\n let envelope: ReturnType<typeof deserializeEnvelope> | undefined;\n let parseError: string | undefined;\n\n try {\n envelope = deserializeEnvelope(body.value);\n } catch (err) {\n parseError = (err as Error).message;\n }\n\n if (parseError !== undefined || envelope === undefined) {\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });\n res.end(JSON.stringify({ valid: false, checks: [], error: parseError }));\n\n return;\n }\n\n const bufLen = (b64: string): number => Buffer.from(b64, 'base64').length;\n\n const checks: CheckResult[] = [\n {\n label: 'Version',\n expected: String(CRYPTO_VERSION),\n actual: String(envelope.v),\n pass: (envelope.v as number) === CRYPTO_VERSION,\n },\n {\n label: 'Algorithm',\n expected: CRYPTO_ALG,\n actual: envelope.alg,\n pass: (envelope.alg as string) === CRYPTO_ALG,\n },\n {\n label: 'Wrapped key',\n expected: '384 bytes (RSA-3072)',\n actual: `${String(bufLen(envelope.k))} bytes`,\n pass: bufLen(envelope.k) === 384,\n },\n {\n label: 'IV',\n expected: '12 bytes',\n actual: `${String(bufLen(envelope.iv))} bytes`,\n pass: bufLen(envelope.iv) === 12,\n },\n {\n label: 'Auth tag',\n expected: '16 bytes',\n actual: `${String(bufLen(envelope.tag))} bytes`,\n pass: bufLen(envelope.tag) === 16,\n },\n {\n label: 'Ciphertext',\n expected: '≥ 1 byte',\n actual: `${String(bufLen(envelope.ct))} bytes`,\n pass: bufLen(envelope.ct) >= 1,\n },\n ];\n\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });\n res.end(JSON.stringify({ valid: checks.every((c) => c.pass), checks }));\n\n return;\n }\n\n if (url.startsWith('/api/wizard')) {\n // The viewer sends the saved dev/prod target here; we map it to a known\n // host. A duplicated header arrives as an array — take the first value.\n // Default to 'prod' when absent/invalid: prod is the product-wide\n // default (almost every plugin ships to production), and only an\n // explicit 'dev' routes to the dev keys.\n const rawTarget = req.headers['x-encryption-target'];\n const targetHeader = Array.isArray(rawTarget) ? rawTarget[0] : rawTarget;\n const target: 'dev' | 'prod' = targetHeader === 'dev' ? 'dev' : 'prod';\n const wizardBase = resolveWizardBase(target);\n\n // The credential headers below are forwarded to wizardBase — refuse to\n // forward them anywhere but a known host.\n if (!isAllowedWizardTarget(wizardBase)) {\n res.writeHead(500, { 'Content-Type': 'application/json; charset=utf-8' });\n res.end(\n JSON.stringify({\n error: `Encryption API host is not allowed: ${wizardBase}`,\n }),\n );\n\n return;\n }\n\n const upstreamPath = url.slice('/api/wizard'.length) || '/';\n const upstreamUrl = `${wizardBase}${upstreamPath}`;\n const method = req.method ?? 'GET';\n\n const chunks: Buffer[] = [];\n\n for await (const chunk of req) {\n chunks.push(chunk as Buffer);\n }\n\n const {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n host: _wizardHost,\n // Internal control header — don't forward it upstream.\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n 'x-encryption-target': _encTarget,\n ...wizardForwardHeaders\n } = req.headers;\n\n const body = chunks.length > 0 ? Buffer.concat(chunks) : undefined;\n const resolvedBody = body && body.length > 0 ? body : undefined;\n\n let upstream: Response;\n\n try {\n upstream = await fetch(upstreamUrl, {\n method,\n headers: wizardForwardHeaders as Record<string, string>,\n ...(resolvedBody !== undefined && { body: resolvedBody }),\n });\n } catch (err) {\n const message =\n (err as NodeJS.ErrnoException).code === 'ECONNREFUSED'\n ? `plugin-wizard is not running at ${wizardBase}`\n : `Failed to reach plugin-wizard: ${(err as Error).message}`;\n\n res.writeHead(503, { 'Content-Type': 'application/json; charset=utf-8' });\n res.end(JSON.stringify({ error: message }));\n\n return;\n }\n\n const wizardResponseHeaders = sanitizeUpstreamHeaders(\n Object.fromEntries(upstream.headers),\n );\n const wizardBody = await upstream.arrayBuffer();\n\n res.writeHead(upstream.status, wizardResponseHeaders);\n res.end(Buffer.from(wizardBody));\n\n return;\n }\n\n if (url.startsWith('/api/proxy')) {\n const proxyTarget = req.headers['x-proxy-target'];\n\n if (typeof proxyTarget !== 'string') {\n res.writeHead(400);\n\n res.end('Missing x-proxy-target header');\n\n return;\n }\n\n if (!isAllowedProxyTarget(proxyTarget)) {\n res.writeHead(400);\n\n res.end('Invalid proxy target');\n\n return;\n }\n\n const upstreamPath = url.slice('/api/proxy'.length) || '/';\n const upstreamUrl = `${proxyTarget}${upstreamPath}`;\n const method = req.method ?? 'GET';\n\n const chunks: Buffer[] = [];\n\n for await (const chunk of req) {\n chunks.push(chunk as Buffer);\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const { host, 'x-proxy-target': _drop, ...forwardHeaders } = req.headers;\n\n if (method === 'GET') {\n const cacheKey = `GET::${upstreamUrl}`;\n const { response: cached, fromCache } = await proxyCache.get(cacheKey, () =>\n fetch(upstreamUrl, {\n method: 'GET',\n headers: forwardHeaders as Record<string, string>,\n }),\n );\n\n createProxyLog({\n kind: 'request',\n method: 'GET',\n status: cached.status,\n upstreamStatus: extractUpstreamStatus(upstreamPath, cached.headers, cached.body),\n fromCache,\n url: upstreamPath,\n });\n\n res.writeHead(cached.status, cached.headers);\n\n res.end(cached.body);\n\n return;\n }\n\n const body = chunks.length > 0 ? Buffer.concat(chunks) : undefined;\n const resolvedBody = body && body.length > 0 ? body : undefined;\n const upstream = await fetch(upstreamUrl, {\n method,\n headers: forwardHeaders as Record<string, string>,\n ...(resolvedBody !== undefined && { body: resolvedBody }),\n });\n const responseHeaders = sanitizeUpstreamHeaders(Object.fromEntries(upstream.headers));\n const responseBody = await readBodyWithLimit(upstream, MAX_PROXY_BYTES);\n\n createProxyLog({\n kind: 'request',\n method,\n status: upstream.status,\n upstreamStatus: extractUpstreamStatus(upstreamPath, responseHeaders, responseBody),\n fromCache: false,\n url: upstreamPath,\n });\n\n res.writeHead(upstream.status, responseHeaders);\n\n res.end(responseBody);\n\n return;\n }\n\n if (url.startsWith('/api/source/tree') && req.method === 'GET') {\n const query = new URL(url, 'http://localhost').searchParams;\n const relParam = query.get('path') ?? '';\n const abs = await resolveSafePath(realPluginDir, relParam);\n\n if (abs === null) {\n res.writeHead(403, { 'Content-Type': 'application/json; charset=utf-8' });\n res.end(JSON.stringify({ error: 'Invalid path' }));\n\n return;\n }\n\n if (isInsideSkippedDir(realPluginDir, abs)) {\n res.writeHead(403, { 'Content-Type': 'application/json; charset=utf-8' });\n res.end(JSON.stringify({ error: 'Path is excluded' }));\n\n return;\n }\n\n try {\n const dirEntries = await readdir(abs, { withFileTypes: true });\n const entries = await Promise.all(\n dirEntries\n .filter((entry) => {\n if (entry.isDirectory()) {\n return !SKIP_DIRS.has(entry.name);\n }\n\n if (entry.isFile()) {\n return !SKIP_FILES.has(entry.name);\n }\n\n return false;\n })\n .map(async (entry) => {\n const kind = entry.isDirectory() ? ('dir' as const) : ('file' as const);\n const result: { name: string; kind: 'dir' | 'file'; size?: number } = {\n name: entry.name,\n kind,\n };\n\n if (kind === 'file') {\n try {\n const stats = await stat(join(abs, entry.name));\n\n result.size = stats.size;\n } catch {\n // Ignore stat failures — file may have been deleted mid-scan.\n }\n }\n\n return result;\n }),\n );\n\n entries.sort((a, b) => {\n if (a.kind !== b.kind) {\n return a.kind === 'dir' ? -1 : 1;\n }\n\n return a.name.localeCompare(b.name);\n });\n\n const normalizedPath = abs === realPluginDir ? '' : abs.slice(realPluginDir.length + 1);\n\n res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });\n res.end(JSON.stringify({ path: normalizedPath, entries }));\n } catch (err) {\n const detail = err instanceof Error ? err.message : String(err);\n\n createServerLog(`source/tree failed (${relParam}): ${detail}`);\n\n res.writeHead(404, { 'Content-Type': 'application/json; charset=utf-8' });\n res.end(JSON.stringify({ error: 'Not found' }));\n }\n\n return;\n }\n\n if (url.startsWith('/api/source/file') && req.method === 'GET') {\n const query = new URL(url, 'http://localhost').searchParams;\n const relParam = query.get('path') ?? '';\n\n if (relParam === '') {\n res.writeHead(400, { 'Content-Type': 'application/json; charset=utf-8' });\n res.end(JSON.stringify({ error: 'Missing path' }));\n\n return;\n }\n\n const abs = await resolveSafePath(realPluginDir, relParam);\n\n if (abs === null) {\n res.writeHead(403, { 'Content-Type': 'application/json; charset=utf-8' });\n res.end(JSON.stringify({ error: 'Invalid path' }));\n\n return;\n }\n\n if (isInsideSkippedDir(realPluginDir, abs)) {\n res.writeHead(403, { 'Content-Type': 'application/json; charset=utf-8' });\n res.end(JSON.stringify({ error: 'Path is excluded' }));\n\n return;\n }\n\n try {\n const stats = await stat(abs);\n\n if (!stats.isFile()) {\n res.writeHead(400, { 'Content-Type': 'application/json; charset=utf-8' });\n res.end(JSON.stringify({ error: 'Not a file' }));\n\n return;\n }\n\n if (stats.size > SOURCE_FILE_MAX_BYTES) {\n res.writeHead(413, { 'Content-Type': 'application/json; charset=utf-8' });\n res.end(JSON.stringify({ error: 'File too large', size: stats.size }));\n\n return;\n }\n\n const ext = extname(abs).toLowerCase();\n const explicitMime = MIME_TYPES[ext];\n const isKnownText = TEXT_EXTENSIONS.has(ext);\n const contentType =\n explicitMime ??\n (isKnownText ? 'text/plain; charset=utf-8' : 'application/octet-stream');\n\n res.writeHead(200, {\n 'Content-Type': contentType,\n 'Content-Length': String(stats.size),\n });\n createReadStream(abs).pipe(res);\n } catch (err) {\n const detail = err instanceof Error ? err.message : String(err);\n\n createServerLog(`source/file failed (${relParam}): ${detail}`);\n\n res.writeHead(404, { 'Content-Type': 'application/json; charset=utf-8' });\n res.end(JSON.stringify({ error: 'Not found' }));\n }\n\n return;\n }\n\n const rawPath = url === '/' ? '/index.html' : url;\n const filePath = join(viewerPath, rawPath);\n const resolvedPath = (await fileExists(filePath))\n ? filePath\n : join(viewerPath, 'index.html');\n const ext = extname(resolvedPath);\n const mimeType = MIME_TYPES[ext] ?? 'application/octet-stream';\n\n res.writeHead(200, { 'Content-Type': mimeType });\n\n createReadStream(resolvedPath).pipe(res);\n } catch (err) {\n if (url.startsWith('/api/proxy')) {\n const upstreamPath = url.slice('/api/proxy'.length) || '/';\n const method = req.method ?? 'GET';\n\n if (err instanceof ProxyResponseTooLargeError) {\n createProxyLog({\n kind: 'info',\n message: `${method} ${upstreamPath} → 502 (response exceeded ${String(err.limit)} bytes)`,\n });\n } else {\n createProxyLog({\n kind: 'request',\n method,\n status: 502,\n fromCache: false,\n url: upstreamPath,\n });\n }\n } else {\n createProxyLog({\n kind: 'info',\n message: `Error handling ${url}: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n\n if (!res.headersSent) {\n res.writeHead(502);\n\n res.end('Bad Gateway');\n }\n }\n })();\n };\n}\n","export interface CachedResponse {\n status: number;\n headers: Record<string, string>;\n body: Buffer;\n}\n\n// Headers we refuse to pass through from upstream to the browser.\n// - set-cookie: would set Kizen cookies on the localhost origin.\n// - access-control-*: would let upstream relax CORS on our responses.\n// - strict-transport-security: shouldn't govern localhost.\n// - content-security-policy(-report-only), x-frame-options: upstream policy\n// doesn't apply to the local viewer and can conflict with our own CSP.\n// content-encoding / content-length are dropped because fetch auto-decompresses\n// the body; the original sizes/encoding no longer match what we forward.\nconst STRIPPED_RESPONSE_HEADERS = new Set([\n 'set-cookie',\n 'strict-transport-security',\n 'content-security-policy',\n 'content-security-policy-report-only',\n 'x-frame-options',\n 'content-encoding',\n 'content-length',\n]);\n\nexport function sanitizeUpstreamHeaders(headers: Record<string, string>): Record<string, string> {\n const filtered: Record<string, string> = {};\n\n for (const [key, value] of Object.entries(headers)) {\n const lower = key.toLowerCase();\n\n if (STRIPPED_RESPONSE_HEADERS.has(lower) || lower.startsWith('access-control-')) {\n continue;\n }\n\n filtered[key] = value;\n }\n\n return filtered;\n}\n\nexport const MAX_PROXY_BYTES = 10 * 1024 * 1024;\n\n// 60s TTL keeps dev-session queries de-duplicated without masking server-side\n// changes for long. 200 entries caps worst-case memory at ~2GB if every entry\n// were maxed out, which it won't be — typical Kizen JSON responses are <100KB.\nconst CACHE_TTL_MS = 60_000;\nconst CACHE_MAX_ENTRIES = 200;\n\nexport class ProxyResponseTooLargeError extends Error {\n readonly bytesRead: number;\n readonly limit: number;\n\n constructor(bytesRead: number, limit: number) {\n super(`Upstream response exceeded ${String(limit)} bytes (read ${String(bytesRead)}).`);\n this.name = 'ProxyResponseTooLargeError';\n this.bytesRead = bytesRead;\n this.limit = limit;\n }\n}\n\nexport async function readBodyWithLimit(response: Response, limit: number): Promise<Buffer> {\n const body = response.body;\n\n if (body === null) {\n return Buffer.alloc(0);\n }\n\n const chunks: Uint8Array[] = [];\n let total = 0;\n\n for await (const chunk of body as AsyncIterable<Uint8Array>) {\n total += chunk.length;\n\n if (total > limit) {\n throw new ProxyResponseTooLargeError(total, limit);\n }\n\n chunks.push(chunk);\n }\n\n return Buffer.concat(chunks);\n}\n\nexport interface ProxyCache {\n get(\n key: string,\n fetcher: () => Promise<Response>,\n ): Promise<{ response: CachedResponse; fromCache: boolean }>;\n clear(): void;\n}\n\nexport interface ProxyCacheOptions {\n onChange?: (size: number) => void;\n // When false, the cache becomes a pass-through: every request hits upstream\n // and nothing is stored. Used by `appbuilder dev --no-cache`.\n enabled?: boolean;\n}\n\ninterface CacheEntry {\n insertedAt: number;\n promise: Promise<CachedResponse>;\n}\n\nasync function toCachedResponse(response: Response): Promise<CachedResponse> {\n const headers = sanitizeUpstreamHeaders(Object.fromEntries(response.headers));\n const body = await readBodyWithLimit(response, MAX_PROXY_BYTES);\n\n return { status: response.status, headers, body };\n}\n\nexport function createProxyCache(options: ProxyCacheOptions = {}): ProxyCache {\n const { onChange, enabled = true } = options;\n\n if (!enabled) {\n return {\n async get(_key, fetcher) {\n const response = await toCachedResponse(await fetcher());\n\n return { response, fromCache: false };\n },\n clear() {\n // Nothing is stored, so there is nothing to clear.\n },\n };\n }\n\n const cache = new Map<string, CacheEntry>();\n const emitChange = (): void => {\n onChange?.(cache.size);\n };\n\n const evict = (key: string): void => {\n if (cache.delete(key)) {\n emitChange();\n }\n };\n\n return {\n get(\n key: string,\n fetcher: () => Promise<Response>,\n ): Promise<{ response: CachedResponse; fromCache: boolean }> {\n const existing = cache.get(key);\n\n if (existing !== undefined) {\n if (Date.now() - existing.insertedAt < CACHE_TTL_MS) {\n return existing.promise.then((response) => ({ response, fromCache: true }));\n }\n\n // Stale — drop and refetch.\n evict(key);\n }\n\n // Map iteration order is insertion order, so the first key is the oldest.\n // Evicting before insert keeps size strictly ≤ CACHE_MAX_ENTRIES.\n if (cache.size >= CACHE_MAX_ENTRIES) {\n const oldest = cache.keys().next().value;\n\n if (oldest !== undefined) {\n evict(oldest);\n }\n }\n\n const pending = fetcher()\n .then(toCachedResponse)\n .catch((error: unknown) => {\n evict(key);\n throw error;\n });\n\n cache.set(key, { insertedAt: Date.now(), promise: pending });\n\n emitChange();\n\n return pending.then((response) => {\n // Only 2xx responses stay cached; everything else is served once and\n // evicted so the next request re-fetches.\n if (response.status < 200 || response.status >= 300) {\n evict(key);\n }\n\n return { response, fromCache: false };\n });\n },\n\n clear(): void {\n cache.clear();\n\n emitChange();\n },\n };\n}\n","/** Maximum number of log entries retained per log channel. */\nexport const LOG_LIMIT = 50;\n\n/** Number of log lines visible in each TUI log panel. */\nexport const LOG_DISPLAY = 8;\n\n/** Debounce delay for file-watcher triggered rebuilds (ms). */\nexport const FILE_WATCH_DEBOUNCE_MS = 150;\n\nexport const MIME_TYPES: Readonly<Record<string, string>> = {\n '.html': 'text/html; charset=utf-8',\n '.js': 'application/javascript; charset=utf-8',\n '.mjs': 'application/javascript; charset=utf-8',\n '.css': 'text/css; charset=utf-8',\n '.png': 'image/png',\n '.jpg': 'image/jpeg',\n '.svg': 'image/svg+xml',\n '.ico': 'image/x-icon',\n '.json': 'application/json; charset=utf-8',\n '.woff': 'font/woff',\n '.woff2': 'font/woff2',\n '.ttf': 'font/ttf',\n '.map': 'application/json',\n};\n","/**\n * Shared helper for resolving the encryption API (plugin-wizard) base URL.\n * Imported by both the dev server request handler and the `encrypt` CLI command\n * so the host defaults and env-var names live in one place. KZN-16467.\n */\n\nexport const ENCRYPTION_API_DEFAULTS = {\n prod: 'https://plugin-wizard.kizen.com', // deployed prod encryption service\n dev: 'https://plugin-wizard.kizen.dev', // deployed dev encryption service\n localDev: 'http://localhost:9823', // local plugin-wizard (APPBUILDER_LOCAL_DEV)\n} as const;\n\n/**\n * Resolves the base URL for the encryption API (plugin-wizard) public-key\n * endpoint. Precedence for the `dev` target:\n * 1. `PLUGIN_WIZARD_URL` — forces a single host for ALL targets.\n * 2. `PLUGIN_WIZARD_URL_DEV` — explicit dev URL.\n * 3. `APPBUILDER_LOCAL_DEV` — any non-empty value → localhost:9823.\n * 4. Hardcoded default — deployed dev service.\n * Prod follows the same pattern minus step 3.\n */\nexport function resolveWizardBase(target: 'dev' | 'prod'): string {\n const forced = process.env.PLUGIN_WIZARD_URL;\n\n if (forced !== undefined && forced !== '') {\n return forced;\n }\n\n if (target === 'prod') {\n // `||` (not `??`) so an empty-string env var falls back to the default,\n // matching the PLUGIN_WIZARD_URL / *_DEV branches above and below.\n return process.env.PLUGIN_WIZARD_URL_PROD || ENCRYPTION_API_DEFAULTS.prod;\n }\n\n if (process.env.PLUGIN_WIZARD_URL_DEV !== undefined && process.env.PLUGIN_WIZARD_URL_DEV !== '') {\n return process.env.PLUGIN_WIZARD_URL_DEV;\n }\n\n if (process.env.APPBUILDER_LOCAL_DEV !== undefined && process.env.APPBUILDER_LOCAL_DEV !== '') {\n return ENCRYPTION_API_DEFAULTS.localDev;\n }\n\n return ENCRYPTION_API_DEFAULTS.dev;\n}\n","import { spawn } from 'node:child_process';\nimport { writeFile, rm, mkdtemp, access } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { tmpdir } from 'node:os';\nimport requirementsTxt from './python-requirements.txt';\nimport { parseRequirementsFile, resolvePythonBinary } from '../lib/pythonRuntime.js';\nimport {\n type ExecutionResult,\n type HttpRequests,\n type StepInputValue,\n} from '../../shared/lib/execution.js';\nexport type {\n ExecutionResult,\n HttpRequests,\n HttpRequestEntry,\n} from '../../shared/lib/execution.js';\n\nconst WRAPPER_SCRIPT = `\nimport sys, json, os, traceback\n\n# --- Inputs proxy (attribute access) ---\nclass _InputsProxy:\n def __init__(self, data):\n object.__setattr__(self, '_data', data)\n\n def __getattr__(self, name):\n if name.startswith('_'):\n raise AttributeError(name)\n return self._data.get(name)\n\n def __repr__(self):\n return repr(self._data)\n\n def __str__(self):\n return str(self._data)\n\n def __bool__(self):\n return bool(self._data)\n\ninputs = _InputsProxy(json.loads(os.environ.get('__KIZEN_INPUTS__', '{}')))\n\n# --- Secrets ---\nsecrets = json.loads(os.environ.get('__KIZEN_SECRETS__', '{}'))\n\n# --- Outputs proxy ---\nclass _OutputsProxy:\n def __init__(self):\n object.__setattr__(self, '_values', {})\n object.__setattr__(self, '_logs', [])\n\n def __setattr__(self, name, value):\n if name.startswith('_'):\n object.__setattr__(self, name, value)\n else:\n self._values[name] = value\n\n def __getattr__(self, name):\n if name.startswith('_'):\n raise AttributeError(name)\n return self._values.get(name)\n\n def log(self, message):\n self._logs.append(str(message))\n\noutputs = _OutputsProxy()\n\n# --- HTTP request capture (requests library only) ---\n_kizen_http_requests = []\n\ndef _kizen_install_http_capture():\n try:\n import requests\n except Exception:\n return\n import time, datetime\n\n _original_send = requests.Session.send\n\n def _kizen_send(self, request, **kwargs):\n submitted_at = datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%d %H:%M:%S')\n start = time.time()\n error_type = None\n response = None\n try:\n response = _original_send(self, request, **kwargs)\n return response\n except Exception as exc:\n error_type = type(exc).__name__\n raise\n finally:\n body = request.body\n if isinstance(body, bytes):\n try:\n body = body.decode('utf-8')\n except Exception:\n body = '<binary>'\n elif body is None:\n body = ''\n\n status = 0\n resp_headers = {}\n resp_body = ''\n if response is not None:\n status = response.status_code\n resp_headers = dict(response.headers)\n if kwargs.get('stream'):\n resp_body = '<streamed>'\n else:\n try:\n resp_body = response.text\n except Exception:\n resp_body = '<unreadable>'\n\n _kizen_http_requests.append({\n 'method': request.method or '',\n 'url': request.url or '',\n 'headers': dict(request.headers or {}),\n 'body': body,\n 'requestSubmittedAt': submitted_at,\n 'session': True,\n 'responseStatusCode': status,\n 'responseHeaders': resp_headers,\n 'responseBody': resp_body,\n 'requestErrorType': error_type,\n 'duration': time.time() - start,\n })\n\n requests.Session.send = _kizen_send\n\n_kizen_install_http_capture()\n\ndef _kizen_http_summary():\n if not _kizen_http_requests:\n return None\n return {\n 'count': len(_kizen_http_requests),\n 'notLogged': 0,\n 'requests': _kizen_http_requests,\n }\n\n# --- Execute user script ---\ntry:\n exec(open(os.environ['__KIZEN_SCRIPT_PATH__'], encoding='utf-8').read())\n result = {\n 'success': True,\n 'outputValues': outputs._values,\n 'logs': outputs._logs,\n 'error': None,\n 'httpRequests': _kizen_http_summary(),\n }\nexcept Exception:\n # Build a clean traceback that hides the wrapper internals.\n # Keep only frames from the user script (shown as File \"<string>\")\n # and re-label them with \"script.py\" for clarity.\n exc_type, exc_value, exc_tb = sys.exc_info()\n entries = traceback.extract_tb(exc_tb)\n user_entries = [e for e in entries if e.filename != __file__]\n for e in user_entries:\n if e.filename == '<string>':\n e.filename = 'script.py'\n lines = ['Traceback (most recent call last):\\\\n']\n lines += traceback.format_list(user_entries)\n lines += traceback.format_exception_only(exc_type, exc_value)\n result = {\n 'success': False,\n 'outputValues': outputs._values,\n 'logs': outputs._logs,\n 'error': ''.join(lines),\n 'httpRequests': _kizen_http_summary(),\n }\n\n# Write results between markers so we can extract them reliably\n# even if the user script wrote to stdout\nsys.stdout.write('\\\\n__KIZEN_RESULT_START__\\\\n')\nsys.stdout.write(json.dumps(result, ensure_ascii=False))\nsys.stdout.write('\\\\n__KIZEN_RESULT_END__\\\\n')\nsys.stdout.flush()\n`.trim();\n\nconst DEFAULT_TIMEOUT = 30_000;\n\nexport type VenvInstallEvent =\n | { kind: 'start' }\n | { kind: 'log'; line: string; stream: 'stdout' | 'stderr' }\n | { kind: 'complete' }\n | { kind: 'error'; message: string };\n\nexport type VenvInstallListener = (event: VenvInstallEvent) => void;\n\nexport interface ExecuteStepParams {\n script: string;\n scriptRuntime: string;\n inputs: Record<string, StepInputValue>;\n secrets: Record<string, string>;\n timeout?: number;\n onInstallProgress?: VenvInstallListener;\n}\n\nconst VENV_DIR = join(process.cwd(), '.kizenapp', 'venv');\n\n// The production Kizen code-runner service only ships python-3-12 and\n// python-3-13 runtime images. Reject any other runtime locally so a bad or\n// unsupported \"runtime\" in a step's config.json fails fast\nconst SUPPORTED_RUNTIMES = ['python-3-12', 'python-3-13'] as const;\n\nfunction isSupportedRuntime(runtime: string): boolean {\n return (SUPPORTED_RUNTIMES as readonly string[]).includes(runtime);\n}\n\n// ./python-requirements.txt is the single source of truth for packages.\n// Keep it in sync with the Python dependency set installed by the production\n// Kizen code-runner service, so local runs match deployed ones.\nconst VENV_PACKAGES = parseRequirementsFile(requirementsTxt);\n\nif (VENV_PACKAGES.length === 0) {\n throw new Error('python-requirements.txt bundled no packages — check the build output');\n}\n\nlet venvReady: Promise<string> | null = null;\n\n// The bundled requirements (psycopg 3.3 in particular) require Python >= 3.10,\n// matching the remote code-runner which only ships 3.12 / 3.13 images. A venv\n// built on an older interpreter fails `pip install` with a cryptic\n// \"No matching distribution found for psycopg[binary]<4.0,>=3.3\".\nconst MIN_PYTHON: readonly [number, number] = [3, 10];\n\nfunction meetsMinimum([major, minor]: [number, number]): boolean {\n return major > MIN_PYTHON[0] || (major === MIN_PYTHON[0] && minor >= MIN_PYTHON[1]);\n}\n\nfunction formatVersion(version: readonly [number, number]): string {\n return `${String(version[0])}.${String(version[1])}`;\n}\n\n// Probe an interpreter for its (major, minor) version. Resolves null if the\n// binary is missing or can't run, so callers can try the next candidate.\nfunction probePython(bin: string): Promise<[number, number] | null> {\n return new Promise((resolve) => {\n const proc = spawn(bin, ['-c', \"import sys; print('%d.%d' % sys.version_info[:2])\"], {\n stdio: ['ignore', 'pipe', 'ignore'],\n });\n\n let out = '';\n\n proc.stdout.on('data', (chunk: Buffer) => {\n out += chunk.toString('utf-8');\n });\n proc.on('error', () => {\n resolve(null);\n });\n proc.on('close', (code) => {\n const match = /(\\d+)\\.(\\d+)/.exec(out);\n\n if (code !== 0 || !match) {\n resolve(null);\n\n return;\n }\n\n resolve([Number(match[1]), Number(match[2])]);\n });\n });\n}\n\n// Pick a system interpreter new enough to install the bundled requirements.\n// Prefer the exact version the runtime asked for, then fall back to python3.\n// Throws a clear, actionable error when nothing usable is found.\nasync function findSystemPython(runtime: string): Promise<string> {\n const preferred = resolvePythonBinary(runtime);\n const candidates = preferred === 'python3' ? ['python3'] : [preferred, 'python3'];\n const tried: string[] = [];\n\n for (const bin of candidates) {\n const version = await probePython(bin);\n\n if (!version) {\n tried.push(`${bin}: not found`);\n\n continue;\n }\n\n if (meetsMinimum(version)) {\n return bin;\n }\n\n tried.push(`${bin}: ${formatVersion(version)} (too old)`);\n }\n\n throw new Error(\n `No Python >= ${formatVersion(MIN_PYTHON)} found for runtime \"${runtime}\". ` +\n `The local runner needs Python ${formatVersion(MIN_PYTHON)}+ to install the bundled ` +\n `packages (e.g. psycopg 3.3), matching the remote code-runner (3.12 / 3.13). ` +\n `Tried ${tried.join(', ')}. Install Python 3.12 or 3.13 and retry.`,\n );\n}\n\nfunction runCommand(\n bin: string,\n args: string[],\n onLine?: (line: string, stream: 'stdout' | 'stderr') => void,\n): Promise<void> {\n return new Promise((resolve, reject) => {\n const proc = spawn(bin, args, { stdio: ['ignore', 'pipe', 'pipe'] });\n\n const pipeLines = (source: NodeJS.ReadableStream, stream: 'stdout' | 'stderr'): string[] => {\n const captured: string[] = [];\n let buffer = '';\n\n source.on('data', (chunk: Buffer) => {\n buffer += chunk.toString('utf-8');\n\n let idx = buffer.indexOf('\\n');\n\n while (idx >= 0) {\n const line = buffer.slice(0, idx).replace(/\\r$/, '');\n\n buffer = buffer.slice(idx + 1);\n\n captured.push(line);\n onLine?.(line, stream);\n idx = buffer.indexOf('\\n');\n }\n });\n\n source.on('end', () => {\n if (buffer.length > 0) {\n const line = buffer.replace(/\\r$/, '');\n\n captured.push(line);\n onLine?.(line, stream);\n }\n });\n\n return captured;\n };\n\n const stderrCaptured = pipeLines(proc.stderr, 'stderr');\n\n pipeLines(proc.stdout, 'stdout');\n\n proc.on('error', reject);\n proc.on('close', (code) => {\n if (code === 0) {\n resolve();\n } else {\n const tail = stderrCaptured.slice(-10).join('\\n').trim();\n const detail = tail.length > 0 ? `: ${tail}` : '';\n\n reject(new Error(`${bin} exited with code ${String(code)}${detail}`));\n }\n });\n });\n}\n\n// Progress listeners for the in-flight venv build, so every caller awaiting the\n// same build receives its install output. Non-null only while a build is live,\n// so a cached-return call doesn't leak a listener that never fires.\nlet venvInstallListeners: Set<VenvInstallListener> | null = null;\n\nfunction ensureVenv(runtime: string, listener?: VenvInstallListener): Promise<string> {\n if (venvReady) {\n // Build already running or done. Attach to its progress if it's still live.\n if (listener) {\n venvInstallListeners?.add(listener);\n }\n\n return venvReady;\n }\n\n const listeners = new Set<VenvInstallListener>();\n\n if (listener) {\n listeners.add(listener);\n }\n\n venvInstallListeners = listeners;\n\n const emit = (event: VenvInstallEvent): void => {\n for (const l of listeners) {\n l(event);\n }\n };\n\n const venvPython = join(VENV_DIR, 'bin', 'python');\n\n venvReady = (async () => {\n try {\n // Reuse an existing venv only when its interpreter is new enough for the\n // bundled requirements; otherwise rebuild it. A stale venv (e.g. Python\n // 3.9) would otherwise fail `pip install` every time with a cryptic\n // \"No matching distribution\" error for psycopg 3.3.\n let reusable = false;\n\n try {\n await access(venvPython);\n\n const existing = await probePython(venvPython);\n\n reusable = existing !== null && meetsMinimum(existing);\n } catch {\n reusable = false;\n }\n\n if (!reusable) {\n // Clear any stale/half-built venv before recreating it. Best-effort:\n // rm of a missing dir is a no-op with force.\n await rm(VENV_DIR, { recursive: true, force: true }).catch(() => {\n /* ignore */\n });\n\n const systemPython = await findSystemPython(runtime);\n\n await runCommand(systemPython, ['-m', 'venv', VENV_DIR]);\n }\n\n emit({ kind: 'start' });\n\n await runCommand(\n venvPython,\n ['-m', 'pip', 'install', '--disable-pip-version-check', ...VENV_PACKAGES],\n (line, stream) => {\n emit({ kind: 'log', line, stream });\n },\n );\n\n emit({ kind: 'complete' });\n\n return venvPython;\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n\n emit({ kind: 'error', message });\n\n // Reset so the next call retries rather than returning the cached\n // rejection forever. Also nuke the venv dir: a half-built venv (a failed\n // `python -m venv` or an interpreter that's too old) would confuse the\n // reuse check on the next attempt. rm is best-effort — we rebuild either\n // way.\n venvReady = null;\n\n await rm(VENV_DIR, { recursive: true, force: true }).catch(() => {\n /* ignore */\n });\n\n throw err;\n } finally {\n venvInstallListeners = null;\n }\n })();\n\n return venvReady;\n}\n\nfunction parseResult(stdout: string): {\n userStdout: string;\n result: {\n success: boolean;\n outputValues: Record<string, unknown>;\n logs: string[];\n error: string | null;\n httpRequests: HttpRequests | null;\n } | null;\n} {\n const startMarker = '__KIZEN_RESULT_START__';\n const endMarker = '__KIZEN_RESULT_END__';\n const startIdx = stdout.indexOf(startMarker);\n const endIdx = stdout.indexOf(endMarker);\n\n if (startIdx === -1 || endIdx === -1) {\n return { userStdout: stdout, result: null };\n }\n\n const userStdout = stdout.slice(0, startIdx).trimEnd();\n const jsonStr = stdout.slice(startIdx + startMarker.length, endIdx).trim();\n\n try {\n const result = JSON.parse(jsonStr) as {\n success: boolean;\n outputValues: Record<string, unknown>;\n logs: string[];\n error: string | null;\n httpRequests: HttpRequests | null;\n };\n\n return { userStdout, result };\n } catch {\n return { userStdout: stdout, result: null };\n }\n}\n\nfunction failedExecutionResult(error: string): ExecutionResult {\n return {\n success: false,\n outputValues: {},\n logs: [],\n stdout: '',\n stderr: '',\n error,\n exitCode: 1,\n durationMs: 0,\n };\n}\n\nexport async function executePythonStep(params: ExecuteStepParams): Promise<ExecutionResult> {\n const timeout = params.timeout ?? DEFAULT_TIMEOUT;\n\n // Fail fast on a runtime the remote code-runner can't run, instead of\n // silently building a venv on whatever interpreter is handy.\n if (!isSupportedRuntime(params.scriptRuntime)) {\n return failedExecutionResult(\n `Unsupported runtime \"${params.scriptRuntime}\". Supported runtimes: ` +\n `${SUPPORTED_RUNTIMES.join(', ')}. Update the step's config.json \"runtime\" field ` +\n `(e.g. \"python 3.13\").`,\n );\n }\n\n const pythonBin = await ensureVenv(params.scriptRuntime, params.onInstallProgress);\n const start = Date.now();\n\n let tmpDir: string | undefined;\n\n try {\n tmpDir = await mkdtemp(join(tmpdir(), 'kizen-step-'));\n\n const wrapperPath = join(tmpDir, 'wrapper.py');\n const scriptPath = join(tmpDir, 'script.py');\n\n await Promise.all([\n writeFile(wrapperPath, WRAPPER_SCRIPT, 'utf-8'),\n writeFile(scriptPath, params.script, 'utf-8'),\n ]);\n\n const env: Record<string, string> = {\n ...(process.env as Record<string, string>),\n __KIZEN_INPUTS__: JSON.stringify(params.inputs),\n __KIZEN_SECRETS__: JSON.stringify(params.secrets),\n __KIZEN_SCRIPT_PATH__: scriptPath,\n };\n\n const { exitCode, stdout, stderr } = await new Promise<{\n exitCode: number;\n stdout: string;\n stderr: string;\n }>((resolve) => {\n const stdoutChunks: Buffer[] = [];\n const stderrChunks: Buffer[] = [];\n let settled = false;\n\n const proc = spawn(pythonBin, [wrapperPath], {\n env,\n cwd: tmpDir,\n stdio: ['ignore', 'pipe', 'pipe'],\n });\n\n const timer = setTimeout(() => {\n proc.kill('SIGKILL');\n }, timeout);\n\n proc.stdout.on('data', (chunk: Buffer) => {\n stdoutChunks.push(chunk);\n });\n\n proc.stderr.on('data', (chunk: Buffer) => {\n stderrChunks.push(chunk);\n });\n\n const finish = (code: number | null): void => {\n if (settled) {\n return;\n }\n\n settled = true;\n clearTimeout(timer);\n resolve({\n exitCode: code ?? 1,\n stdout: Buffer.concat(stdoutChunks).toString('utf-8'),\n stderr: Buffer.concat(stderrChunks).toString('utf-8'),\n });\n };\n\n proc.on('close', finish);\n proc.on('error', (err) => {\n if (settled) {\n return;\n }\n\n settled = true;\n clearTimeout(timer);\n resolve({\n exitCode: 1,\n stdout: '',\n stderr: err.message,\n });\n });\n });\n\n const durationMs = Date.now() - start;\n const { userStdout, result } = parseResult(stdout);\n\n if (result) {\n const base: ExecutionResult = {\n success: result.success,\n outputValues: result.outputValues,\n logs: result.logs,\n stdout: userStdout,\n stderr,\n exitCode,\n durationMs,\n };\n\n if (result.error !== null) {\n base.error = result.error;\n }\n\n if (result.httpRequests) {\n base.httpRequests = result.httpRequests;\n }\n\n return base;\n }\n\n // If we couldn't parse the result, the wrapper itself likely failed\n const base: ExecutionResult = {\n success: false,\n outputValues: {},\n logs: [],\n stdout: userStdout,\n stderr,\n exitCode,\n durationMs,\n };\n\n if (exitCode !== 0) {\n base.error = `Process exited with code ${String(exitCode)}`;\n }\n\n return base;\n } finally {\n if (tmpDir) {\n void rm(tmpDir, { recursive: true, force: true });\n }\n }\n}\n","awslambdaric\nbcrypt\nboto3\nfpdf2\nlxml\nmsgpack\nnumpy\noracledb\nparamiko\npsycopg[binary]>=3.3,<4.0\npyjwt[crypto]\npymysql[rsa,ed25519]\npypdf[full]\npython-dateutil\npytz\nrequests\nsqlalchemy>=2.0,<2.1\ntzdata\n","export function parseRequirementsFile(content: string): string[] {\n return content\n .split('\\n')\n .map((line) => line.trim().replace(/\\s+#.*$/, ''))\n .filter((line) => line.length > 0 && !line.startsWith('#'));\n}\n\nexport function resolvePythonBinary(runtime: string): string {\n const match = /^python-(\\d+)[.-](\\d+)$/.exec(runtime);\n const major = match?.[1];\n const minor = match?.[2];\n\n if (major !== undefined && minor !== undefined) {\n return `python${major}.${minor}`;\n }\n\n return 'python3';\n}\n","export interface HttpRequestEntry {\n method: string;\n url: string;\n headers: Record<string, string>;\n body: string;\n requestSubmittedAt: string;\n session: boolean;\n responseStatusCode: number;\n responseHeaders: Record<string, string>;\n responseBody: string;\n requestErrorType: string | null;\n duration: number;\n}\n\nexport interface HttpRequests {\n count: number;\n notLogged: number;\n requests: HttpRequestEntry[];\n}\n\nexport interface ExecutionResult {\n success: boolean;\n outputValues: Record<string, unknown>;\n logs: string[];\n stdout: string;\n stderr: string;\n error?: string;\n exitCode: number;\n durationMs: number;\n httpRequests?: HttpRequests;\n}\n\nexport type StepInputValue = string | null;\n\nexport function toStepInputValue(raw: string | null | undefined): StepInputValue {\n return raw === undefined || raw === null || raw.trim() === '' ? null : raw;\n}\n\nexport function buildStepInputs(\n names: string[],\n rawValues: Record<string, string>,\n): Record<string, StepInputValue> {\n return Object.fromEntries(names.map((name) => [name, toStepInputValue(rawValues[name])]));\n}\n\nfunction coerceStepInputValue(value: unknown): StepInputValue {\n if (value === null || value === undefined) {\n return null;\n }\n\n if (typeof value === 'string') {\n return toStepInputValue(value);\n }\n\n if (typeof value === 'number' || typeof value === 'boolean' || typeof value === 'bigint') {\n return String(value);\n }\n\n if (typeof value === 'function' || typeof value === 'symbol') {\n return null;\n }\n\n return JSON.stringify(value);\n}\n\nexport function normalizeStepInputs(\n inputs: Record<string, unknown> | undefined,\n): Record<string, StepInputValue> {\n if (!inputs) {\n return {};\n }\n\n return Object.fromEntries(\n Object.entries(inputs).map(([name, value]) => [name, coerceStepInputValue(value)]),\n );\n}\n","export const TEXT_EXTENSIONS = new Set([\n '.ts',\n '.tsx',\n '.js',\n '.jsx',\n '.mjs',\n '.cjs',\n '.json',\n '.md',\n '.mdx',\n '.yml',\n '.yaml',\n '.toml',\n '.css',\n '.scss',\n '.html',\n '.htm',\n '.xml',\n '.svg',\n '.txt',\n '.sh',\n '.py',\n '.env',\n '.gitignore',\n '.prettierrc',\n '.eslintrc',\n]);\n","export type ProxyLogEntry =\n | {\n kind: 'request';\n method: string;\n status: number;\n // For calls to Kizen's `/external-integrations/proxy` endpoint, the\n // third-party API's status is carried in the response body (`status_code`)\n // rather than the HTTP status. `status` is the proxy status; this is the\n // upstream one. Undefined for non-proxy calls.\n upstreamStatus?: number | undefined;\n fromCache: boolean;\n url: string;\n }\n | { kind: 'info'; message: string };\n\nexport function proxyLogEntryToString(entry: ProxyLogEntry): string {\n if (entry.kind === 'info') {\n return entry.message;\n }\n\n const cache = entry.fromCache ? ' [cache]' : '';\n const upstream =\n entry.upstreamStatus !== undefined ? ` (upstream ${String(entry.upstreamStatus)})` : '';\n\n return `${entry.method} ${entry.url} → ${String(entry.status)}${upstream}${cache}`;\n}\n","import { launch } from 'chrome-launcher';\nimport type { LaunchedChrome } from 'chrome-launcher';\nimport { createRequire } from 'node:module';\nimport { mkdirSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nconst CDP = createRequire(import.meta.url)('chrome-remote-interface') as (opts: {\n port: number;\n}) => Promise<CDPClient>;\n\ninterface CDPHeader {\n name: string;\n value: string;\n}\n\ninterface CDPFetchPausedEvent {\n requestId: string;\n request: { url: string };\n responseHeaders?: CDPHeader[];\n responseStatusCode?: number;\n}\n\ninterface CDPClient {\n Fetch: {\n enable: (opts: { patterns: { urlPattern: string; requestStage: string }[] }) => Promise<void>;\n getResponseBody: (opts: {\n requestId: string;\n }) => Promise<{ body: string; base64Encoded: boolean }>;\n fulfillRequest: (opts: {\n requestId: string;\n responseCode: number;\n responseHeaders: CDPHeader[];\n body?: string;\n base64Encoded?: boolean;\n }) => Promise<void>;\n continueRequest: (opts: { requestId: string }) => Promise<void>;\n };\n Network: {\n getAllCookies: () => Promise<{ cookies: CDPCookie[] }>;\n setCookie: (opts: CDPCookieSet) => Promise<void>;\n };\n Target: {\n setDiscoverTargets: (opts: { discover: boolean }) => Promise<void>;\n closeTarget: (opts: { targetId: string }) => Promise<void>;\n activateTarget: (opts: { targetId: string }) => Promise<void>;\n };\n Browser: {\n setDockTile: (opts: { image?: string; label?: string }) => Promise<void>;\n };\n send: (method: string, params?: object, sessionId?: string) => Promise<unknown>;\n on: (event: string, handler: (params: unknown, sessionId?: string) => void) => void;\n close: () => Promise<void>;\n}\n\ninterface CDPTargetCreatedEvent {\n targetInfo: {\n targetId: string;\n type: string;\n url: string;\n };\n}\n\ninterface CDPCookie {\n name: string;\n value: string;\n domain?: string;\n path?: string;\n secure?: boolean;\n httpOnly?: boolean;\n sameSite?: string;\n expirationDate?: number;\n}\n\ninterface CDPCookieSet {\n url: string;\n name: string;\n value: string;\n domain?: string;\n path?: string;\n secure?: boolean;\n httpOnly?: boolean;\n sameSite?: string;\n expires?: number;\n}\n\nconst CSP_HEADERS = new Set([\n 'content-security-policy',\n 'content-security-policy-report-only',\n 'x-frame-options',\n]);\n\nconst KIZEN_DOMAINS = ['kizen.dev', 'kizen.com'];\n\nfunction isKizenUrl(url: string): boolean {\n try {\n const { hostname } = new URL(url);\n\n return KIZEN_DOMAINS.some((d) => hostname === d || hostname.endsWith('.' + d));\n } catch {\n return false;\n }\n}\n\nasync function installDockIcon(client: CDPClient): Promise<void> {\n try {\n const iconPath = join(dirname(fileURLToPath(import.meta.url)), 'viewer', 'icon.png');\n const icon = await readFile(iconPath);\n\n await client.Browser.setDockTile({ image: icon.toString('base64') });\n } catch {\n // Non-critical: silently skip if icon is missing or platform doesn't support it\n }\n}\n\nexport interface ChromeViewerOptions {\n port: number;\n userDataDir: string;\n broadcast: (msg: object) => void;\n path?: string;\n debugLog?: (msg: string) => void;\n // Always-on channel for user-visible warnings (e.g. \"CDP unavailable,\n // running without interception\"). Unlike debugLog, not gated by --debug.\n onWarn?: (msg: string) => void;\n verbose?: boolean;\n}\n\nexport interface ChromeViewerHandle {\n kill: () => void;\n}\n\nexport async function launchChromeViewer(opts: ChromeViewerOptions): Promise<ChromeViewerHandle> {\n // chrome-launcher opens log files inside userDataDir before Chrome starts\n mkdirSync(opts.userDataDir, { recursive: true });\n\n const baseUrl = `http://localhost:${String(opts.port)}`;\n\n const chrome: LaunchedChrome = await launch({\n startingUrl: baseUrl,\n chromeFlags: [\n `--app=${baseUrl}`,\n '--no-first-run',\n '--no-default-browser-check',\n '--disable-extensions',\n '--disable-features=DeviceBoundSessions',\n ],\n userDataDir: opts.userDataDir,\n handleSIGINT: false,\n logLevel: 'silent',\n });\n\n const cdpPort = chrome.port;\n\n let client: CDPClient | null = null;\n let cookieTimer: ReturnType<typeof setInterval> | null = null;\n let mainTargetId: string | null = null;\n let reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n let reconnectAttempt = 0;\n let killed = false;\n\n const dbg = (msg: string): void => {\n opts.debugLog?.(msg);\n };\n\n const vb = (msg: string): void => {\n if (opts.verbose) {\n opts.debugLog?.(msg);\n }\n };\n\n const clearCookieTimer = (): void => {\n if (cookieTimer !== null) {\n clearInterval(cookieTimer);\n cookieTimer = null;\n }\n };\n\n const isNewTabUrl = (url: string): boolean =>\n url === 'chrome://new-tab-page/' || url === 'chrome://newtab/';\n\n const setupClient = async (c: CDPClient): Promise<void> => {\n // Fresh CDP session: reset per-connection state.\n clearCookieTimer();\n mainTargetId = null;\n\n await installDockIcon(c);\n\n // ── 1. Response interception: strip CSP + fix SameSite cookies ──────────────\n await c.Fetch.enable({\n patterns: KIZEN_DOMAINS.flatMap((d) => [\n { urlPattern: `*://${d}/*`, requestStage: 'Response' },\n { urlPattern: `*://*.${d}/*`, requestStage: 'Response' },\n ]),\n });\n\n c.on('Fetch.requestPaused', (rawParams: unknown) => {\n void (async () => {\n const params = rawParams as CDPFetchPausedEvent;\n const { requestId, request, responseHeaders, responseStatusCode } = params;\n const url = request.url;\n\n vb(`Fetch ${String(responseStatusCode ?? '?')} ${url}`);\n\n const filtered: CDPHeader[] = [];\n let rewroteSetCookie = false;\n\n for (const h of responseHeaders ?? []) {\n if (CSP_HEADERS.has(h.name.toLowerCase())) {\n continue;\n }\n\n if (h.name.toLowerCase() === 'set-cookie' && isKizenUrl(url)) {\n const patched = h.value\n .split('\\n')\n .map((cookie) => {\n if (!/SameSite=/i.test(cookie)) {\n return cookie + '; SameSite=None; Secure';\n }\n\n return cookie.replace(/SameSite=\\w+/i, 'SameSite=None');\n })\n .join('\\n');\n\n filtered.push({ name: h.name, value: patched });\n rewroteSetCookie = true;\n } else {\n filtered.push(h);\n }\n }\n\n if (rewroteSetCookie) {\n vb(` rewrote Set-Cookie SameSite on ${url}`);\n }\n\n try {\n const { body, base64Encoded } = await c.Fetch.getResponseBody({ requestId });\n\n await c.Fetch.fulfillRequest({\n requestId,\n responseCode: responseStatusCode ?? 200,\n responseHeaders: filtered,\n body,\n ...(base64Encoded && { base64Encoded: true }),\n });\n } catch (e) {\n vb(` fulfillRequest failed (${(e as Error).message}), falling through`);\n\n try {\n await c.Fetch.continueRequest({ requestId });\n } catch (e2) {\n vb(` continueRequest also failed (${(e2 as Error).message})`);\n }\n }\n })();\n });\n\n // ── 2. Periodic SameSite cookie patching ────────────────────────────────────\n cookieTimer = setInterval(() => {\n void (async () => {\n try {\n const { cookies } = await c.Network.getAllCookies();\n\n let patched = 0;\n\n for (const cookie of cookies) {\n if (!isKizenUrl(`https://${cookie.domain ?? ''}`)) {\n continue;\n }\n\n if (cookie.sameSite === 'None') {\n continue;\n }\n\n const raw = cookie.domain ?? '';\n const bare = raw.startsWith('.') ? raw.slice(1) : raw;\n\n await c.Network.setCookie({\n url: `https://${bare}`,\n name: cookie.name,\n value: cookie.value,\n domain: raw,\n path: cookie.path ?? '/',\n secure: true,\n ...(cookie.httpOnly !== undefined && { httpOnly: cookie.httpOnly }),\n ...(cookie.expirationDate !== undefined && {\n expires: cookie.expirationDate,\n }),\n sameSite: 'None',\n });\n\n patched++;\n }\n\n if (patched > 0) {\n vb(`cookie-patch cycle: updated ${String(patched)} cookie(s) to SameSite=None`);\n }\n } catch (e) {\n vb(`cookie-patch cycle failed: ${(e as Error).message}`);\n }\n })();\n }, 2000);\n\n // macOS dock clicks on --app= windows open a stray new-tab-page window\n // (Chromium excludes app windows from its \"is a browser window open?\" check).\n // activate the original app window, then close the intruder. setDiscoverTargets replays\n // existing targets so mainTargetId gets recaptured after a CDP reconnect.\n await c.Target.setDiscoverTargets({ discover: true });\n\n const handleTarget = (targetInfo: { targetId: string; type: string; url: string }): void => {\n if (targetInfo.type !== 'page') {\n return;\n }\n\n if (isNewTabUrl(targetInfo.url)) {\n dbg(`closed stray new-tab-page target ${targetInfo.targetId}`);\n\n if (mainTargetId !== null) {\n void c.Target.activateTarget({ targetId: mainTargetId }).catch(() => {\n /* ignore */\n });\n }\n\n void c.Target.closeTarget({ targetId: targetInfo.targetId }).catch(() => {\n /* ignore */\n });\n\n return;\n }\n\n if (mainTargetId === null) {\n mainTargetId = targetInfo.targetId;\n dbg(`captured main target ${targetInfo.targetId} (${targetInfo.url})`);\n }\n };\n\n c.on('Target.targetCreated', (rawParams: unknown) => {\n const { targetInfo } = rawParams as CDPTargetCreatedEvent;\n\n vb(`target +${targetInfo.type} ${targetInfo.targetId} ${targetInfo.url}`);\n handleTarget(targetInfo);\n });\n\n c.on('Target.targetInfoChanged', (rawParams: unknown) => {\n const { targetInfo } = rawParams as CDPTargetCreatedEvent;\n\n vb(`target ~${targetInfo.type} ${targetInfo.targetId} ${targetInfo.url}`);\n handleTarget(targetInfo);\n });\n\n // CDP's underlying WebSocket can drop (sleep/wake, transient failure) while\n // Chrome keeps running. Without reconnect, all interception silently stops.\n c.on('disconnect', () => {\n if (killed || client !== c) {\n return;\n }\n\n dbg('CDP disconnected');\n client = null;\n clearCookieTimer();\n scheduleReconnect();\n });\n };\n\n const scheduleReconnect = (): void => {\n if (killed || reconnectTimer !== null) {\n return;\n }\n\n const delay = Math.min(1000 * 2 ** reconnectAttempt, 10_000);\n const attemptNumber = reconnectAttempt + 1;\n\n reconnectAttempt++;\n\n dbg(`CDP reconnect scheduled in ${String(delay)}ms (attempt #${String(attemptNumber)})`);\n\n reconnectTimer = setTimeout(() => {\n reconnectTimer = null;\n\n void (async () => {\n let c: CDPClient;\n\n try {\n c = await CDP({ port: cdpPort });\n } catch {\n dbg(`CDP reconnect attempt #${String(attemptNumber)} failed`);\n scheduleReconnect();\n\n return;\n }\n\n if (killed) {\n try {\n await c.close();\n } catch {\n /* ignore */\n }\n\n return;\n }\n\n client = c;\n\n try {\n await setupClient(c);\n dbg(`CDP reconnected after ${String(attemptNumber)} attempt(s)`);\n reconnectAttempt = 0;\n } catch {\n if (client === c) {\n client = null;\n }\n\n try {\n await c.close();\n } catch {\n /* ignore */\n }\n\n dbg(`CDP reconnect attempt #${String(attemptNumber)} failed during setup`);\n scheduleReconnect();\n }\n })();\n }, delay);\n };\n\n // Initial CDP connection — Chrome may not be ready immediately. 30 × 300ms\n // (9s total) gives cold starts, slow disks, and Rosetta-translated Chromium\n // a reasonable window before we give up and run without interception.\n const MAX_CDP_ATTEMPTS = 30;\n const CDP_ATTEMPT_DELAY_MS = 300;\n\n for (let attempt = 0; attempt < MAX_CDP_ATTEMPTS; attempt++) {\n await new Promise<void>((r) => setTimeout(r, CDP_ATTEMPT_DELAY_MS));\n\n dbg(`CDP connect attempt ${String(attempt + 1)}/${String(MAX_CDP_ATTEMPTS)}`);\n\n try {\n const c = await CDP({ port: cdpPort });\n\n client = c;\n\n if (opts.path) {\n void c.send('Page.navigate', { url: `${baseUrl}${opts.path}` });\n }\n\n try {\n await setupClient(c);\n dbg('CDP connected');\n } catch {\n if (client === c) {\n client = null;\n }\n\n try {\n await c.close();\n } catch {\n /* ignore */\n }\n\n dbg('CDP setup failed after connect');\n }\n\n break;\n } catch {\n if (attempt === MAX_CDP_ATTEMPTS - 1) {\n // CDP never came up; window still opens, just no CSP rewrite or\n // SameSite cookie patching. Surface this via onWarn so it appears in\n // the TUI even when the user didn't pass --debug.\n const warning = `CDP unavailable after ${String(MAX_CDP_ATTEMPTS)} attempts — viewer running without interception (CSP/cookie rewrites disabled)`;\n\n dbg(warning);\n opts.onWarn?.(warning);\n\n return {\n kill: () => {\n chrome.kill();\n },\n };\n }\n }\n }\n\n if (!client) {\n return {\n kill: () => {\n chrome.kill();\n },\n };\n }\n\n const kill = (): void => {\n dbg('CDP kill requested — tearing down');\n killed = true;\n\n if (reconnectTimer !== null) {\n clearTimeout(reconnectTimer);\n reconnectTimer = null;\n }\n\n clearCookieTimer();\n\n if (client !== null) {\n try {\n void client.close();\n } catch {\n /* ignore */\n }\n\n client = null;\n }\n\n chrome.kill();\n };\n\n return { kill };\n}\n","import { useCallback, useState } from 'react';\n\nexport function useLogHistory(limit: number): [string[], (message: string) => void] {\n const [history, setHistory] = useState<string[]>([]);\n\n const append = useCallback(\n (message: string): void => {\n setHistory((h) => [...h, `${new Date().toLocaleTimeString()}: ${message}`].slice(-limit));\n },\n [limit],\n );\n\n return [history, append];\n}\n","import type { FC } from 'react';\nimport { useCallback, useEffect, useState } from 'react';\nimport { Box, Text, useInput } from 'ink';\nimport {\n DEFAULT_PROFILE_NAME,\n ENVIRONMENTS,\n GLOBAL_CREDENTIALS_PATH,\n listCredentialProfiles,\n loadCredentialProfile,\n loadGlobalCredentials,\n normalizeCredentialIds,\n saveCredentialProfile,\n} from '../lib/credentials.js';\nimport type { CredentialProfile, Credentials } from '../lib/credentials.js';\nimport { AppHeader } from './AppHeader.js';\n\ntype Mode = 'global' | 'local';\n\ntype Phase =\n | { type: 'mode-select'; cursor: 0 | 1 }\n | { type: 'profile-loading' }\n | { type: 'profile-select'; profiles: CredentialProfile[]; cursor: number }\n | {\n type: 'name-entry';\n nameBuffer: string;\n nameError?: string;\n existingProfiles: CredentialProfile[];\n }\n | { type: 'loading' }\n | { type: 'creds-entry'; field: number; values: Partial<Credentials>; envCursor: number }\n | { type: 'saving' }\n | { type: 'done' };\n\nconst FIELDS = ['apiKey', 'userId', 'businessId'] as const;\nconst FIELD_LABELS: Record<string, string> = {\n apiKey: 'API Key',\n userId: 'User ID',\n businessId: 'Business ID',\n};\n\nexport type CredentialMode = 'global' | 'local';\n\nexport interface CredentialSetupResult {\n mode: CredentialMode;\n credentials: Credentials | null;\n profileName?: string;\n}\n\ninterface CredentialSetupUIProps {\n initialMode?: CredentialMode;\n showProfileManager?: boolean;\n onComplete: (result: CredentialSetupResult) => void;\n onCancel?: () => void;\n}\n\nconst Hint: FC<{ text: string }> = ({ text }) => <Text dimColor>{text}</Text>;\n\nexport const CredentialSetupUI: FC<CredentialSetupUIProps> = ({\n initialMode,\n showProfileManager,\n onComplete,\n onCancel,\n}) => {\n const [phase, setPhase] = useState<Phase>(\n initialMode === 'global' && !showProfileManager\n ? { type: 'loading' }\n : initialMode === 'global' && showProfileManager\n ? { type: 'profile-loading' }\n : { type: 'mode-select', cursor: 0 },\n );\n const [inputBuffer, setInputBuffer] = useState('');\n const [error, setError] = useState<string | null>(null);\n const [activeProfileName, setActiveProfileName] = useState<string | undefined>(undefined);\n\n const handleModeChosen = useCallback(\n (mode: Mode) => {\n if (mode === 'local') {\n onComplete({ mode: 'local', credentials: null });\n\n return;\n }\n\n setPhase({ type: 'profile-loading' });\n },\n [onComplete],\n );\n\n const handleProfileChosen = useCallback(async (profile: CredentialProfile | null) => {\n if (profile === null) {\n // \"Add new profile\" selected\n setPhase({ type: 'profile-loading' });\n\n const profiles = await listCredentialProfiles();\n\n setPhase({ type: 'name-entry', nameBuffer: '', existingProfiles: profiles });\n\n return;\n }\n\n setActiveProfileName(profile.isDefault ? undefined : profile.name);\n\n setPhase({ type: 'loading' });\n\n const existing = profile.isDefault\n ? await loadGlobalCredentials()\n : await loadCredentialProfile(profile.name);\n const envCursor = existing ? Math.max(0, ENVIRONMENTS.indexOf(existing.environment)) : 0;\n\n setPhase({ type: 'creds-entry', field: 0, values: existing ?? {}, envCursor });\n }, []);\n\n const handleSave = useCallback(\n async (values: Partial<Credentials>, envCursor: number) => {\n const environment = ENVIRONMENTS[envCursor] ?? 'go';\n const credentials: Credentials = {\n ...normalizeCredentialIds(values),\n environment,\n };\n\n setPhase({ type: 'saving' });\n\n try {\n const profileName = activeProfileName ?? DEFAULT_PROFILE_NAME;\n\n await saveCredentialProfile(profileName, credentials);\n\n onComplete({\n mode: 'global',\n credentials,\n ...(activeProfileName !== undefined && { profileName: activeProfileName }),\n });\n } catch (err) {\n setError(err instanceof Error ? err.message : String(err));\n\n setPhase({ type: 'creds-entry', field: 0, values, envCursor });\n }\n },\n [onComplete, activeProfileName],\n );\n\n useInput((input, key) => {\n if (key.ctrl && input === 'c') {\n process.exit(0);\n }\n\n if (key.escape) {\n if (phase.type === 'creds-entry' || phase.type === 'name-entry') {\n // Go back to profile select if we came from there\n if (initialMode === 'global' && showProfileManager) {\n setPhase({ type: 'profile-loading' });\n\n void loadProfileList();\n\n return;\n }\n }\n\n onCancel?.();\n\n return;\n }\n\n if (phase.type === 'mode-select') {\n if (key.upArrow) {\n setPhase({ type: 'mode-select', cursor: 0 });\n } else if (key.downArrow) {\n setPhase({ type: 'mode-select', cursor: 1 });\n } else if (key.return) {\n const mode: Mode = phase.cursor === 0 ? 'global' : 'local';\n\n handleModeChosen(mode);\n }\n\n return;\n }\n\n if (phase.type === 'profile-select') {\n const { profiles, cursor } = phase;\n const addNewIdx = profiles.length;\n const totalItems = profiles.length + 1; // +1 for \"Add new\"\n\n if (key.upArrow) {\n setPhase({ ...phase, cursor: (cursor - 1 + totalItems) % totalItems });\n } else if (key.downArrow) {\n setPhase({ ...phase, cursor: (cursor + 1) % totalItems });\n } else if (key.return) {\n if (cursor === addNewIdx) {\n setPhase({ type: 'name-entry', nameBuffer: '', existingProfiles: profiles });\n } else {\n const selected = profiles[cursor] ?? profiles[0];\n\n if (selected) {\n void handleProfileChosen(selected);\n }\n }\n }\n\n return;\n }\n\n if (phase.type === 'name-entry') {\n const { nameBuffer, existingProfiles } = phase;\n\n if (key.backspace || key.delete) {\n setPhase({ type: 'name-entry', nameBuffer: nameBuffer.slice(0, -1), existingProfiles });\n } else if (key.return) {\n const trimmed = nameBuffer.trim();\n\n if (!trimmed) {\n setPhase({ ...phase, nameError: 'Name cannot be empty' });\n\n return;\n }\n\n if (trimmed === DEFAULT_PROFILE_NAME) {\n setPhase({ ...phase, nameError: `\"${DEFAULT_PROFILE_NAME}\" is reserved` });\n\n return;\n }\n\n if (existingProfiles.some((p) => p.name === trimmed)) {\n setPhase({ ...phase, nameError: `Profile \"${trimmed}\" already exists` });\n\n return;\n }\n\n // Valid name — proceed to empty creds-entry\n setActiveProfileName(trimmed);\n\n setPhase({ type: 'creds-entry', field: 0, values: {}, envCursor: 0 });\n\n setInputBuffer('');\n } else if (input && !key.ctrl && !key.meta) {\n setPhase({ type: 'name-entry', nameBuffer: nameBuffer + input, existingProfiles });\n }\n\n return;\n }\n\n if (phase.type === 'creds-entry') {\n const { field, values, envCursor } = phase;\n const isEnvField = field === FIELDS.length;\n\n if (isEnvField) {\n if (key.leftArrow) {\n setPhase({\n ...phase,\n envCursor: (envCursor - 1 + ENVIRONMENTS.length) % ENVIRONMENTS.length,\n });\n } else if (key.rightArrow) {\n setPhase({ ...phase, envCursor: (envCursor + 1) % ENVIRONMENTS.length });\n } else if (key.upArrow) {\n setPhase({ ...phase, field: field - 1 });\n\n setInputBuffer(values[FIELDS[field - 1] as keyof typeof values] ?? '');\n } else if (key.return) {\n void handleSave(values, envCursor);\n }\n\n return;\n }\n\n const fieldName = FIELDS[field];\n\n if (!fieldName) {\n return;\n }\n\n if (key.backspace || key.delete) {\n setInputBuffer((prev) => prev.slice(0, -1));\n } else if (key.upArrow && field > 0) {\n const updatedValues = { ...values, [fieldName]: inputBuffer };\n const prevField = field - 1;\n\n setPhase({ ...phase, field: prevField, values: updatedValues });\n\n setInputBuffer(updatedValues[FIELDS[prevField] as keyof typeof updatedValues] ?? '');\n } else if (key.return || key.tab || key.downArrow) {\n const updatedValues = { ...values, [fieldName]: inputBuffer };\n const nextField = field + 1;\n\n setPhase({ ...phase, field: nextField, values: updatedValues });\n\n if (nextField < FIELDS.length) {\n setInputBuffer(updatedValues[FIELDS[nextField] as keyof typeof updatedValues] ?? '');\n } else {\n setInputBuffer('');\n }\n } else if (input && !key.ctrl && !key.meta) {\n setInputBuffer((prev) => prev + input);\n }\n }\n });\n\n const loadProfileList = useCallback(async () => {\n const profiles = await listCredentialProfiles();\n\n setPhase({ type: 'profile-select', profiles, cursor: 0 });\n }, []);\n\n // Load profile list when entering profile-loading phase\n useEffect(() => {\n if (phase.type === 'profile-loading') {\n void loadProfileList();\n }\n }, [phase.type, loadProfileList]);\n\n // Handle initial mode without profile manager (existing behavior)\n useEffect(() => {\n if (initialMode === 'global' && !showProfileManager) {\n void (async () => {\n const existing = await loadGlobalCredentials();\n const envCursor = existing ? Math.max(0, ENVIRONMENTS.indexOf(existing.environment)) : 0;\n\n setPhase({ type: 'creds-entry', field: 0, values: existing ?? {}, envCursor });\n })();\n }\n }, []); // eslint-disable-line react-hooks/exhaustive-deps\n\n // Reset input buffer when switching to creds-entry\n useEffect(() => {\n if (phase.type === 'creds-entry' && phase.field === 0) {\n setInputBuffer(phase.values.apiKey ?? '');\n }\n }, [phase.type]); // eslint-disable-line react-hooks/exhaustive-deps\n\n if (phase.type === 'loading' || phase.type === 'saving' || phase.type === 'profile-loading') {\n const label =\n phase.type === 'saving'\n ? 'Saving credentials…'\n : phase.type === 'profile-loading'\n ? 'Loading profiles…'\n : 'Loading credentials…';\n\n return (\n <Box paddingY={1} paddingX={2}>\n <Text dimColor>{label}</Text>\n </Box>\n );\n }\n\n if (phase.type === 'done') {\n return null;\n }\n\n if (phase.type === 'mode-select') {\n const options: { label: string; desc: string; mode: Mode }[] = [\n { label: 'Global', desc: `~/.kizenappbuilder/credentials.json`, mode: 'global' },\n { label: 'Local', desc: 'Enter credentials in the browser dev tools', mode: 'local' },\n ];\n\n return (\n <Box flexDirection=\"column\" paddingY={1} paddingX={2} gap={1}>\n <AppHeader />\n <Box flexDirection=\"column\" gap={0}>\n <Text bold>Credential mode</Text>\n {options.map((opt, i) => {\n const selected = phase.cursor === i;\n\n return (\n <Box key={opt.mode} gap={2}>\n <Text {...(selected && { color: 'cyan' as const })}>{selected ? '❯' : ' '}</Text>\n <Text bold={selected} {...(selected && { color: 'cyan' as const })}>\n {opt.label}\n </Text>\n <Text dimColor>{opt.desc}</Text>\n </Box>\n );\n })}\n </Box>\n <Hint text=\"↑↓ to move · Enter to select · Ctrl+C to quit\" />\n </Box>\n );\n }\n\n if (phase.type === 'profile-select') {\n const { profiles, cursor } = phase;\n const addNewIdx = profiles.length;\n\n return (\n <Box flexDirection=\"column\" paddingY={1} paddingX={2} gap={1}>\n <AppHeader />\n <Box flexDirection=\"column\" gap={0}>\n <Text bold>Credential profiles</Text>\n {profiles.map((profile, i) => {\n const selected = cursor === i;\n\n return (\n <Box key={profile.name} gap={2}>\n <Text {...(selected && { color: 'cyan' as const })}>{selected ? '❯' : ' '}</Text>\n <Text bold={selected} {...(selected && { color: 'cyan' as const })}>\n {profile.isDefault ? 'Default' : profile.name}\n </Text>\n <Text dimColor>{profile.path}</Text>\n </Box>\n );\n })}\n <Box gap={2}>\n <Text {...(cursor === addNewIdx && { color: 'cyan' as const })}>\n {cursor === addNewIdx ? '❯' : ' '}\n </Text>\n <Text\n bold={cursor === addNewIdx}\n {...(cursor === addNewIdx && { color: 'cyan' as const })}\n >\n + Add new profile\n </Text>\n </Box>\n </Box>\n <Hint text=\"↑↓ to move · Enter to select · Esc to cancel\" />\n </Box>\n );\n }\n\n if (phase.type === 'name-entry') {\n const { nameBuffer, nameError } = phase;\n\n return (\n <Box flexDirection=\"column\" paddingY={1} paddingX={2} gap={1}>\n <AppHeader />\n <Box flexDirection=\"column\" gap={0}>\n <Text bold>New credential profile</Text>\n </Box>\n {nameError && <Text color=\"red\">Error: {nameError}</Text>}\n <Box gap={2}>\n <Box width={12}>\n <Text bold color=\"cyan\">\n Profile name\n </Text>\n </Box>\n <Text color=\"cyan\">{'>'}</Text>\n <Text>{nameBuffer}</Text>\n <Text color=\"cyan\">{'█'}</Text>\n </Box>\n <Hint text=\"Type a name · Enter to confirm · Esc to go back\" />\n </Box>\n );\n }\n\n // creds-entry phase\n const { field: activeField, values, envCursor } = phase;\n const isEnvField = activeField === FIELDS.length;\n const profileLabel = activeProfileName ?? DEFAULT_PROFILE_NAME;\n\n return (\n <Box flexDirection=\"column\" paddingY={1} paddingX={2} gap={1}>\n <AppHeader />\n <Box flexDirection=\"column\" gap={0}>\n <Text bold>\n {activeProfileName !== undefined ? `Profile: ${activeProfileName}` : 'Global credentials'}\n </Text>\n <Text dimColor>\n Saved to:{' '}\n {activeProfileName !== undefined\n ? `~/.kizenappbuilder/${activeProfileName}.json`\n : GLOBAL_CREDENTIALS_PATH}\n </Text>\n </Box>\n {error && <Text color=\"red\">Error: {error}</Text>}\n <Box flexDirection=\"column\" gap={0}>\n {FIELDS.map((name, i) => {\n const isActive = activeField === i;\n const displayValue = isActive ? inputBuffer : (values[name] ?? '');\n\n return (\n <Box key={name} gap={2}>\n <Box width={12}>\n <Text bold={isActive} {...(isActive && { color: 'cyan' as const })}>\n {FIELD_LABELS[name]}\n </Text>\n </Box>\n <Text {...(isActive && { color: 'cyan' as const })}>{'>'}</Text>\n <Text>{displayValue}</Text>\n {isActive && <Text color=\"cyan\">{'█'}</Text>}\n </Box>\n );\n })}\n <Box gap={2}>\n <Box width={12}>\n <Text bold={isEnvField} {...(isEnvField && { color: 'cyan' as const })}>\n Environment\n </Text>\n </Box>\n <Text {...(isEnvField && { color: 'cyan' as const })}>{'>'}</Text>\n <Box gap={1}>\n {ENVIRONMENTS.map((env, i) => {\n const isSelected = i === envCursor;\n\n if (isEnvField) {\n return (\n <Text key={env} bold={isSelected} {...(isSelected && { color: 'cyan' as const })}>\n {isSelected ? `[${env}]` : env}\n </Text>\n );\n }\n\n return (\n <Text key={env} dimColor={!isSelected} bold={isSelected}>\n {env}\n </Text>\n );\n })}\n </Box>\n </Box>\n </Box>\n {isEnvField ? (\n <Hint text=\"←→ to select · ↑↓ to move · Enter to save · Esc to cancel\" />\n ) : (\n <Hint text=\"↑↓ to move · Backspace to delete · Esc to cancel\" />\n )}\n <Text dimColor>Profile: {profileLabel}</Text>\n </Box>\n );\n};\n","import { createElement } from 'react';\nimport { render } from 'ink';\nimport type { Command } from 'commander';\nimport { EncryptUI } from '../ui/EncryptUI.js';\nimport { encryptSecret } from '../lib/encryptionClient.js';\nimport type { EncryptionContext } from '../lib/encryptionClient.js';\nimport { loadCredentialsFromFile, loadGlobalCredentials } from '../lib/credentials.js';\nimport {\n invalidStageMessage,\n isValidStage,\n readManifestDefaults,\n readStdin,\n resolveStage,\n writeEnvelopeFile,\n type ManifestDefaults,\n} from '../lib/encryptHelpers.js';\nimport { runHeadless } from '../lib/encryptHeadless.js';\n\ninterface EncryptOptions {\n remote?: boolean;\n credentials?: string;\n apiName?: string;\n value?: string;\n stage?: string;\n out?: string;\n}\n\nexport function encryptCommand(program: Command): void {\n program\n .command('encrypt')\n .description('Encrypt a secret for a plugin against its encryption keys')\n .option('--remote', \"encrypt via the plugin-wizard's remote API instead of on-machine\")\n .option('-c, --credentials <path>', 'path to a credentials JSON file')\n .option('-a, --api-name <name>', 'plugin api_name the secret belongs to')\n .option('-v, --value <value>', 'plaintext secret value to encrypt')\n .option('-s, --stage <stage>', 'which encryption API to use: dev or prod (default: prod)')\n .option('-o, --out <path>', 'also write the encrypted envelope to a file')\n .action(async (options: EncryptOptions) => {\n if (options.stage !== undefined && !isValidStage(options.stage)) {\n console.error(invalidStageMessage(options.stage));\n process.exit(1);\n }\n\n // Read kizen.json for the api_name default. Skip the file read entirely\n // when api_name is already supplied via a flag.\n const needsDefaults = options.apiName === undefined;\n const defaults: ManifestDefaults = needsDefaults ? await readManifestDefaults() : {};\n\n // Default to prod when --stage isn't given (almost every plugin ships to\n // production); pass --stage dev to override.\n const { stage, wasDefaulted: stageWasDefaulted } = resolveStage(options.stage);\n\n const ctx: EncryptionContext = {\n isRemote: options.remote === true,\n stage,\n };\n\n // ink's interactive UI needs a TTY for raw-mode input AND a TTY stdout to\n // render into. If either is redirected/piped (CI, `> out.json`, `| jq`),\n // fall back to the headless flow so stdout gets clean compact JSON instead\n // of ANSI frames.\n if (!process.stdin.isTTY || !process.stdout.isTTY) {\n try {\n await runHeadless(ctx, options, defaults, stageWasDefaulted, {\n loadCredentialsFromFile,\n loadGlobalCredentials,\n encryptSecret,\n readStdin,\n stdinIsTTY: () => process.stdin.isTTY,\n writeStdout: (text) => {\n process.stdout.write(text);\n },\n writeStderr: (text) => {\n process.stderr.write(text);\n },\n writeEnvelopeFile,\n setExitCode: (code) => {\n process.exitCode = code;\n },\n });\n } catch (err) {\n console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);\n process.exit(1);\n }\n\n return;\n }\n\n // The UI copies to the clipboard itself; we capture the raw value here so\n // that after ink unmounts we can write --out (ink's rendered frame\n // soft-wraps the long base64, so we never read the envelope back off it).\n let envelopeValue: string | undefined;\n\n const { waitUntilExit } = render(\n createElement(EncryptUI, {\n ctx,\n stageDefaulted: stageWasDefaulted,\n onDone: (value: string) => {\n envelopeValue = value;\n },\n ...(options.credentials !== undefined && { credentialsPath: options.credentials }),\n ...(options.apiName !== undefined && { initialApiName: options.apiName }),\n ...(defaults.apiName !== undefined && { defaultApiName: defaults.apiName }),\n ...(options.value !== undefined && { initialValue: options.value }),\n }),\n { exitOnCtrlC: false },\n );\n\n await waitUntilExit();\n\n // envelopeValue is only set on success (onDone); stays undefined on Ctrl+C\n // or error, so nothing is written in those cases.\n if (envelopeValue !== undefined && options.out !== undefined) {\n try {\n await writeEnvelopeFile(options.out, envelopeValue);\n process.stderr.write(`Wrote encrypted envelope to ${options.out}\\n`);\n } catch (err) {\n console.error(\n `Error writing ${options.out}: ${err instanceof Error ? err.message : String(err)}`,\n );\n process.exitCode = 1;\n }\n }\n });\n}\n","import type { FC, ReactNode } from 'react';\nimport { useCallback, useEffect, useState } from 'react';\nimport { Box, Text, useApp, useInput } from 'ink';\nimport {\n listCredentialProfiles,\n loadCredentialProfile,\n loadCredentialsFromFile,\n loadGlobalCredentials,\n} from '../lib/credentials.js';\nimport type { CredentialProfile, Credentials } from '../lib/credentials.js';\nimport { encryptSecret } from '../lib/encryptionClient.js';\nimport type { EncryptionContext } from '../lib/encryptionClient.js';\nimport { copyToClipboard } from '../lib/clipboard.js';\nimport { AppHeader } from './AppHeader.js';\nimport { Spinner } from './Spinner.js';\n\ninterface EncryptUIProps {\n ctx: EncryptionContext;\n /** True when --stage was not given and the stage fell back to the prod default. */\n stageDefaulted?: boolean;\n /** Skip the profile picker and load from this file instead. */\n credentialsPath?: string;\n /** Provided via --api-name; skips the api_name prompt. */\n initialApiName?: string;\n /** Prefill for the api_name prompt (from kizen.json) — does not skip it. */\n defaultApiName?: string;\n /** Provided via --value; skips the secret prompt. */\n initialValue?: string;\n /** Called once with the base64 envelope value when encryption succeeds, so the\n * caller can write --out / emit it after ink unmounts. */\n onDone?: (envelopeValue: string) => void;\n}\n\ntype Phase =\n | { type: 'loading' }\n | { type: 'profile-select'; profiles: CredentialProfile[]; cursor: number }\n | { type: 'api-name-entry'; buffer: string; error?: string }\n | { type: 'value-entry'; buffer: string; error?: string }\n | { type: 'fetching-key' }\n | { type: 'encrypting' }\n | { type: 'done'; envelope: string; copied: boolean }\n | { type: 'error'; message: string };\n\nconst Hint: FC<{ text: string }> = ({ text }) => <Text dimColor>{text}</Text>;\n\nexport const EncryptUI: FC<EncryptUIProps> = ({\n ctx,\n stageDefaulted,\n credentialsPath,\n initialApiName,\n defaultApiName,\n initialValue,\n onDone,\n}) => {\n const app = useApp();\n const [phase, setPhase] = useState<Phase>({ type: 'loading' });\n const [credentials, setCredentials] = useState<Credentials | null>(null);\n const [apiName, setApiName] = useState<string>(initialApiName ?? '');\n const [secret, setSecret] = useState<string>(initialValue ?? '');\n\n const fail = useCallback((err: unknown) => {\n process.exitCode = 1;\n // Exit is deferred to the terminal-phase effect below so the error frame is\n // actually painted before ink unmounts.\n setPhase({ type: 'error', message: err instanceof Error ? err.message : String(err) });\n }, []);\n\n const runEncryption = useCallback(\n async (creds: Credentials, name: string, value: string) => {\n try {\n const envelopeValue = await encryptSecret(ctx, creds, name, value, (p) => {\n setPhase(p === 'fetching-key' ? { type: 'fetching-key' } : { type: 'encrypting' });\n });\n const envelope = JSON.stringify({ encrypted: true, value: envelopeValue }, null, 2);\n\n onDone?.(envelopeValue);\n\n // Copy the envelope to the clipboard so the user can paste it without the\n // terminal's soft-wrapping becoming real line breaks in the copied text.\n // The envelope is ciphertext (never the plaintext secret), so this is\n // safe; the copy is best-effort and the envelope is shown either way.\n const copied = await copyToClipboard(envelope);\n\n // Exit is deferred to the terminal-phase effect below so the done frame\n // (with the envelope) is painted before ink unmounts.\n setPhase({ type: 'done', envelope, copied });\n } catch (err) {\n fail(err);\n }\n },\n [ctx, fail, onDone],\n );\n\n // Advance to the next required input, or kick off the encryption once we have\n // everything. Args are passed explicitly so we never read stale state.\n const proceed = useCallback(\n (creds: Credentials, name: string, value: string) => {\n if (name.trim() === '') {\n setPhase({ type: 'api-name-entry', buffer: defaultApiName ?? '' });\n\n return;\n }\n\n if (value === '') {\n setPhase({ type: 'value-entry', buffer: '' });\n\n return;\n }\n\n void runEncryption(creds, name.trim(), value);\n },\n [defaultApiName, runEncryption],\n );\n\n const handleProfileChosen = useCallback(\n async (profile: CredentialProfile) => {\n try {\n setPhase({ type: 'loading' });\n\n const creds = profile.isDefault\n ? await loadGlobalCredentials()\n : await loadCredentialProfile(profile.name);\n\n if (creds === null) {\n throw new Error(`Could not load credential profile: ${profile.name}`);\n }\n\n setCredentials(creds);\n proceed(creds, apiName, secret);\n } catch (err) {\n fail(err);\n }\n },\n [apiName, secret, proceed, fail],\n );\n\n // Resolve credentials on mount, then either show the picker or move on.\n useEffect(() => {\n void (async () => {\n try {\n if (credentialsPath !== undefined) {\n // loadCredentialsFromFile throws on a missing/invalid file; wrap it so\n // the error frame shows which path failed rather than a raw ENOENT.\n let creds: Credentials;\n\n try {\n creds = await loadCredentialsFromFile(credentialsPath);\n } catch (err) {\n throw new Error(\n `Could not load credentials from ${credentialsPath}: ${\n err instanceof Error ? err.message : String(err)\n }`,\n );\n }\n\n setCredentials(creds);\n proceed(creds, apiName, secret);\n\n return;\n }\n\n const profiles = await listCredentialProfiles();\n\n if (profiles.length === 0) {\n throw new Error(\n 'No credential profiles found. Create ~/.kizenappbuilder/credentials.json first.',\n );\n }\n\n const [only] = profiles;\n\n if (profiles.length === 1 && only !== undefined) {\n const creds = only.isDefault\n ? await loadGlobalCredentials()\n : await loadCredentialProfile(only.name);\n\n if (creds === null) {\n throw new Error(`Could not load credential profile: ${only.name}`);\n }\n\n setCredentials(creds);\n proceed(creds, apiName, secret);\n\n return;\n }\n\n setPhase({ type: 'profile-select', profiles, cursor: 0 });\n } catch (err) {\n fail(err);\n }\n })();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n // Exit only once a terminal frame has been committed and written to the\n // terminal. Calling app.exit() in the same tick as the setPhase would unmount\n // ink before it paints the done/error frame, leaving the spinner as the last\n // thing on screen.\n useEffect(() => {\n if (phase.type === 'done' || phase.type === 'error') {\n app.exit();\n }\n }, [phase, app]);\n\n useInput((input, key) => {\n if (key.ctrl && input === 'c') {\n process.exitCode = 130;\n app.exit();\n\n return;\n }\n\n if (phase.type === 'profile-select') {\n const { profiles, cursor } = phase;\n\n if (key.upArrow) {\n setPhase({ ...phase, cursor: (cursor - 1 + profiles.length) % profiles.length });\n } else if (key.downArrow) {\n setPhase({ ...phase, cursor: (cursor + 1) % profiles.length });\n } else if (key.return) {\n // cursor is kept in range by the modulo above, so this is always defined.\n const selected = profiles[cursor];\n\n if (selected !== undefined) {\n void handleProfileChosen(selected);\n }\n }\n\n return;\n }\n\n if (phase.type === 'api-name-entry') {\n const { buffer } = phase;\n\n if (key.backspace || key.delete) {\n setPhase({ type: 'api-name-entry', buffer: buffer.slice(0, -1) });\n } else if (key.return) {\n const name = buffer.trim();\n\n if (name === '') {\n setPhase({ type: 'api-name-entry', buffer, error: 'api_name cannot be empty' });\n\n return;\n }\n\n setApiName(name);\n\n if (credentials) {\n proceed(credentials, name, secret);\n } else {\n fail(new Error('Internal error: credentials were not loaded'));\n }\n } else if (input && !key.ctrl && !key.meta) {\n setPhase({ type: 'api-name-entry', buffer: buffer + input });\n }\n\n return;\n }\n\n if (phase.type === 'value-entry') {\n const { buffer } = phase;\n\n if (key.backspace || key.delete) {\n setPhase({ type: 'value-entry', buffer: buffer.slice(0, -1) });\n } else if (key.return) {\n if (buffer === '') {\n setPhase({ type: 'value-entry', buffer, error: 'secret cannot be empty' });\n\n return;\n }\n\n setSecret(buffer);\n\n if (credentials) {\n proceed(credentials, apiName, buffer);\n } else {\n fail(new Error('Internal error: credentials were not loaded'));\n }\n } else if (input && !key.ctrl && !key.meta) {\n setPhase({ type: 'value-entry', buffer: buffer + input });\n }\n\n return;\n }\n });\n\n const modeLabel = ctx.isRemote ? 'remote Kizen API' : 'on-machine';\n\n const stageLabel = stageDefaulted === true ? `${ctx.stage} (default)` : ctx.stage;\n\n const frame = (children: ReactNode): ReactNode => (\n <Box flexDirection=\"column\" paddingY={1} paddingX={2} gap={1}>\n <AppHeader />\n <Text dimColor>\n Mode: {modeLabel} Stage: {stageLabel}\n </Text>\n {children}\n </Box>\n );\n\n if (phase.type === 'loading') {\n return frame(\n <Box gap={1}>\n <Spinner />\n <Text dimColor>Loading credentials…</Text>\n </Box>,\n );\n }\n\n if (phase.type === 'profile-select') {\n const { profiles, cursor } = phase;\n\n return frame(\n <>\n <Text bold>Credential profile</Text>\n <Box flexDirection=\"column\">\n {profiles.map((profile, i) => {\n const selected = cursor === i;\n\n return (\n <Box key={profile.name} gap={2}>\n <Text {...(selected && { color: 'cyan' as const })}>{selected ? '❯' : ' '}</Text>\n <Text bold={selected} {...(selected && { color: 'cyan' as const })}>\n {profile.isDefault ? 'Default' : profile.name}\n </Text>\n <Text dimColor>{profile.path}</Text>\n </Box>\n );\n })}\n </Box>\n <Hint text=\"↑↓ to move · Enter to select · Ctrl+C to quit\" />\n </>,\n );\n }\n\n if (phase.type === 'api-name-entry') {\n return frame(\n <>\n <Text bold>Plugin api_name</Text>\n {phase.error !== undefined && <Text color=\"red\">Error: {phase.error}</Text>}\n <Box gap={1}>\n <Text color=\"cyan\">{'>'}</Text>\n <Text>{phase.buffer}</Text>\n <Text color=\"cyan\">█</Text>\n </Box>\n <Hint text=\"Type the api_name · Enter to confirm · Ctrl+C to quit\" />\n </>,\n );\n }\n\n if (phase.type === 'value-entry') {\n return frame(\n <>\n <Text bold>Secret value</Text>\n {phase.error !== undefined && <Text color=\"red\">Error: {phase.error}</Text>}\n <Box gap={1}>\n <Text color=\"cyan\">{'>'}</Text>\n <Text>{'•'.repeat(phase.buffer.length)}</Text>\n <Text color=\"cyan\">█</Text>\n </Box>\n <Hint text=\"Input hidden · Enter to encrypt · Ctrl+C to quit\" />\n </>,\n );\n }\n\n if (phase.type === 'fetching-key') {\n return frame(\n <Box gap={1}>\n <Spinner />\n <Text>\n Fetching {ctx.stage} public key for <Text bold>{apiName}</Text>…\n </Text>\n </Box>,\n );\n }\n\n if (phase.type === 'encrypting') {\n return frame(\n <Box gap={1}>\n <Spinner />\n <Text>Encrypting…</Text>\n </Box>,\n );\n }\n\n if (phase.type === 'error') {\n return frame(\n <Box gap={1}>\n <Text color=\"red\">✗</Text>\n <Text color=\"red\">{phase.message}</Text>\n </Box>,\n );\n }\n\n // phase.type === 'done'\n return frame(\n <>\n <Box gap={1}>\n <Text color=\"green\">✓</Text>\n <Text bold>Encrypted secret ready</Text>\n </Box>\n {phase.copied ? (\n <Text color=\"green\">\n ✓ Copied to clipboard — paste it into the secret value in your kizen.json.\n </Text>\n ) : (\n <Text dimColor>\n {'Paste this into the secret value in your kizen.json (re-run with --out <path> to save ' +\n 'it to a file; selecting it here may capture line wraps):'}\n </Text>\n )}\n <Text>{phase.envelope}</Text>\n </>,\n );\n};\n","/**\n * Network + crypto helpers for the `encrypt` command, shared between the ink UI\n * and any non-interactive callers. Keeping these out of the React tree means the\n * dev/prod routing and envelope handling live in one testable place. KZN-16467.\n *\n * Both modes talk to the encryption API (plugin-wizard) DIRECTLY via\n * `resolveWizardBase(stage)` — the app-builder dev server is never involved, so\n * `appbuilder encrypt` works without `appbuilder dev` running:\n * - on-machine (default): fetch the public key, then encrypt in-process.\n * - remote (`--remote`): POST the plaintext to the wizard's /encrypt endpoint\n * and let it do the crypto with the keypair it already holds.\n */\nimport { encrypt, serializeEnvelope } from '@kizenapps/packager';\nimport type { Credentials } from './credentials.js';\nimport { getProxyEnvStatus, PROXY_UNAVAILABLE_HINT } from './proxyEnv.js';\nimport { resolveWizardBase } from './wizardUrl.js';\n\nexport interface EncryptionContext {\n /**\n * When true, the wizard's /encrypt endpoint performs the encryption; otherwise\n * we fetch the public key and encrypt on-machine. Either way the request goes\n * straight to the wizard host — never through the app-builder dev server.\n */\n isRemote: boolean;\n /** Which encryption API to target. */\n stage: 'dev' | 'prod';\n}\n\n/** Phases reported while encrypting, so a UI can show progress. */\nexport type EncryptPhase = 'fetching-key' | 'encrypting';\n\n/**\n * Node's fetch (undici) wraps socket failures in a generic `TypeError: fetch\n * failed`, stashing the real error (with its `code`) on `.cause`. Look in both\n * places so we can surface a friendlier \"not running\" message.\n */\nfunction isConnRefused(err: unknown): boolean {\n const e = err as { code?: string; cause?: { code?: string } };\n\n return e.code === 'ECONNREFUSED' || e.cause?.code === 'ECONNREFUSED';\n}\n\nfunction authHeaders(credentials: Credentials): Record<string, string> {\n return {\n 'Content-Type': 'application/json',\n 'x-api-key': credentials.apiKey,\n 'x-user-id': credentials.userId,\n 'x-business-id': credentials.businessId,\n 'x-auth-environment': credentials.environment,\n };\n}\n\n/** Wraps a fetch to the wizard so connection failures read clearly. */\nasync function wizardFetch(wizardBase: string, path: string, init: RequestInit): Promise<Response> {\n try {\n return await fetch(`${wizardBase}${path}`, init);\n } catch (err) {\n throw new Error(\n isConnRefused(err)\n ? `Plugin-wizard is not running at ${wizardBase}`\n : `Failed to reach plugin-wizard: ${(err as Error).message}${getProxyEnvStatus() === 'unavailable' ? ` ${PROXY_UNAVAILABLE_HINT}` : ''}`,\n );\n }\n}\n\n/**\n * Parses a wizard JSON response without throwing on a non-JSON body. Upstream\n * errors can arrive as HTML 502 pages, plain-text 429s, or an auth 401 raised\n * before the JSON handler runs — calling res.json() on those would throw an\n * opaque SyntaxError and hide the real status. Returning {} lets callers fall\n * back to a clear HTTP-status error.\n */\nasync function readJsonSafe(res: Response): Promise<Record<string, unknown>> {\n const text = await res.text();\n\n if (text === '') {\n return {};\n }\n\n try {\n const parsed = JSON.parse(text) as unknown;\n\n return typeof parsed === 'object' && parsed !== null ? (parsed as Record<string, unknown>) : {};\n } catch {\n return {};\n }\n}\n\n/**\n * Fetches the public key for a plugin directly from the wizard host. Used by the\n * on-machine encryption path.\n */\nexport async function fetchPublicKey(\n ctx: EncryptionContext,\n credentials: Credentials,\n apiName: string,\n): Promise<string> {\n const wizardBase = resolveWizardBase(ctx.stage);\n const res = await wizardFetch(wizardBase, '/get-public-key', {\n method: 'POST',\n headers: authHeaders(credentials),\n body: JSON.stringify({ api_name: apiName }),\n });\n\n const data = await readJsonSafe(res);\n\n if (!res.ok || typeof data.public_key !== 'string') {\n const errMsg = typeof data.error === 'string' ? data.error : `HTTP ${String(res.status)}`;\n\n throw new Error(`Failed to fetch public key: ${errMsg}`);\n }\n\n return data.public_key;\n}\n\n/** Encrypts a value in-process via @kizenapps/packager and returns the\n * serialized envelope's base64 `value`. */\nfunction encryptLocally(publicKeyPem: string, value: string): string {\n const envelope = encrypt(value, publicKeyPem);\n const serialized = serializeEnvelope(envelope) as { encrypted?: boolean; value?: unknown };\n\n if (typeof serialized.value !== 'string') {\n throw new Error('Unexpected serialized envelope shape from @kizenapps/packager');\n }\n\n return serialized.value;\n}\n\n/**\n * Asks the wizard's /encrypt endpoint to encrypt the value with the keypair it\n * holds for `apiName`, returning the serialized envelope's base64 `value`. The\n * wizard fetches its own public key, so no separate get-public-key call is made.\n */\nasync function encryptRemote(\n ctx: EncryptionContext,\n credentials: Credentials,\n apiName: string,\n value: string,\n): Promise<string> {\n const wizardBase = resolveWizardBase(ctx.stage);\n const res = await wizardFetch(wizardBase, '/encrypt', {\n method: 'POST',\n headers: authHeaders(credentials),\n body: JSON.stringify({ api_name: apiName, value }),\n });\n\n const data = await readJsonSafe(res);\n\n if (!res.ok || data.encrypted !== true || typeof data.value !== 'string') {\n const errMsg = typeof data.error === 'string' ? data.error : `HTTP ${String(res.status)}`;\n\n throw new Error(`Encryption via plugin-wizard failed: ${errMsg}`);\n }\n\n return data.value;\n}\n\nexport async function encryptSecret(\n ctx: EncryptionContext,\n credentials: Credentials,\n apiName: string,\n value: string,\n onPhase?: (phase: EncryptPhase) => void,\n): Promise<string> {\n if (ctx.isRemote) {\n onPhase?.('encrypting');\n\n return encryptRemote(ctx, credentials, apiName, value);\n }\n\n onPhase?.('fetching-key');\n\n const publicKey = await fetchPublicKey(ctx, credentials, apiName);\n\n onPhase?.('encrypting');\n\n return encryptLocally(publicKey, value);\n}\n","import { readFile, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nexport type EncryptStage = 'dev' | 'prod';\n\nexport function envelopeObject(value: string): { encrypted: true; value: string } {\n return { encrypted: true, value };\n}\n\nexport function compactEnvelope(value: string): string {\n return JSON.stringify(envelopeObject(value));\n}\n\nexport async function writeEnvelopeFile(path: string, value: string): Promise<void> {\n await writeFile(path, `${JSON.stringify(envelopeObject(value), null, 2)}\\n`, 'utf-8');\n}\n\nexport interface ManifestDefaults {\n apiName?: string;\n}\n\nexport const DEFAULT_STAGE: EncryptStage = 'prod';\n\nexport function isValidStage(stage: string): stage is EncryptStage {\n return stage === 'dev' || stage === 'prod';\n}\n\nexport function invalidStageMessage(stage: string): string {\n return `Error: --stage must be \"dev\" or \"prod\" (got: \"${stage}\")`;\n}\n\nexport function resolveStage(stage: string | undefined): {\n stage: EncryptStage;\n wasDefaulted: boolean;\n} {\n return {\n stage: stage === 'dev' || stage === 'prod' ? stage : DEFAULT_STAGE,\n wasDefaulted: stage === undefined,\n };\n}\n\nexport function defaultStageNotice(stage: EncryptStage): string {\n return `No --stage given; defaulting to ${stage} encryption keys (pass --stage dev to override)\\n`;\n}\n\nexport async function readManifestDefaults(cwd: string = process.cwd()): Promise<ManifestDefaults> {\n try {\n const raw = await readFile(join(cwd, 'kizen.json'), 'utf-8');\n const parsed = JSON.parse(raw) as unknown;\n const manifest = (Array.isArray(parsed) ? parsed[0] : parsed) as Record<string, unknown>;\n\n const apiName =\n typeof manifest.api_name === 'string' && manifest.api_name !== ''\n ? manifest.api_name\n : undefined;\n\n return {\n ...(apiName !== undefined && { apiName }),\n };\n } catch {\n // Not in a plugin directory — fine, the UI will prompt with no defaults.\n }\n\n return {};\n}\n\nexport function stripTrailingNewlines(value: string): string {\n return value.replace(/[\\r\\n]+$/, '');\n}\n\nexport async function readStdin(): Promise<string> {\n const chunks: Buffer[] = [];\n\n for await (const chunk of process.stdin) {\n chunks.push(chunk as Buffer);\n }\n\n return Buffer.concat(chunks).toString('utf-8');\n}\n","import type { EncryptionContext } from './encryptionClient.js';\nimport type { Credentials } from './credentials.js';\nimport type { ManifestDefaults } from './encryptHelpers.js';\nimport { compactEnvelope, defaultStageNotice, stripTrailingNewlines } from './encryptHelpers.js';\n\nexport interface HeadlessEncryptOptions {\n credentials?: string;\n apiName?: string;\n value?: string;\n out?: string;\n}\n\nexport interface HeadlessEncryptDeps {\n loadCredentialsFromFile: (path: string) => Promise<Credentials>;\n loadGlobalCredentials: () => Promise<Credentials | null>;\n encryptSecret: (\n ctx: EncryptionContext,\n credentials: Credentials,\n apiName: string,\n value: string,\n ) => Promise<string>;\n readStdin: () => Promise<string>;\n stdinIsTTY: () => boolean;\n writeStdout: (text: string) => void;\n writeStderr: (text: string) => void;\n writeEnvelopeFile: (path: string, value: string) => Promise<void>;\n setExitCode: (code: number) => void;\n}\n\nexport async function runHeadless(\n ctx: EncryptionContext,\n options: HeadlessEncryptOptions,\n defaults: ManifestDefaults,\n stageWasDefaulted: boolean,\n deps: HeadlessEncryptDeps,\n): Promise<void> {\n const credentials =\n options.credentials !== undefined\n ? await deps.loadCredentialsFromFile(options.credentials)\n : await deps.loadGlobalCredentials();\n\n if (credentials === null) {\n throw new Error(\n 'No credentials found. Pass --credentials or create ~/.kizenappbuilder/credentials.json.',\n );\n }\n\n const apiName = options.apiName ?? defaults.apiName;\n\n if (apiName === undefined || apiName.trim() === '') {\n throw new Error(\n 'api_name is required in non-interactive mode. Pass --api-name or run inside a plugin directory.',\n );\n }\n\n if (stageWasDefaulted) {\n deps.writeStderr(defaultStageNotice(ctx.stage));\n }\n\n let value = options.value;\n\n if (value === undefined) {\n if (deps.stdinIsTTY()) {\n throw new Error(\n 'No secret provided and stdin is a terminal. Pass --value, or pipe the secret in ' +\n '(e.g. `printf %s \"$SECRET\" | npx --yes @kizenapps/cli encrypt …`).',\n );\n }\n\n deps.writeStderr('Reading secret from stdin (pass --value to skip)…\\n');\n\n value = stripTrailingNewlines(await deps.readStdin());\n }\n\n if (value === '') {\n throw new Error('A secret value is required. Pass --value or pipe it via stdin.');\n }\n\n const envelopeValue = await deps.encryptSecret(ctx, credentials, apiName.trim(), value);\n\n deps.writeStdout(`${compactEnvelope(envelopeValue)}\\n`);\n\n if (options.out !== undefined) {\n try {\n await deps.writeEnvelopeFile(options.out, envelopeValue);\n deps.writeStderr(`Wrote encrypted envelope to ${options.out}\\n`);\n } catch (err) {\n deps.writeStderr(\n `Error writing ${options.out}: ${err instanceof Error ? err.message : String(err)}\\n`,\n );\n deps.setExitCode(1);\n }\n }\n}\n","export const VALID_ICONS = new Set([\n 'phone',\n 'envelope',\n 'pen-nib',\n 'calendar-days',\n 'paperclip',\n 'file',\n 'clipboard',\n 'pen',\n 'tag',\n 'book',\n 'print',\n 'pen-to-square',\n 'folder',\n 'folder-open',\n 'thumbtack',\n 'globe',\n 'city',\n 'briefcase',\n 'compass',\n 'address-book',\n 'business-time',\n 'computer-classic',\n 'pen-fancy',\n 'badge-check',\n 'mug-saucer',\n 'landmark',\n 'chart-simple',\n 'envelopes',\n 'diagram-venn',\n 'calendar',\n 'pencil',\n 'phone-volume',\n 'copy',\n 'table',\n 'building',\n 'network-wired',\n 'address-card',\n 'tags',\n 'registered',\n 'signature',\n 'phone-office',\n 'projector',\n 'sitemap',\n 'marker',\n 'badge',\n 'wallet',\n 'copyright',\n 'bullseye',\n 'calculator',\n 'certificate',\n 'percent',\n 'eraser',\n 'file-spreadsheet',\n 'glasses',\n 'industry',\n 'vault',\n 'user-tie-hair-long',\n 'user-tie-hair',\n 'user-hair-mullet',\n 'trademark',\n 'timeline-arrow',\n 'timeline',\n 'table-tree',\n 'table-rows',\n 'table-pivot',\n 'table-layout',\n 'table-columns',\n 'stapler',\n 'square-poll-vertical',\n 'square-poll-horizontal',\n 'square-phone-flip',\n 'square-phone',\n 'square-pen',\n 'square-kanban',\n 'square-envelope',\n 'socks',\n 'slot-machine',\n 'signature-slash',\n 'signature-lock',\n 'shredder',\n 'scissors',\n 'scanner-image',\n 'scale-unbalanced-flip',\n 'scale-unbalanced',\n 'scale-balanced',\n 'router',\n 'rectangle-pro',\n 'print-slash',\n 'print-magnifying-glass',\n 'presentation-screen',\n 'podium',\n 'phone-slash',\n 'phone-intercom',\n 'phone-flip',\n 'person-chalkboard',\n 'pen-nib-slash',\n 'pen-clip',\n 'paste',\n 'paperclip-vertical',\n 'notebook',\n 'note-sticky',\n 'money-check-pen',\n 'money-check-dollar-pen',\n 'magnifying-glass-chart',\n 'magnifying-glass-arrow-right',\n 'list-tree',\n 'list-timeline',\n 'list-radio',\n 'list-dropdown',\n 'list-check',\n 'laptop-file',\n 'lamp-desk',\n 'keynote',\n 'industry-windows',\n 'inboxes',\n 'inbox-full',\n 'house-laptop',\n 'highlighter',\n 'folders',\n 'folder-xmark',\n 'folder-tree',\n 'folder-plus',\n 'folder-minus',\n 'folder-arrow-up',\n 'folder-arrow-down',\n 'floppy-disk-circle-xmark',\n 'floppy-disk-circle-arrow-right',\n 'floppy-disk',\n 'file-user',\n 'file-lines',\n 'file-circle-plus',\n 'file-circle-info',\n 'file-chart-pie',\n 'file-chart-column',\n 'fax',\n 'envelope-open',\n 'envelope-dot',\n 'envelope-circle-check',\n 'coffee-pot',\n 'cloud-word',\n 'clipboard-question',\n 'chart-user',\n 'chart-tree-map',\n 'chart-simple-horizontal',\n 'chart-pyramid',\n 'chart-pie-simple',\n 'chart-pie',\n 'chart-line-up',\n 'chart-line-down',\n 'chart-line',\n 'cake-candles',\n 'cabinet-filing',\n 'bullhorn',\n 'briefcase-blank',\n 'briefcase-arrow-right',\n 'brain-arrow-curved-right',\n 'boxes-packing',\n 'box-archive',\n 'book-section',\n 'bars-staggered',\n 'bars-progress',\n 'badge-percent',\n 'badge-dollar',\n 'arrows-to-eye',\n 'arrows-to-dot',\n 'arrows-spin',\n 'sparkles',\n 'megaphone',\n 'block-question',\n 'lightbulb-slash',\n 'comments-dollar',\n 'comments',\n 'bullseye-pointer',\n 'lightbulb',\n 'user-group-crown',\n 'user-crown',\n 'signal-stream-slash',\n 'signal-stream',\n 'rectangle-ad',\n 'ranking-star',\n 'person-rays',\n 'people-group',\n 'messages-dollar',\n 'message-dollar',\n 'magnifying-glass-location',\n 'magnifying-glass-dollar',\n 'lightbulb-on',\n 'lightbulb-exclamation',\n 'lightbulb-dollar',\n 'lightbulb-cfl-on',\n 'lightbulb-cfl',\n 'hundred-points',\n 'group-arrows-rotate',\n 'gift-card',\n 'filter-circle-dollar',\n 'envelopes-bulk',\n 'envelope-open-text',\n 'envelope-open-dollar',\n 'comment-dollar',\n 'chart-mixed',\n 'bullseye-arrow',\n 'star',\n 'heart',\n 'camera-retro',\n 'truck-fast',\n 'bell',\n 'cart-shopping',\n 'gift',\n 'barcode',\n 'bookmark',\n 'camera',\n 'thumbs-up',\n 'thumbs-down',\n 'key',\n 'truck',\n 'balloons',\n 'handshake',\n 'shop',\n 'shirt',\n 'bag-shopping',\n 'moped',\n 'cart-plus',\n 'credit-card',\n 'store',\n 'cash-register',\n 'booth-curtain',\n 'trophy',\n 'receipt',\n 'truck-container',\n 'truck-clock',\n 'truck-bolt',\n 'trophy-star',\n 'store-slash',\n 'store-lock',\n 'star-exclamation',\n 'shop-slash',\n 'shop-lock',\n 'rectangle-barcode',\n 'person-booth',\n 'nfc-trash',\n 'nfc-symbol',\n 'nfc-slash',\n 'nfc-signal',\n 'nfc-pen',\n 'nfc-magnifying-glass',\n 'nfc-lock',\n 'nfc',\n 'money-check-dollar',\n 'money-check',\n 'mobile-signal-out',\n 'mobile-signal',\n 'hexagon-vertical-nft-slanted',\n 'hexagon-vertical-nft',\n 'hexagon-image',\n 'hand-holding-box',\n 'gifts',\n 'gem',\n 'credit-card-front',\n 'credit-card-blank',\n 'cart-xmark',\n 'cart-shopping-fast',\n 'cart-minus',\n 'cart-circle-xmark',\n 'cart-circle-plus',\n 'cart-circle-exclamation',\n 'cart-circle-check',\n 'cart-circle-arrow-up',\n 'cart-circle-arrow-down',\n 'cart-arrow-up',\n 'cart-arrow-down',\n 'box-open-full',\n 'basket-shopping-simple',\n 'basket-shopping',\n 'barcode-scan',\n 'barcode-read',\n 'balloon',\n 'bags-shopping',\n 'bars',\n 'browser',\n 'chart-bar',\n 'cog',\n 'database',\n 'calendar-alt',\n 'play',\n 'kizen-k',\n 'add',\n 'book-alt',\n 'form-entity',\n 'arrows-to-circle',\n 'question-circle',\n 'chevron-down',\n 'chevron-up',\n 'window-restore',\n 'forward',\n]);\n\nexport const VALID_ICONS_LIST = [...VALID_ICONS].sort();\n\n// Icons rendered as custom Kizen-brand React components — no FontAwesome equivalent.\nexport const CUSTOM_ICON_NAMES = new Set(['kizen-k', 'form-entity']);\n\nexport const ALL_VALID_ICONS_LIST = [...VALID_ICONS_LIST, ...[...CUSTOM_ICON_NAMES].sort()];\n","import type { Command } from 'commander';\nimport { ALL_VALID_ICONS_LIST } from '../../shared/lib/validIcons.js';\n\nexport function iconsCommand(program: Command): void {\n program\n .command('icons')\n .description('List all valid icon names accepted by toolbar items, pages, and adornments')\n .action(() => {\n for (const name of ALL_VALID_ICONS_LIST) {\n console.log(name);\n }\n });\n}\n","import { mkdir, writeFile, readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { Command } from 'commander';\nimport { readLocalFiles } from '../lib/readFiles.js';\nimport { GLOBAL_CREDENTIALS_DIR } from '../lib/credentials.js';\nimport { generateHtml, generateMarkdown } from '../lib/reportHelpers.js';\n\nconst EXAMPLES_DIR = join(GLOBAL_CREDENTIALS_DIR, 'examples');\n\nexport function reportCommand(program: Command): void {\n program\n .command('report')\n .description('Generate a self-contained HTML report of the plugin')\n .option('-o, --output <path>', `output file path (default: ${EXAMPLES_DIR}/<api_name>.html)`)\n .action(async (options: { output?: string }) => {\n const pluginDir = process.cwd();\n\n let manifest: Record<string, unknown>;\n\n try {\n const raw = await readFile(join(pluginDir, 'kizen.json'), 'utf-8');\n const parsed = JSON.parse(raw) as unknown;\n\n manifest = (Array.isArray(parsed) ? parsed[0] : parsed) as Record<string, unknown>;\n } catch {\n console.error('Error: kizen.json not found. Run this command from a plugin directory.');\n process.exit(1);\n }\n\n const apiName = typeof manifest.api_name === 'string' ? manifest.api_name : 'plugin';\n const htmlPath = options.output ?? join(EXAMPLES_DIR, `${apiName}.html`);\n const mdPath = htmlPath.replace(/\\.html$/, '.md');\n\n const files = await readLocalFiles(pluginDir, { detectBinaryByContent: true });\n\n await mkdir(join(htmlPath, '..'), { recursive: true });\n\n await Promise.all([\n writeFile(htmlPath, generateHtml(manifest, files), 'utf-8'),\n writeFile(mdPath, generateMarkdown(manifest, files), 'utf-8'),\n ]);\n\n console.log(`Plugin report written to:\\n ${htmlPath}\\n ${mdPath}`);\n });\n}\n","import type { FileContent } from '@kizenapps/packager';\n\nconst SENSITIVE_FIELDS = new Set(['developer_business_id']);\n\nexport function redactServices(services: unknown): unknown {\n if (!Array.isArray(services)) {\n return services;\n }\n\n return services.map((svc: unknown) => {\n if (typeof svc !== 'object' || svc === null) {\n return svc;\n }\n\n const s = svc as Record<string, unknown>;\n\n if (typeof s.auth_credentials !== 'object' || s.auth_credentials === null) {\n return s;\n }\n\n const redacted = Object.fromEntries(Object.keys(s.auth_credentials).map((k) => [k, '*****']));\n\n return { ...s, auth_credentials: redacted };\n });\n}\n\nexport interface TreeNode {\n name: string;\n children: Map<string, TreeNode>;\n isFile: boolean;\n filePath: string;\n}\n\nexport function buildTree(files: FileContent[]): TreeNode {\n const root: TreeNode = { name: '', children: new Map(), isFile: false, filePath: '' };\n\n for (const file of files) {\n const parts = file.path.split('/');\n let node = root;\n\n parts.forEach((part, i) => {\n if (!node.children.has(part)) {\n node.children.set(part, {\n name: part,\n children: new Map(),\n isFile: i === parts.length - 1,\n filePath: parts.slice(0, i + 1).join('/'),\n });\n }\n\n const next = node.children.get(part);\n\n if (next) {\n node = next;\n }\n });\n }\n\n return root;\n}\n\nfunction sortTreeChildren(node: TreeNode): TreeNode[] {\n return [...node.children.values()].sort((a, b) => {\n if (a.isFile !== b.isFile) {\n return a.isFile ? 1 : -1;\n }\n\n return a.name.localeCompare(b.name);\n });\n}\n\nexport function fileId(path: string): string {\n return 'file-' + path.replace(/[^a-zA-Z0-9]/g, '-');\n}\n\nexport function esc(str: string): string {\n return str\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"');\n}\n\nexport function fileExt(path: string): string {\n const idx = path.lastIndexOf('.');\n\n return idx >= 0 ? path.slice(idx).toLowerCase() : '';\n}\n\nconst LANG_MAP: Record<string, string> = {\n '.ts': 'typescript',\n '.tsx': 'typescript',\n '.js': 'javascript',\n '.jsx': 'javascript',\n '.mjs': 'javascript',\n '.cjs': 'javascript',\n '.json': 'json',\n '.css': 'css',\n '.scss': 'scss',\n '.html': 'html',\n '.htm': 'html',\n '.md': 'markdown',\n '.mdx': 'markdown',\n '.py': 'python',\n '.sh': 'bash',\n '.yml': 'yaml',\n '.yaml': 'yaml',\n '.xml': 'xml',\n '.toml': 'toml',\n};\n\nexport function mdLang(path: string): string {\n return LANG_MAP[fileExt(path)] ?? '';\n}\n\n// A fenced block must be delimited by more backticks than the longest run inside\n// it, or content that is itself markdown (a README with a code sample) escapes\n// its wrapper and corrupts the rest of the document.\nexport function mdFence(content: string): string {\n const longestRun = [...content.matchAll(/`+/g)].reduce((max, m) => Math.max(max, m[0].length), 0);\n\n return '`'.repeat(Math.max(3, longestRun + 1));\n}\n\nexport function renderTextTree(node: TreeNode, prefix = ''): string {\n const sorted = sortTreeChildren(node);\n\n return sorted\n .map((child, i) => {\n const isLast = i === sorted.length - 1;\n const connector = isLast ? '└── ' : '├── ';\n const childPrefix = isLast ? ' ' : '│ ';\n\n if (child.isFile) {\n return `${prefix}${connector}${child.name}`;\n }\n\n return `${prefix}${connector}${child.name}/\\n${renderTextTree(child, prefix + childPrefix)}`;\n })\n .join('\\n');\n}\n\nconst LICENSE_FILE = /(^|\\/)licen[cs]e(\\.md|\\.txt)?$/i;\n\nexport function filterSourceFiles(files: FileContent[]): FileContent[] {\n return files.filter(\n (f) => f.path !== 'kizen.json' && f.path !== 'plugin-report.html' && !LICENSE_FILE.test(f.path),\n );\n}\n\nexport function buildFilteredConfig(manifest: Record<string, unknown>): Record<string, unknown> {\n return Object.fromEntries(\n Object.entries(manifest)\n .filter(([k]) => !SENSITIVE_FIELDS.has(k))\n .map(([k, v]) => [k, k === 'services' ? redactServices(v) : v]),\n );\n}\n\nconst IMAGE_MIME: Record<string, string> = {\n '.png': 'image/png',\n '.svg': 'image/svg+xml',\n '.jpg': 'image/jpeg',\n '.jpeg': 'image/jpeg',\n '.gif': 'image/gif',\n '.webp': 'image/webp',\n};\n\nfunction renderTree(node: TreeNode): string {\n const sorted = sortTreeChildren(node);\n const items = sorted.map((child) => {\n if (child.isFile) {\n return `<li class=\"tf\"><a href=\"#${fileId(child.filePath)}\" data-id=\"${fileId(child.filePath)}\">${esc(child.name)}</a></li>`;\n }\n\n return `<li class=\"td\"><span class=\"dn\">${esc(child.name)}/</span>${renderTree(child)}</li>`;\n });\n\n return `<ul>${items.join('')}</ul>`;\n}\n\nfunction renderFileSection(file: FileContent): string {\n let body: string;\n\n if (file.base64Image !== undefined) {\n const mime = IMAGE_MIME[fileExt(file.path)] ?? 'image/png';\n\n body = `<img src=\"data:${mime};base64,${file.base64Image}\" alt=\"${esc(file.path)}\" style=\"max-width:100%\">`;\n } else if (file.binaryData !== undefined) {\n body = `<p class=\"bin\">[Binary file: ${String(file.binaryData.length)} bytes]</p>`;\n } else {\n body = `<pre><code>${esc(file.content)}</code></pre>`;\n }\n\n return `<section id=\"${fileId(file.path)}\"><h2 class=\"fp\">${esc(file.path)}</h2><div class=\"fb\">${body}</div></section>`;\n}\n\nexport function generateMarkdown(manifest: Record<string, unknown>, files: FileContent[]): string {\n const filtered = buildFilteredConfig(manifest);\n const name = typeof manifest.name === 'string' ? manifest.name : 'Plugin';\n const version = typeof manifest.version === 'string' ? manifest.version : '';\n const description = typeof manifest.description === 'string' ? manifest.description : '';\n const sourceFiles = filterSourceFiles(files);\n\n const lines: string[] = [];\n\n lines.push(`# ${name}${version ? ` v${version}` : ''}`);\n if (description) {\n lines.push('', description);\n }\n\n const configJson = JSON.stringify(filtered, null, 2);\n const configFence = mdFence(configJson);\n\n lines.push(\n '',\n '## Configuration (`kizen.json`)',\n '',\n `${configFence}json`,\n configJson,\n configFence,\n );\n\n lines.push('', '## File Tree', '', '```', renderTextTree(buildTree(sourceFiles)), '```');\n\n lines.push('', '## Files');\n\n for (const file of sourceFiles) {\n lines.push('', `### \\`${file.path}\\``, '');\n\n if (file.base64Image !== undefined) {\n lines.push(`[Image file: ${file.path}]`);\n } else if (file.binaryData !== undefined) {\n lines.push(`[Binary file: ${String(file.binaryData.length)} bytes]`);\n } else {\n const fence = mdFence(file.content);\n\n lines.push(`${fence}${mdLang(file.path)}`, file.content, fence);\n }\n }\n\n return lines.join('\\n') + '\\n';\n}\n\nexport function generateHtml(manifest: Record<string, unknown>, files: FileContent[]): string {\n const filtered = buildFilteredConfig(manifest);\n const name = typeof manifest.name === 'string' ? manifest.name : 'Plugin';\n const version = typeof manifest.version === 'string' ? manifest.version : '';\n const description = typeof manifest.description === 'string' ? manifest.description : '';\n\n const sourceFiles = filterSourceFiles(files);\n const treeHtml = renderTree(buildTree(sourceFiles));\n const fileSections = sourceFiles.map(renderFileSection).join('\\n');\n\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">\n<title>${esc(name)} — Plugin Report</title>\n<style>\n*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}\n:root{\n --bg:#1e1e2e;--sb:#181825;--hd:#11111b;--tx:#cdd6f4;--mu:#6c7086;\n --ac:#89b4fa;--gr:#a6e3a1;--bd:#313244;--cb:#181825;--sw:280px;\n --fn:'Menlo','Consolas','Monaco',monospace;\n}\nhtml{font-size:14px}\nbody{background:var(--bg);color:var(--tx);font-family:var(--fn);display:flex;flex-direction:column;height:100vh}\nheader{background:var(--hd);border-bottom:1px solid var(--bd);padding:14px 20px;flex-shrink:0}\nheader h1{font-size:1.1rem;color:var(--ac)}\nheader p{color:var(--mu);font-size:.85rem;margin-top:3px}\n.layout{display:flex;flex:1;overflow:hidden}\nnav{width:var(--sw);background:var(--sb);border-right:1px solid var(--bd);overflow-y:auto;padding:12px 0;flex-shrink:0}\nnav a.cfg{display:block;padding:6px 16px;color:var(--gr);text-decoration:none;font-size:.85rem}\nnav a.cfg:hover,nav a.cfg.active{background:var(--bd)}\nnav ul{list-style:none;padding-left:0}\n.td>.dn{display:block;padding:4px 16px;color:var(--mu);font-size:.8rem}\n.td ul{padding-left:14px}\n.tf a{display:block;padding:3px 16px;color:var(--tx);text-decoration:none;font-size:.8rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.tf a:hover,.tf a.active{background:var(--bd);color:var(--ac)}\nmain{flex:1;overflow-y:auto;padding:0 24px 40px}\nsection{padding:32px 0;border-bottom:1px solid var(--bd)}\nh2.fp{font-size:.9rem;color:var(--ac);margin-bottom:12px;word-break:break-all}\n#config h2.fp{color:var(--gr)}\npre{background:var(--cb);border:1px solid var(--bd);border-radius:6px;padding:14px;overflow-x:auto;font-size:.78rem;line-height:1.6;white-space:pre}\ncode{font-family:var(--fn)}\nimg{border:1px solid var(--bd);border-radius:4px}\n.bin{color:var(--mu);font-style:italic;padding:12px 0}\n::-webkit-scrollbar{width:6px;height:6px}\n::-webkit-scrollbar-track{background:transparent}\n::-webkit-scrollbar-thumb{background:var(--bd);border-radius:3px}\n</style>\n</head>\n<body>\n<header>\n <h1>${esc(name)}${version ? ` <span style=\"color:var(--mu);font-size:.8em\">v${esc(version)}</span>` : ''}</h1>\n ${description ? `<p>${esc(description)}</p>` : ''}\n</header>\n<div class=\"layout\">\n<nav>\n <a href=\"#config\" class=\"cfg\" data-id=\"config\">kizen.json (config)</a>\n ${treeHtml}\n</nav>\n<main>\n<section id=\"config\"><h2 class=\"fp\">kizen.json — Plugin Configuration</h2><div class=\"fb\"><pre><code>${esc(JSON.stringify(filtered, null, 2))}</code></pre></div></section>\n${fileSections}\n</main>\n</div>\n<script>\n(function(){\n var links=document.querySelectorAll('[data-id]');\n function setActive(id){links.forEach(function(l){l.classList.toggle('active',l.getAttribute('data-id')===id);})}\n links.forEach(function(l){l.addEventListener('click',function(){setActive(this.getAttribute('data-id'));});});\n var obs=new IntersectionObserver(function(es){es.forEach(function(e){if(e.isIntersecting)setActive(e.target.id);});},{rootMargin:'-20% 0px -70% 0px'});\n document.querySelectorAll('section[id]').forEach(function(s){obs.observe(s);});\n})();\n</script>\n</body>\n</html>`;\n}\n","import type { Command } from 'commander';\nimport { runSetupClaude } from '../lib/setupClaude.js';\n\nexport function setupClaudeCommand(program: Command): void {\n program\n .command('setup-claude')\n .description('Install or refresh the Claude Code skill for building custom blocks')\n .option('--dry-run', 'report what would change without writing files')\n .action(async (options: { dryRun?: boolean }) => {\n await runSetupClaude(process.cwd(), options);\n });\n}\n"],"mappings":"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AAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ECAA,IAAAC,GAAA,g2GCAA,IAAAC,GAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ECAA,IAAAC,GAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ECAA,IAAAC,GAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;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,IAAKkB,CAAa,EAClD,QAAQ,OAAO,MAAM,+BAA+BlB,EAAQ,GAAG;AAAA,CAAI,CACrE,OAASiB,EAAK,CACZ,QAAQ,MACN,iBAAiBjB,EAAQ,GAAG,KAAKiB,aAAe,MAAQA,EAAI,QAAU,OAAOA,CAAG,CAAC,EACnF,EACA,QAAQ,SAAW,CACrB,CAEJ,CAAC,CACL,CK5HO,IAAMO,GAAc,IAAI,IAAI,CACjC,QACA,WACA,UACA,gBACA,YACA,OACA,YACA,MACA,MACA,OACA,QACA,gBACA,SACA,cACA,YACA,QACA,OACA,YACA,UACA,eACA,gBACA,mBACA,YACA,cACA,aACA,WACA,eACA,YACA,eACA,WACA,SACA,eACA,OACA,QACA,WACA,gBACA,eACA,OACA,aACA,YACA,eACA,YACA,UACA,SACA,QACA,SACA,YACA,WACA,aACA,cACA,UACA,SACA,mBACA,UACA,WACA,QACA,qBACA,gBACA,mBACA,YACA,iBACA,WACA,aACA,aACA,cACA,eACA,gBACA,UACA,uBACA,yBACA,oBACA,eACA,aACA,gBACA,kBACA,QACA,eACA,kBACA,iBACA,WACA,WACA,gBACA,wBACA,mBACA,iBACA,SACA,gBACA,cACA,yBACA,sBACA,SACA,cACA,iBACA,aACA,oBACA,gBACA,WACA,QACA,qBACA,WACA,cACA,kBACA,yBACA,yBACA,+BACA,YACA,gBACA,aACA,gBACA,aACA,cACA,YACA,UACA,mBACA,UACA,aACA,eACA,cACA,UACA,eACA,cACA,cACA,eACA,kBACA,oBACA,2BACA,iCACA,cACA,YACA,aACA,mBACA,mBACA,iBACA,oBACA,MACA,gBACA,eACA,wBACA,aACA,aACA,qBACA,aACA,iBACA,0BACA,gBACA,mBACA,YACA,gBACA,kBACA,aACA,eACA,iBACA,WACA,kBACA,wBACA,2BACA,gBACA,cACA,eACA,iBACA,gBACA,gBACA,eACA,gBACA,gBACA,cACA,WACA,YACA,iBACA,kBACA,kBACA,WACA,mBACA,YACA,mBACA,aACA,sBACA,gBACA,eACA,eACA,cACA,eACA,kBACA,iBACA,4BACA,0BACA,eACA,wBACA,mBACA,mBACA,gBACA,iBACA,sBACA,YACA,uBACA,iBACA,qBACA,uBACA,iBACA,cACA,iBACA,OACA,QACA,eACA,aACA,OACA,gBACA,OACA,UACA,WACA,SACA,YACA,cACA,MACA,QACA,WACA,YACA,OACA,QACA,eACA,QACA,YACA,cACA,QACA,gBACA,gBACA,SACA,UACA,kBACA,cACA,aACA,cACA,cACA,aACA,mBACA,aACA,YACA,oBACA,eACA,YACA,aACA,YACA,aACA,UACA,uBACA,WACA,MACA,qBACA,cACA,oBACA,gBACA,+BACA,uBACA,gBACA,mBACA,QACA,MACA,oBACA,oBACA,aACA,qBACA,aACA,oBACA,mBACA,0BACA,oBACA,uBACA,yBACA,gBACA,kBACA,gBACA,yBACA,kBACA,eACA,eACA,UACA,gBACA,OACA,UACA,YACA,MACA,WACA,eACA,OACA,UACA,MACA,WACA,cACA,mBACA,kBACA,eACA,aACA,iBACA,SACF,CAAC,EAEYC,GAAmB,CAAC,GAAGD,EAAW,EAAE,KAAK,EAGzCE,GAAoB,IAAI,IAAI,CAAC,UAAW,aAAa,CAAC,EAEtDC,GAAuB,CAAC,GAAGF,GAAkB,GAAG,CAAC,GAAGC,EAAiB,EAAE,KAAK,CAAC,EC3SnF,SAASE,GAAaC,EAAwB,CACnDA,EACG,QAAQ,OAAO,EACf,YAAY,4EAA4E,EACxF,OAAO,IAAM,CACZ,QAAWC,KAAQC,GACjB,QAAQ,IAAID,CAAI,CAEpB,CAAC,CACL,CCZA,OAAS,SAAAE,GAAO,aAAAC,GAAW,YAAAC,OAAgB,cAC3C,OAAS,QAAAC,OAAY,OCCrB,IAAMC,GAAmB,IAAI,IAAI,CAAC,uBAAuB,CAAC,EAEnD,SAASC,GAAeC,EAA4B,CACzD,OAAK,MAAM,QAAQA,CAAQ,EAIpBA,EAAS,IAAKC,GAAiB,CACpC,GAAI,OAAOA,GAAQ,UAAYA,IAAQ,KACrC,OAAOA,EAGT,IAAMC,EAAID,EAEV,GAAI,OAAOC,EAAE,kBAAqB,UAAYA,EAAE,mBA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","names":["http","PROXY_UNAVAILABLE_HINT","PROXY_VARS","isSet","value","status","applyProxyFromEnv","env","http","name","getProxyEnvStatus","readFileSync","dirname","join","fileURLToPath","Command","createElement","render","PluginValidationError","spawn","platform","clipboardCommands","CLIPBOARD_TIMEOUT_MS","runClipboardCommand","text","cmd","args","resolve","child","spawned","settled","finish","ok","timer","code","copyToClipboard","command","BLOCKS_DIRECTORY_NAME","CONFIG_FILE_NAME","MANIFEST_FILE_NAME","sanitizeToAPIName","mkdir","writeFile","join","PluginValidationError","packagePlugin","parseManifestFromFiles","transformDeployablePlugin","transformFiles","validatePluginApp","readdir","readFile","join","relative","IMAGE_EXTENSIONS","BINARY_EXTENSIONS","SKIP_FILES","SKIP_DIRS","BINARY_SNIFF_BYTES","looksBinary","buf","walk","dir","rootDir","entries","paths","entry","readLocalFiles","detectBinaryByContent","absolutePaths","absPath","relPath","dotIndex","ext","serializePlugin","plugin","allReleaseNotes","packageLocalPlugin","pluginDir","onStep","files","readLocalFiles","issues","validatePluginApp","issue","PluginValidationError","minified","transformFiles","manifests","parseManifestFromFiles","packaged","packagePlugin","deployable","transformDeployablePlugin","runBuild","outputDir","mkdir","bundle","notesDir","f","a","b","jsonStr","stripReleaseNotes","key","value","bundleSize","writeFile","join","DIMENSION_FIELDS","DIMENSION_RANGES","DEFAULT_SIZE_BOUNDS","DEFAULT_SIZE_FIELDS","SIZE_FIELDS","AUTHORED_FIELDS","UNSUPPORTED_SEQUENCES","BlockExportError","reason","message","options","formatAvailableBlocks","available","multiplePlugins","entry","selectBlock","deployable","apiName","candidates","plugin","block","pluginApiName","only","matches","match","isRecord","value","isPositiveInteger","hasUnsupportedContent","sequence","findInvalidBlockField","raw","name","script","styles","eventScripts","invalidEntry","eventName","body","unsupported","invalidDimension","field","invertedMin","minField","maxField","min","max","invalidDefault","invalidBlockMessage","range","selectionError","selection","list","parseJsonRecord","content","parsed","manifestEntries","files","manifestFile","file","MANIFEST_FILE_NAME","manifests","entries","manifest","authoredBlockConfig","prefix","BLOCKS_DIRECTORY_NAME","authoredByApiName","directory","fileName","rest","CONFIG_FILE_NAME","config","sanitizeToAPIName","authored","withAuthoredConfig","key","applyAuthoredConfig","packageBlocks","pluginDir","issues","packageLocalPlugin","issue","exportBlock","warnings","invalidField","plural","count","singular","pluralForm","groupIssuesByPath","issues","groups","issue","key","group","formatHeader","errorCount","warningCount","errors","formatValidationIssues","sections","path","randomUUID","join","PluginValidationError","BASE_URLS","APP_URLS","PRODUCTION_ENVIRONMENTS","isProductionEnvironment","env","mkdir","readFile","writeFile","join","loadConfig","outputDir","content","saveConfig","config","mkdir","readFile","readdir","writeFile","homedir","dirname","join","ENVIRONMENTS","cleanCredentialId","value","normalizeCredentialIds","values","GLOBAL_CREDENTIALS_DIR","join","homedir","GLOBAL_CREDENTIALS_PATH","DEFAULT_PROFILE_NAME","isValidEnvironment","value","ENVIRONMENTS","trimString","parseCredentials","raw","obj","env","normalizeCredentialIds","loadCredentialsFromFile","filePath","content","readFile","environmentSourceOf","loadCredentialsDetailed","loadGlobalCredentials","saveGlobalCredentials","credentials","mkdir","dirname","writeFile","getProfilePath","name","listCredentialProfiles","profiles","entries","readdir","entry","saveCredentialProfile","loadCredentialProfile","listLoadableCredentialProfiles","loadable","profile","_","index","fs","path","ensureGitignore","projectDir","gitignorePath","entry","contents","lines","l","addition","AUTH_FAILED_HINT","FORBIDDEN_HINT","MAX_PAGES","UNPREFIXED_KEYS","KizenApiError","kind","message","options","isRecord","value","collectMessages","prefix","out","push","text","texts","item","key","child","childPrefix","formatDrfError","body","messages","errorCause","err","e","readBody","res","statusError","method","path","status","detail","listResults","data","createKizenClient","credentials","fetchImpl","baseUrl","BASE_URLS","request","target","url","headers","init","getProxyEnvStatus","PROXY_UNAVAILABLE_HINT","json","segment","resolveNext","next","base","resolved","type","customObjectId","params","all","seen","page","id","business","clientObject","dashboardId","dashletId","createHash","mkdir","readFile","writeFile","dirname","join","PUSH_NAME_PREFIX","PUSH_MAP_RELATIVE_PATH","DIMENSION_KEYS","PUSH_MAP_STRING_FIELDS","isRecord","value","isFiniteNumber","clamp","min","max","withoutCustomObject","record","rest","pushKey","pluginApiName","blockApiName","parsePushKey","name","parts","pickDimensions","source","dimensions","key","pickHostChrome","toCustomCodeContent","block","script","buildDashletConfig","args","computeMaxBottom","dashlets","maxBottom","dashlet","layout","y","h","computeCreateLayout","content","layoutId","w","buildCreateBody","buildUpdateBody","existing","rawConfig","contentOf","config","isCustomCodeDashlet","findCustomCodeDashlets","dashboard","customCodeName","normalizeEventScripts","stringOr","candidate","entry","sortKeysDeep","sorted","nameOf","canonicalContentHash","canonical","createHash","matchPushTarget","mapped","named","first","detectDrift","matchesKey","findPushMapEntry","entries","upsertPushMapEntry","index","candidateIndex","removePushMapEntry","toPushMapEntry","field","cleanCredentialId","pushedAtTime","latestPerKey","byKey","id","current","isMissingFileError","error","pushMapErrorDetail","readPushMap","pluginDir","raw","readFile","join","parsed","writePushMap","filePath","mkdir","dirname","writeFile","DASHBOARD_TYPE_TO_SURFACE","SURFACE_TO_DASHBOARD_TYPE","dashboardTypeToSurface","type","surfaceToDashboardType","surface","buildDashboardUrl","base","access","mkdir","readFile","writeFile","dirname","join","posix","SKILL_default","design_default","copilot_instructions_default","security_instructions_default","version_discipline_instructions_default","kizenData_default","copilotFiles","copilot_instructions_default","security_instructions_default","version_discipline_instructions_default","KIZEN_DATA_LIB_FILE","kizenDataLibPath","entryDir","claudeFiles","entryDirs","SKILL_default","design_default","kizenData_default","CLAUDE_SKILL_PATH","STALE_CLAUDE_SKILL_WARNING","isMissing","error","nodeClaudeFs","path","readFile","content","mkdir","dirname","writeFile","access","normalizeEntryDir","entry","normalized","posix","entryDirsOf","manifest","entryDirs","entryDir","pluginClaudeFiles","dir","fs","join","claudeFiles","statusOf","current","bundled","planClaudeFiles","files","file","applyClaudeFiles","options","plan","_file","index","isClaudeSkillStale","managed","defaultSetupClaudeDeps","line","code","count","status","runSetupClaude","deps","dryRun","counts","createDefaultPushDeps","cwd","loadCredentialsDetailed","listLoadableCredentialProfiles","loadConfig","packageBlocks","credentials","createKizenClient","readPushMap","writePushMap","ensureGitignore","dir","isClaudeSkillStale","randomUUID","text","code","EDIT_ACCESS_LEVELS","CHART_GROUP_HINT","errorMessage","error","failure","message","extra","success","value","apiFailure","KizenApiError","PluginValidationError","formatValidationIssues","environmentList","ENVIRONMENTS","loadCredentialSource","source","deps","detailed","problem","empty","field","profileSource","profile","resolveCredentials","options","profiles","names","candidate","GLOBAL_CREDENTIALS_PATH","config","join","active","only","blockChoices","deployable","available","multiplePlugins","entry","pluginApiName","apiName","block","plugin","qualified","blockSelectionMessage","selection","list","formatAvailableBlocks","resolveBlock","packaged","selectBlock","findInvalidBlockField","invalidBlockMessage","content","toCustomCodeContent","canonicalContentHash","canEditFor","employeeAccess","toTargetRow","summary","surface","toTargetCustomObject","object","CONTACTS_OBJECT_NAME","listPushableObjects","client","objects","clientObjectId","pushable","left","right","listTargets","environment","businessId","objectId","chartGroups","row","dashboards","homepages","customObjects","isMemberDashlet","dashboard","dashlet","buildTargetChoices","findCustomCodeDashlets","parsed","parsePushKey","customCodeName","target","action","resolvedBy","dashboardTypeToSurface","chooseDashboard","context","toChoice","resolveFlaggedDashboard","dashboardId","choices","dashletId","isCustomCodeDashlet","match","matchPushTarget","resolveRemembered","resolveTarget","customObjectOf","raw","id","fetchUrl","segment","buildPlan","resolved","warnings","body","path","actionLine","detectDrift","drift","buildUpdateBody","buildCreateBody","url","buildDashboardUrl","APP_URLS","isProductionEnvironment","pushMapKeyOf","applyPlan","plan","createdId","remembered","upsertPushMapEntry","PUSH_MAP_RELATIVE_PATH","UUID_PATTERN","buildBrowserRefresh","forgetRemembered","key","findPushMapEntry","removePushMapEntry","headlessWriteGate","DRY_RUN_NOTE","formatSummaryLines","formatIssueWarning","issue","quoteArg","arg","formatFailureText","result","command","choiceArgs","lines","choice","args","writeFailure","output","credentialArgs","claudeSkillWarnings","STALE_CLAUDE_SKILL_WARNING","runPushHeadless","blockArgs","kind","fail","credentialStep","blockStep","forgotten","targetStep","gateStep","planStep","blockInfo","common","issueWarnings","gate","w","warning","appliedStep","applied","refresh","pad","width","formatTargetTable","title","rows","header","cells","widths","label","index","cell","line","formatTargetsText","runTargetsHeadless","objectArgs","targetsStep","useEffect","useState","Box","Text","useApp","useInput","Box","Text","Box","Text","jsx","LOGO_LINES","Logo","line","i","Fragment","jsx","jsxs","AppHeader","marginBottom","Logo","Box","Text","useMemo","useState","Box","Text","useInput","clamp","value","min","max","moveCursor","cursor","length","delta","options","current","isEnabled","index","step","offset","target","visibleWindow","size","rows","start","jsx","jsxs","DEFAULT_HINT","DEFAULT_WINDOW_SIZE","initialCursor","items","initialIndex","clamped","moveCursor","firstEnabled","item","SelectList","title","onSelect","onCancel","hint","windowSize","isActive","cursorState","setCursorState","useState","disabled","useMemo","cursor","pageSize","useInput","input","key","move","delta","start","end","visibleWindow","above","below","Box","Text","offset","selected","itemDisabled","highlight","useEffect","useState","Text","jsx","SPINNER_FRAMES","Spinner","frame","setFrame","id","prev","Fragment","jsx","jsxs","SURFACE_ITEMS","SURFACE_NOUNS","DRIFT_WARNING","isCreateChoice","choice","orderTargetChoices","choices","matchedId","matched","creates","rest","targetItem","description","dashboardItem","row","label","part","withTarget","options","dashboardId","next","createPushFlow","apiName","deps","setPhase","setSession","fail","view","guard","task","error","apiFailure","apply","context","plan","step","applyPlan","target","buildPlan","gate","headlessWriteGate","resolve","back","resolveTarget","prepare","credentials","block","key","pushMapKeyOf","pushMap","forgetRemembered","removePushMapEntry","session","findPushMapEntry","packageBlock","name","resolveBlock","loadCredentials","resolveCredentials","listDashboards","surface","object","noun","rows","surfaceToDashboardType","summary","toTargetRow","environment","businessId","phase","objects","listPushableObjects","dashboard","match","matchPushTarget","buildTargetChoices","ConfirmPrompt","prompt","strict","onAccept","onCancel","useInput","input","answer","Text","Lines","lines","color","Box","line","index","PlanSummary","formatSummaryLines","Working","Spinner","ErrorFrame","formatValidationIssues","DoneFrame","applied","refresh","buildBrowserRefresh","warning","PushUI","app","useApp","useState","flow","initialOptions","useEffect","frame","children","AppHeader","SelectList","_item","item","describeError","error","PluginValidationError","formatValidationIssues","blockCommand","program","block","apiName","options","exported","warnings","exportBlock","json","copyToClipboard","runPushHeadless","createDefaultPushDeps","waitUntilExit","render","createElement","PushUI","runTargetsHeadless","createElement","render","useEffect","useState","Box","Text","useApp","PluginValidationError","formatBytes","n","Box","Text","jsx","jsxs","groupIssuesByPath","issues","groups","issue","key","group","ValidationIssues","errorCount","path","Fragment","jsx","jsxs","STEPS","STEP_LABELS","BuildUI","outputDir","pluginDir","app","useApp","step","setStep","useState","failed","setFailed","issues","setIssues","errorMessage","setErrorMessage","bundleSize","setBundleSize","useEffect","runBuild","size","err","PluginValidationError","currentIndex","isDone","Box","AppHeader","s","i","isActive","isStepDone","Text","Spinner","formatBytes","ValidationIssues","buildCommand","program","pluginDir","outputDir","ensureGitignore","waitUntilExit","render","createElement","BuildUI","createElement","render","useCallback","useState","Box","Text","useApp","useInput","join","access","mkdir","writeFile","dirname","join","config_default","script_default","styles_default","config_default","script_default","styles_default","config_default","script_default","config_default","script_default","styles_default","greet_default","config_default","script_default","config_default","script_default","config_default","script_default","ARTIFACT_TYPES","ARTIFACT_LABELS","TEMPLATES","config_default","script_default","styles_default","greet_default","artifactFiles","type","entryDir","directory","component","files","relativePath","content","scaffoldArtifactFiles","types","deflateSync","THUMBNAIL_SIZE","BODY_HALF_SIZE","BODY_CORNER_RADIUS","KNOB_RADIUS","KNOB_OFFSET_RATIO","NECK_HALF_WIDTH","SATURATION","LIGHTNESS","fnv1a","text","hash","i","thumbnailStyle","apiName","hslToRgb","hue","saturation","lightness","chroma","sector","secondary","match","r","g","b","roundedBoxDistance","x","y","halfW","halfH","radius","qx","qy","circleDistance","cx","cy","puzzlePieceDistance","s","k","offset","neckHalf","d","topKnob","rightKnob","bottomSocket","leftSocket","renderPixels","style","size","pixels","knobExtension","centre","shift","py","px","turn","coverage","CRC_TABLE","_","n","c","crc32","bytes","crc","byte","pngChunk","type","data","typeBytes","length","PNG_SIGNATURE","encodePng","width","height","rgba","ihdr","stride","raw","thumbnailBytes","THUMBNAIL_PATH","PROD_ENVIRONMENTS","pathExists","path","access","precheckTargetDir","dir","join","findAvailableSubDir","parentDir","baseName","base","i","candidate","buildManifest","input","businessId","targetEnvironments","writeScaffoldedFiles","targetDir","scaffolded","files","file","directories","dirname","mkdir","writeFile","createPlugin","manifest","scaffoldArtifactFiles","copilotFiles","claudeFiles","thumbnailBytes","ensureGitignore","FIELDS","FIELD_LABELS","REQUIRED_FIELDS","API_NAME_PATTERN","API_NAME_HINT","inferApiName","name","emptyValues","defaultBusinessId","validateField","fieldName","inputBuffer","value","normalizeFieldValue","toggleArtifactSelection","selected","type","next","ARTIFACT_TYPES","candidate","jsx","jsxs","Hint","text","Text","CreateUI","parentDir","defaultBusinessId","defaultEnvironment","app","useApp","phase","setPhase","useState","mode","setMode","values","setValues","emptyValues","artifacts","setArtifacts","ARTIFACT_TYPES","inputBuffer","setInputBuffer","targetDir","setTargetDir","enterFieldEntry","useCallback","nextMode","initialValues","runPrecheck","dir","result","precheckTargetDir","resolveSubDirAndConfirm","finalValues","findAvailableSubDir","err","runWrite","createPlugin","useInput","input","key","field","current","fieldName","FIELDS","prev","updated","prevField","prevName","fieldError","validateField","valueToStore","normalizeFieldValue","nextField","nextName","existing","nextBuffer","inferApiName","cursor","selected","lastField","lastName","type","next","toggleArtifactSelection","options","Box","AppHeader","opt","i","reason","activeField","targetLine","name","isActive","displayValue","isRequired","REQUIRED_FIELDS","label","FIELD_LABELS","active","checked","ARTIFACT_LABELS","manifest","buildManifest","join","PLACEHOLDER_DESCRIPTION","parseArtifactSelection","raw","ARTIFACT_TYPES","requested","part","unknown","resolveHeadlessInput","options","defaults","targetDir","name","apiName","inferApiName","API_NAME_PATTERN","API_NAME_HINT","description","developerBusinessId","developerEnvironment","resolveEnvironment","isEnvironment","value","ENVIRONMENTS","runHeadlessCreate","deps","input","err","precheck","conflict","artifactSummary","createCommand","program","ENVIRONMENTS","ARTIFACT_TYPES","options","parentDir","globalCreds","loadGlobalCredentials","defaultBusinessId","defaultEnvironment","suppliedFlags","value","runHeadlessCreate","precheckTargetDir","createPlugin","text","code","waitUntilExit","render","createElement","CreateUI","createElement","render","useCallback","useEffect","useRef","useState","Box","Text","useInput","PluginValidationError","watch","createServer","join","WebSocketServer","createReadStream","realpathSync","access","readdir","readFile","realpath","stat","dirname","extname","join","resolve","sep","fileURLToPath","STRIPPED_RESPONSE_HEADERS","sanitizeUpstreamHeaders","headers","filtered","key","value","lower","MAX_PROXY_BYTES","CACHE_TTL_MS","CACHE_MAX_ENTRIES","ProxyResponseTooLargeError","bytesRead","limit","readBodyWithLimit","response","body","chunks","total","chunk","toCachedResponse","createProxyCache","options","onChange","enabled","_key","fetcher","cache","emitChange","evict","existing","oldest","pending","error","MIME_TYPES","ENCRYPTION_API_DEFAULTS","resolveWizardBase","target","forced","spawn","writeFile","rm","mkdtemp","access","join","tmpdir","python_requirements_default","parseRequirementsFile","content","line","resolvePythonBinary","runtime","match","major","minor","toStepInputValue","raw","coerceStepInputValue","value","toStepInputValue","normalizeStepInputs","inputs","name","WRAPPER_SCRIPT","DEFAULT_TIMEOUT","VENV_DIR","join","SUPPORTED_RUNTIMES","isSupportedRuntime","runtime","VENV_PACKAGES","parseRequirementsFile","python_requirements_default","venvReady","MIN_PYTHON","meetsMinimum","major","minor","formatVersion","version","probePython","bin","resolve","proc","spawn","out","chunk","code","match","findSystemPython","preferred","resolvePythonBinary","candidates","tried","runCommand","args","onLine","reject","pipeLines","source","stream","captured","buffer","idx","line","stderrCaptured","tail","detail","venvInstallListeners","ensureVenv","listener","listeners","emit","event","l","venvPython","reusable","access","existing","rm","systemPython","err","message","parseResult","stdout","startMarker","endMarker","startIdx","endIdx","userStdout","jsonStr","result","failedExecutionResult","error","executePythonStep","params","timeout","pythonBin","start","tmpDir","mkdtemp","tmpdir","wrapperPath","scriptPath","writeFile","env","exitCode","stderr","stdoutChunks","stderrChunks","settled","timer","finish","durationMs","base","TEXT_EXTENSIONS","CRYPTO_ALG","CRYPTO_VERSION","deserializeEnvelope","encrypt","serializeEnvelope","proxyLogEntryToString","entry","cache","upstream","SOURCE_FILE_MAX_BYTES","SKIP_FILES","isLocalHost","host","hostname","PROXY_ALLOWED_DOMAINS","isAllowedWizardTarget","target","url","domain","isAllowedProxyTarget","isLocalOrigin","origin","resolveSafePath","realPluginDir","relParam","rel","abs","resolve","sep","realAbs","realpath","isInsideSkippedDir","pluginDir","segment","SKIP_DIRS","getViewerPath","filename","fileURLToPath","join","dirname","extractUpstreamStatus","upstreamPath","headers","body","parsed","fileExists","filePath","access","createRequestHandler","viewerPath","createServerLog","createProxyLog","credentialsRef","activeProfileRef","outputDir","broadcast","onProxyCacheChange","lastPathRef","cacheEnabled","proxyCache","createProxyCache","realpathSync","req","res","profiles","listCredentialProfiles","chunks","chunk","profileName","creds","loadGlobalCredentials","loadCredentialProfile","active","currentConfig","loadConfig","saveConfig","bundlePath","content","readFile","stepParams","normalizeStepInputs","event","result","executePythonStep","envelope","encrypt","serialized","serializeEnvelope","err","parseError","deserializeEnvelope","bufLen","b64","checks","CRYPTO_VERSION","CRYPTO_ALG","c","rawTarget","wizardBase","resolveWizardBase","upstreamUrl","method","_wizardHost","_encTarget","wizardForwardHeaders","resolvedBody","upstream","message","wizardResponseHeaders","sanitizeUpstreamHeaders","wizardBody","proxyTarget","_drop","forwardHeaders","cacheKey","cached","fromCache","responseHeaders","responseBody","readBodyWithLimit","MAX_PROXY_BYTES","dirEntries","readdir","entries","entry","kind","stats","stat","a","b","normalizedPath","detail","ext","extname","explicitMime","MIME_TYPES","isKnownText","TEXT_EXTENSIONS","contentType","createReadStream","resolvedPath","mimeType","ProxyResponseTooLargeError","launch","createRequire","mkdirSync","readFile","dirname","join","fileURLToPath","CDP","CSP_HEADERS","KIZEN_DOMAINS","isKizenUrl","url","hostname","d","installDockIcon","client","iconPath","icon","launchChromeViewer","opts","baseUrl","chrome","cdpPort","cookieTimer","mainTargetId","reconnectTimer","reconnectAttempt","killed","dbg","msg","vb","clearCookieTimer","isNewTabUrl","setupClient","c","rawParams","params","requestId","request","responseHeaders","responseStatusCode","filtered","rewroteSetCookie","h","patched","cookie","body","base64Encoded","e","e2","cookies","raw","bare","handleTarget","targetInfo","scheduleReconnect","delay","attemptNumber","MAX_CDP_ATTEMPTS","CDP_ATTEMPT_DELAY_MS","attempt","r","warning","useCallback","useState","useLogHistory","limit","history","setHistory","append","message","h","useCallback","useEffect","useState","Box","Text","useInput","jsx","jsxs","FIELDS","FIELD_LABELS","Hint","text","Text","CredentialSetupUI","initialMode","showProfileManager","onComplete","onCancel","phase","setPhase","useState","inputBuffer","setInputBuffer","error","setError","activeProfileName","setActiveProfileName","handleModeChosen","useCallback","mode","handleProfileChosen","profile","profiles","listCredentialProfiles","existing","loadGlobalCredentials","loadCredentialProfile","envCursor","ENVIRONMENTS","handleSave","values","environment","credentials","normalizeCredentialIds","saveCredentialProfile","DEFAULT_PROFILE_NAME","err","useInput","input","key","loadProfileList","cursor","addNewIdx","totalItems","selected","nameBuffer","existingProfiles","trimmed","p","field","fieldName","prev","updatedValues","prevField","nextField","useEffect","label","Box","AppHeader","opt","i","nameError","activeField","isEnvField","profileLabel","GLOBAL_CREDENTIALS_PATH","name","isActive","displayValue","env","isSelected","jsx","jsxs","SKIP_WATCH_PREFIXES","DevUI","port","pluginDir","outputDir","initialCredentials","initialCredentialMode","initialActiveProfile","initialLastPath","debug","verbose","autoViewer","cacheEnabled","credentialsRef","useRef","activeProfileRef","lastPathRef","credMode","setCredMode","useState","credentialMode","setCredentialMode","status","setStatus","errorMessage","setErrorMessage","serverLogHistory","appendServerLog","useLogHistory","buildLogHistory","appendBuildLog","cdpLogHistory","appendCdpLog","proxyLogHistory","setProxyLogHistory","buildStatus","setBuildStatus","buildError","setBuildError","buildIssues","setBuildIssues","lastBuilt","setLastBuilt","lastBundleSize","setLastBundleSize","wsClientCount","setWsClientCount","proxyCacheSize","setProxyCacheSize","proxyCacheHits","setProxyCacheHits","proxyCacheMisses","setProxyCacheMisses","buildingRef","viewerLaunchedRef","chromeHandleRef","debounceTimerRef","wsClientsRef","pendingMessagesRef","broadcast","useCallback","msg","json","pruned","client","createServerLog","launchChromeViewerCb","launchChromeViewer","join","handle","useEffect","onExit","useInput","input","key","handleCredentialsDone","result","profile","saveConfig","createProxyLog","entry","h","proxyLogEntryToString","n","createBuildLog","message","triggerBuild","runBuild","bundleSize","formatBytes","err","PluginValidationError","watcher","watch","_","filename","normalized","prefix","viewerPath","getViewerPath","fileExists","viewerBuilt","handler","createRequestHandler","server","createServer","wss","WebSocketServer","ws","CredentialSetupUI","elapsedSeconds","elapsedLabel","buildErrorCount","issue","Box","AppHeader","Text","Spinner","ValidationIssues","log","index","i","runSetupUI","initialMode","resolve","unmountFn","handleComplete","result","unmount","render","createElement","CredentialSetupUI","devCommand","program","options","port","pluginDir","outputDir","ensureGitignore","credentials","credentialMode","activeCredentialProfile","lastPath","loadConfig","loadCredentialsFromFile","config","loadCredentialProfile","loadGlobalCredentials","profile","saveConfig","verbose","debug","autoViewer","cacheEnabled","waitUntilExit","DevUI","createElement","render","useCallback","useEffect","useState","Box","Text","useApp","useInput","encrypt","serializeEnvelope","isConnRefused","err","e","authHeaders","credentials","wizardFetch","wizardBase","path","init","getProxyEnvStatus","PROXY_UNAVAILABLE_HINT","readJsonSafe","res","text","parsed","fetchPublicKey","ctx","apiName","resolveWizardBase","data","errMsg","encryptLocally","publicKeyPem","value","envelope","encrypt","serialized","serializeEnvelope","encryptRemote","encryptSecret","onPhase","publicKey","Fragment","jsx","jsxs","Hint","text","Text","EncryptUI","ctx","stageDefaulted","credentialsPath","initialApiName","defaultApiName","initialValue","onDone","app","useApp","phase","setPhase","useState","credentials","setCredentials","apiName","setApiName","secret","setSecret","fail","useCallback","err","runEncryption","creds","name","value","envelopeValue","encryptSecret","p","envelope","copied","copyToClipboard","proceed","handleProfileChosen","profile","loadGlobalCredentials","loadCredentialProfile","useEffect","loadCredentialsFromFile","profiles","listCredentialProfiles","only","useInput","input","key","cursor","selected","buffer","modeLabel","stageLabel","frame","children","Box","AppHeader","Spinner","i","readFile","writeFile","join","envelopeObject","value","compactEnvelope","writeEnvelopeFile","path","DEFAULT_STAGE","isValidStage","stage","invalidStageMessage","resolveStage","defaultStageNotice","readManifestDefaults","cwd","raw","parsed","manifest","apiName","stripTrailingNewlines","readStdin","chunks","chunk","runHeadless","ctx","options","defaults","stageWasDefaulted","deps","credentials","apiName","defaultStageNotice","value","stripTrailingNewlines","envelopeValue","compactEnvelope","err","encryptCommand","program","options","isValidStage","invalidStageMessage","defaults","readManifestDefaults","stage","stageWasDefaulted","resolveStage","ctx","runHeadless","loadCredentialsFromFile","loadGlobalCredentials","encryptSecret","readStdin","text","writeEnvelopeFile","code","err","envelopeValue","waitUntilExit","render","createElement","EncryptUI","value","VALID_ICONS","VALID_ICONS_LIST","CUSTOM_ICON_NAMES","ALL_VALID_ICONS_LIST","iconsCommand","program","name","ALL_VALID_ICONS_LIST","mkdir","writeFile","readFile","join","SENSITIVE_FIELDS","redactServices","services","svc","s","redacted","k","buildTree","files","root","file","parts","node","part","i","next","sortTreeChildren","a","b","fileId","path","esc","str","fileExt","idx","LANG_MAP","mdLang","mdFence","content","longestRun","max","m","renderTextTree","prefix","sorted","child","isLast","connector","childPrefix","LICENSE_FILE","filterSourceFiles","f","buildFilteredConfig","manifest","v","IMAGE_MIME","renderTree","renderFileSection","body","generateMarkdown","filtered","name","version","description","sourceFiles","lines","configJson","configFence","fence","generateHtml","treeHtml","fileSections","EXAMPLES_DIR","join","GLOBAL_CREDENTIALS_DIR","reportCommand","program","options","pluginDir","manifest","raw","readFile","parsed","apiName","htmlPath","mdPath","files","readLocalFiles","mkdir","writeFile","generateHtml","generateMarkdown","setupClaudeCommand","program","options","runSetupClaude","readVersion","pkgPath","join","dirname","fileURLToPath","readFileSync","createProgram","program","Command","createCommand","setupClaudeCommand","buildCommand","devCommand","encryptCommand","reportCommand","iconsCommand","blockCommand","applyProxyFromEnv","http","createProgram"]}
|