@kizenapps/cli 0.16.1 → 0.18.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 +78 -12
- package/dist/index.js.map +1 -1
- package/dist/viewer/assets/{CodeStepsPage-DoQTFAvB.js → CodeStepsPage-bUqixBkt.js} +1 -1
- package/dist/viewer/assets/{ConfigurationPage-WvAn-eE3.js → ConfigurationPage-egBHLNoe.js} +1 -1
- package/dist/viewer/assets/{SandboxPage-DiL1N1bn.js → SandboxPage-CWOkZs5g.js} +1 -1
- package/dist/viewer/assets/{WhenBadge-DiiQ6XoK.js → WhenBadge-P9aN2Qd7.js} +1 -1
- package/dist/viewer/assets/{configStorage-Bnv2jFLx.js → configStorage-DcQWEL9-.js} +1 -1
- package/dist/viewer/assets/{index-DqBLj4Is.js → index-BXPMaCXm.js} +2 -2
- package/dist/viewer/assets/{useCriticalExceptionDialog-ruFjUSi0.js → useCriticalExceptionDialog-BI_gNDBK.js} +2 -2
- package/dist/viewer/index.html +1 -1
- package/package.json +2 -2
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/commands/build.ts","../src/ui/BuildUI.tsx","../src/lib/runBuild.ts","../src/lib/readFiles.ts","../shared/lib/formatBytes.ts","../src/ui/AppHeader.tsx","../src/ui/Logo.tsx","../src/ui/Spinner.tsx","../src/lib/gitignore.ts","../src/commands/create.ts","../src/ui/CreateUI.tsx","../src/lib/createPlugin.ts","../src/lib/credentials.ts","../shared/lib/credentials.ts","../src/commands/dev.ts","../src/ui/DevUI.tsx","../src/server/requestHandler.ts","../src/lib/proxyCache.ts","../src/lib/constants.ts","../src/lib/config.ts","../src/server/pythonExecutor.ts","../shared/lib/fileExtensions.ts","../shared/lib/proxy.ts","../src/chrome/launcher.ts","../src/hooks/useLogHistory.ts","../src/ui/CredentialSetupUI.tsx"],"sourcesContent":["import { readFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { program } from 'commander';\nimport { buildCommand } from './commands/build.js';\nimport { createCommand } from './commands/create.js';\nimport { devCommand } from './commands/dev.js';\n\nconst pkgPath = join(dirname(fileURLToPath(import.meta.url)), '..', 'package.json');\nconst pkg = JSON.parse(readFileSync(pkgPath, 'utf-8')) as { version: string };\n\nprogram.name('appbuilder').description('Kizen plugin app builder').version(pkg.version);\n\ncreateCommand(program);\n\nbuildCommand(program);\n\ndevCommand(program);\n\nprogram.parse();\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 { 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';\n\ntype BuildStep = BuildStepName | 'done' | 'error';\n\ninterface BuildUIProps {\n outputDir: string;\n pluginDir: string;\n}\n\nconst STEPS: BuildStepName[] = [\n 'creating-dir',\n 'reading-files',\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 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 [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 app.exit();\n })\n .catch((err: unknown) => {\n const message = err instanceof Error ? err.message : String(err);\n\n setErrorMessage(message);\n setStep('error');\n app.exit();\n });\n }, [outputDir, pluginDir, app]);\n\n const currentIndex = STEPS.indexOf(step as BuildStepName);\n const isError = step === 'error';\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 = isError && 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 {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","import { mkdir, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { minifyFiles, packagePlugin, transformDeployablePlugin } from '@kizenapps/packager';\nimport type { DeployablePlugin } from '@kizenapps/packager';\nimport { readLocalFiles } from './readFiles.js';\n\nconst REQUIRED_MANIFEST_FIELDS = ['name', 'api_name', 'version', 'entry'] as const;\n\ntype ParsedManifest = Parameters<typeof packagePlugin>[1];\n\nfunction validateManifestObject(manifest: Record<string, unknown>, index?: number): void {\n const label = index === undefined ? 'kizen.json' : `kizen.json entry #${String(index + 1)}`;\n\n for (const field of REQUIRED_MANIFEST_FIELDS) {\n const value = manifest[field];\n\n if (typeof value !== 'string' || value === '') {\n throw new Error(\n `${label} is missing required field \"${field}\" (expected a non-empty string).`,\n );\n }\n }\n}\n\nfunction parseManifest(content: string): ParsedManifest {\n let parsed: unknown;\n\n try {\n parsed = JSON.parse(content);\n } catch (err) {\n const detail = err instanceof Error ? err.message : String(err);\n\n throw new Error(`kizen.json is not valid JSON: ${detail}`);\n }\n\n if (Array.isArray(parsed)) {\n parsed.forEach((entry, i) => {\n if (typeof entry !== 'object' || entry === null) {\n throw new Error(`kizen.json entry #${String(i + 1)} is not a JSON object.`);\n }\n\n validateManifestObject(entry as Record<string, unknown>, i);\n });\n\n return parsed as ParsedManifest;\n }\n\n if (typeof parsed !== 'object' || parsed === null) {\n throw new Error('kizen.json must be a JSON object (or array of objects).');\n }\n\n validateManifestObject(parsed as Record<string, unknown>);\n\n return parsed as ParsedManifest;\n}\n\nexport type BuildStepName =\n | 'creating-dir'\n | 'reading-files'\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 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 onStep?.('reading-files');\n\n const files = await readLocalFiles(pluginDir);\n\n onStep?.('minifying');\n\n const minified = await minifyFiles(files);\n\n onStep?.('packaging');\n\n const manifestFile = minified.find((f) => f.path === 'kizen.json');\n\n if (!manifestFile) {\n throw new Error('kizen.json not found in plugin directory.');\n }\n\n const manifests = parseManifest(manifestFile.content);\n const packaged = packagePlugin(minified, manifests);\n const deployable = Object.values(packaged).map(transformDeployablePlugin);\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']);\n\nexport const SKIP_DIRS = new Set(['node_modules', '.git', '.kizenapp', '.github']);\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 paths.push(join(dir, entry.name));\n }\n }\n\n return paths;\n}\n\nexport async function readLocalFiles(rootDir: string): 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 if (BINARY_EXTENSIONS.has(ext)) {\n const buf = await readFile(absPath);\n\n return { path: relPath, content: '', binaryData: buf };\n }\n\n const content = await readFile(absPath, 'utf-8');\n\n return { path: relPath, content };\n }),\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 { 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 { 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 * 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 { createElement } from 'react';\nimport { render } from 'ink';\nimport type { Command } from 'commander';\nimport { CreateUI } from '../ui/CreateUI.js';\nimport { loadGlobalCredentials } from '../lib/credentials.js';\n\nexport function createCommand(program: Command): void {\n program\n .command('create')\n .description('Scaffold a new Kizen plugin project')\n .action(async () => {\n const parentDir = process.cwd();\n const globalCreds = await loadGlobalCredentials();\n const defaultBusinessId = globalCreds?.businessId ?? '';\n\n const { waitUntilExit } = render(createElement(CreateUI, { parentDir, defaultBusinessId }), {\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 { AppHeader } from './AppHeader.js';\n\nconst FIELDS = ['name', 'apiName', 'externalLink', 'description', 'developerBusinessId'] as const;\n\ntype FieldName = (typeof FIELDS)[number];\n\nconst 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\nconst REQUIRED_FIELDS: readonly FieldName[] = ['name', 'apiName'];\n\nfunction inferApiName(name: string): string {\n return name\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '_')\n .replace(/^_+|_+$/g, '');\n}\n\ntype FieldValues = Record<FieldName, string>;\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 | { type: 'resolving-target' }\n | { type: 'confirm'; values: FieldValues }\n | { type: 'writing' }\n | { type: 'done'; targetDir: string }\n | { type: 'error'; message: string };\n\ninterface CreateUIProps {\n parentDir: string;\n defaultBusinessId: string;\n}\n\nconst Hint: FC<{ text: string }> = ({ text }) => <Text dimColor>{text}</Text>;\n\nfunction emptyValues(defaultBusinessId: string): FieldValues {\n return {\n name: '',\n apiName: '',\n externalLink: '',\n description: '',\n developerBusinessId: defaultBusinessId,\n };\n}\n\nexport const CreateUI: FC<CreateUIProps> = ({ parentDir, defaultBusinessId }) => {\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 [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): Promise<void> => {\n try {\n const dir = await findAvailableSubDir(parentDir, finalValues.apiName);\n\n setTargetDir(dir);\n\n setPhase({ type: 'confirm', values: finalValues });\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(async (finalValues: FieldValues, dir: string): 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 });\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\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 buffer = inputBuffer.trim();\n const isRequired = REQUIRED_FIELDS.includes(fieldName);\n\n if (isRequired && !buffer) {\n setPhase({\n type: 'field-entry',\n field,\n values: current,\n fieldError: `${FIELD_LABELS[fieldName]} is required`,\n });\n\n return;\n }\n\n const valueToStore = fieldName === 'description' ? inputBuffer : buffer;\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 if (mode === 'sub-dir') {\n setPhase({ type: 'resolving-target' });\n\n void resolveSubDirAndConfirm(updated);\n } else {\n setPhase({ type: 'confirm', values: updated });\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 === 'confirm') {\n if (key.escape) {\n const lastField = FIELDS.length - 1;\n const lastName = FIELDS[lastField];\n\n setPhase({ type: 'field-entry', field: lastField, values: phase.values });\n\n setInputBuffer(lastName ? phase.values[lastName] : '');\n\n return;\n }\n\n if (key.return) {\n setPhase({ type: 'writing' });\n\n void runWrite(phase.values, targetDir);\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 === '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 });\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 dimColor>Also creates:</Text>\n <Text dimColor>\n {' '}\n {join(targetDir, 'src/')}\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>{' '}appbuilder dev</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 { join } from 'node:path';\nimport { ensureGitignore } from './gitignore.js';\n\nexport interface CreatePluginInput {\n targetDir: string;\n name: string;\n apiName: string;\n externalLink: string;\n description: string;\n developerBusinessId: string;\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 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: ['prod'],\n config_template: {},\n base_config: {},\n developer_business_id: input.developerBusinessId,\n };\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 ensureGitignore(input.targetDir);\n}\n","import { mkdir, readFile, readdir, writeFile } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { dirname, join } from 'node:path';\nimport { ENVIRONMENTS, type Environment, type Credentials } from '../../shared/lib/credentials.js';\nexport { ENVIRONMENTS, type Environment, type Credentials } 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 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 = obj.environment;\n\n return {\n apiKey: typeof obj.apiKey === 'string' ? obj.apiKey : '',\n userId: typeof obj.userId === 'string' ? obj.userId : '',\n businessId: typeof obj.businessId === 'string' ? obj.businessId : '',\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 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","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","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 .action(\n async (options: {\n port: string;\n credentials?: string;\n debug?: boolean;\n verbose?: boolean;\n viewer?: 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\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 }),\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 { 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';\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}\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}) => {\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 [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 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 const message = err instanceof Error ? err.message : String(err);\n\n setBuildError(message);\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 );\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]);\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 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' && <Text color=\"red\">✗ {buildError ?? 'unknown 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 {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 ● {proxyCacheSize} key{proxyCacheSize !== 1 ? 's' : ''} in the network cache ·{' '}\n {proxyCacheHits} hit · {proxyCacheMisses} miss\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 { executePythonStep } from './pythonExecutor.js';\nimport { SKIP_DIRS } from '../lib/readFiles.js';\nimport { TEXT_EXTENSIONS } from '../../shared/lib/fileExtensions.js';\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\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\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): (req: IncomingMessage, res: ServerResponse) => void {\n const proxyCache = createProxyCache({ onChange: onProxyCacheChange });\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(credentialsRef.current !== null ? JSON.stringify(credentialsRef.current) : '{}');\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\n await saveConfig(outputDir, {\n credentialMode: 'global',\n ...(active !== undefined && { activeCredentialProfile: active }),\n });\n\n broadcast({ type: 'credentials-updated', credentials: creds });\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/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, string>;\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 scriptRuntime: body.scriptRuntime ?? 'python-3.9',\n inputs: 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.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 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 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}\n\ninterface CacheEntry {\n insertedAt: number;\n promise: Promise<CachedResponse>;\n}\n\nexport function createProxyCache(options: ProxyCacheOptions = {}): ProxyCache {\n const cache = new Map<string, CacheEntry>();\n const { onChange } = options;\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(async (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 .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","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}\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 { 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 { type ExecutionResult, type HttpRequests } 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, string>;\n secrets: Record<string, string>;\n timeout?: number;\n onInstallProgress?: VenvInstallListener;\n}\n\nconst VENV_DIR = join(process.cwd(), '.kizenapp', 'venv');\nconst VENV_PACKAGES = [\n 'awslambdaric',\n 'bcrypt',\n 'fpdf2',\n 'lxml',\n 'msgpack',\n 'numpy',\n 'paramiko',\n 'pyjwt',\n 'pypdf',\n 'pytz',\n 'requests',\n 'tzdata',\n];\n\nlet venvReady: Promise<string> | null = null;\n\nfunction resolvePythonBinary(runtime: string): string {\n // e.g. \"python-3.9\" -> try \"python3.9\" first\n const match = /^python-(\\d+\\.\\d+)$/.exec(runtime);\n\n if (match?.[1]) {\n return `python${match[1]}`;\n }\n\n return 'python3';\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\nconst installListeners = new Set<VenvInstallListener>();\n\nfunction emitInstall(event: VenvInstallEvent): void {\n for (const listener of installListeners) {\n listener(event);\n }\n}\n\nfunction ensureVenv(runtime: string, listener?: VenvInstallListener): Promise<string> {\n if (listener) {\n installListeners.add(listener);\n }\n\n if (!venvReady) {\n venvReady = (async () => {\n const venvPython = join(VENV_DIR, 'bin', 'python');\n\n try {\n await access(venvPython);\n } catch {\n const systemPython = resolvePythonBinary(runtime);\n\n await runCommand(systemPython, ['-m', 'venv', VENV_DIR]);\n }\n\n emitInstall({ kind: 'start' });\n\n try {\n await runCommand(\n venvPython,\n ['-m', 'pip', 'install', '--disable-pip-version-check', ...VENV_PACKAGES],\n (line, stream) => {\n emitInstall({ kind: 'log', line, stream });\n },\n );\n\n emitInstall({ kind: 'complete' });\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n\n emitInstall({ kind: 'error', message });\n\n // Reset so the next call retries rather than returning the cached\n // rejection forever. Also nuke the venv dir: if `python -m venv`\n // failed mid-create, the remnants will confuse the access() check\n // on the next attempt. rm is best-effort — we'll rebuild either 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 installListeners.clear();\n }\n\n return venvPython;\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\nexport async function executePythonStep(params: ExecuteStepParams): Promise<ExecutionResult> {\n const timeout = params.timeout ?? DEFAULT_TIMEOUT;\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","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 | { kind: 'request'; method: string; status: number; fromCache: boolean; url: string }\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\n return `${entry.method} ${entry.url} → ${String(entry.status)}${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 CDPRemoteObject {\n type: string;\n subtype?: string;\n value?: unknown;\n description?: string;\n objectId?: string;\n preview?: CDPObjectPreview;\n}\n\ninterface CDPPropertyPreview {\n name: string;\n type: string;\n value?: string;\n subtype?: string;\n valuePreview?: CDPObjectPreview;\n}\n\ninterface CDPObjectPreview {\n type: string;\n subtype?: string;\n overflow: boolean;\n properties: CDPPropertyPreview[];\n}\n\ninterface CDPConsoleEvent {\n type: string;\n args: CDPRemoteObject[];\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 Runtime: {\n enable: () => Promise<void>;\n consoleAPICalled: (handler: (params: CDPConsoleEvent) => void) => void;\n callFunctionOn: (opts: {\n objectId: string;\n functionDeclaration: string;\n returnByValue: boolean;\n }) => Promise<{ result: { value?: unknown } }>;\n };\n Target: {\n setAutoAttach: (opts: {\n autoAttach: boolean;\n waitForDebuggerOnStart: boolean;\n flatten: boolean;\n }) => Promise<void>;\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) => 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 CDPAttachedToTargetEvent {\n sessionId: string;\n targetInfo: { targetId: string; type: string; url: string };\n waitingForDebugger: boolean;\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\nfunction parseProp(prop: CDPPropertyPreview): unknown {\n if (prop.type === 'number') {\n return Number(prop.value);\n }\n\n if (prop.type === 'boolean') {\n return prop.value === 'true';\n }\n\n if (prop.type === 'undefined') {\n return undefined;\n }\n\n if (prop.type === 'object' && prop.value === 'null') {\n return null;\n }\n\n if (prop.type === 'object' && prop.valuePreview) {\n const { valuePreview } = prop;\n\n if (valuePreview.subtype === 'array') {\n return valuePreview.properties\n .filter((p) => /^\\d+$/.test(p.name))\n .sort((a, b) => parseInt(a.name) - parseInt(b.name))\n .map(parseProp);\n }\n\n const obj: Record<string, unknown> = {};\n\n for (const p of valuePreview.properties) {\n obj[p.name] = parseProp(p);\n }\n\n return obj;\n }\n\n return prop.value ?? `[${prop.type}]`;\n}\n\nfunction serializeArg(arg: CDPRemoteObject): unknown {\n if (arg.value !== undefined) {\n return arg.value;\n }\n\n if (arg.preview) {\n const { preview } = arg;\n\n if (preview.subtype === 'array') {\n return preview.properties\n .filter((p) => /^\\d+$/.test(p.name))\n .sort((a, b) => parseInt(a.name) - parseInt(b.name))\n .map(parseProp);\n }\n\n const obj: Record<string, unknown> = {};\n\n for (const prop of preview.properties) {\n obj[prop.name] = parseProp(prop);\n }\n\n return obj;\n }\n\n return arg.description ?? `[${arg.type}]`;\n}\n\nasync function serializeArgAsync(client: CDPClient, arg: CDPRemoteObject): Promise<unknown> {\n if (arg.type === 'object' && arg.objectId) {\n try {\n const result = await client.Runtime.callFunctionOn({\n objectId: arg.objectId,\n functionDeclaration:\n 'function() { const seen = new WeakSet(); return JSON.stringify(this, function(k,v) { if (typeof v === \"object\" && v !== null) { if (seen.has(v)) return \"[Circular]\"; seen.add(v); } return v; }); }',\n returnByValue: true,\n });\n const val = result.result.value;\n\n if (typeof val === 'string') {\n return JSON.parse(val) as unknown;\n }\n } catch {\n // fall through to preview-based serialization\n }\n }\n\n return serializeArg(arg);\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 ],\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 await c.send('Runtime.enable', { generatePreview: true });\n\n // Child targets (iframes, popups, nested pages) auto-attach with their own\n // sessionIds. Runtime.enable is per-session, so without this the main page\n // works but sandbox/plugin frames are silent. Register before setAutoAttach\n // so we don't miss the first attach event.\n c.on('Target.attachedToTarget', (rawParams: unknown) => {\n const params = rawParams as CDPAttachedToTargetEvent;\n const { sessionId, targetInfo } = params;\n\n vb(`attached session ${sessionId} (${targetInfo.type} ${targetInfo.url})`);\n\n void c.send('Runtime.enable', { generatePreview: true }, sessionId).catch((e: unknown) => {\n vb(` Runtime.enable on session ${sessionId} failed: ${(e as Error).message}`);\n });\n });\n\n await c.Target.setAutoAttach({\n autoAttach: true,\n waitForDebuggerOnStart: false,\n flatten: true,\n });\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 c.on('Runtime.consoleAPICalled', (rawParams: unknown) => {\n void (async () => {\n const { type, args } = rawParams as CDPConsoleEvent;\n\n if (args[0]?.type === 'string' && String(args[0].value).includes('Chrome Security')) {\n return;\n }\n\n const level =\n type === 'warning'\n ? 'warn'\n : ['log', 'warn', 'error', 'info'].includes(type)\n ? type\n : 'log';\n\n vb(`console.${level} (${String(args.length)} arg(s))`);\n\n const serialized = await Promise.all(args.map((arg) => serializeArgAsync(c, arg)));\n\n opts.broadcast({ type: 'console-message', level, args: serialized });\n })().catch((e: unknown) => {\n vb(`console serialization failed: ${(e as Error).message}`);\n });\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 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 apiKey: values.apiKey ?? '',\n userId: values.userId ?? '',\n businessId: values.businessId ?? '',\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"],"mappings":"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","names":["readFileSync","dirname","join","fileURLToPath","program","createElement","render","useEffect","useState","Box","Text","useApp","mkdir","writeFile","join","minifyFiles","packagePlugin","transformDeployablePlugin","readdir","readFile","join","relative","IMAGE_EXTENSIONS","BINARY_EXTENSIONS","SKIP_DIRS","walk","dir","rootDir","entries","paths","entry","readLocalFiles","absolutePaths","absPath","relPath","dotIndex","ext","buf","content","REQUIRED_MANIFEST_FIELDS","validateManifestObject","manifest","index","label","field","value","parseManifest","content","parsed","err","detail","entry","i","serializePlugin","plugin","allReleaseNotes","runBuild","pluginDir","outputDir","onStep","mkdir","files","readLocalFiles","minified","minifyFiles","manifestFile","f","manifests","packaged","packagePlugin","deployable","transformDeployablePlugin","bundle","notesDir","a","b","jsonStr","stripReleaseNotes","key","bundleSize","writeFile","join","formatBytes","n","Box","Text","Box","Text","jsx","LOGO_LINES","Logo","line","i","Fragment","jsx","jsxs","AppHeader","marginBottom","Logo","Box","Text","useEffect","useState","Text","jsx","SPINNER_FRAMES","Spinner","frame","setFrame","id","prev","Fragment","jsx","jsxs","STEPS","STEP_LABELS","BuildUI","outputDir","pluginDir","app","useApp","step","setStep","useState","errorMessage","setErrorMessage","bundleSize","setBundleSize","useEffect","runBuild","size","err","message","currentIndex","isError","isDone","Box","AppHeader","s","i","isActive","isStepDone","Text","Spinner","formatBytes","fs","path","ensureGitignore","projectDir","gitignorePath","entry","contents","lines","l","addition","buildCommand","program","pluginDir","outputDir","ensureGitignore","waitUntilExit","render","createElement","BuildUI","createElement","render","useCallback","useState","Box","Text","useApp","useInput","join","access","mkdir","writeFile","join","pathExists","path","access","precheckTargetDir","dir","join","findAvailableSubDir","parentDir","baseName","base","i","candidate","buildManifest","input","createPlugin","mkdir","manifest","writeFile","ensureGitignore","jsx","jsxs","FIELDS","FIELD_LABELS","REQUIRED_FIELDS","inferApiName","name","Hint","text","Text","emptyValues","defaultBusinessId","CreateUI","parentDir","app","useApp","phase","setPhase","useState","mode","setMode","values","setValues","inputBuffer","setInputBuffer","targetDir","setTargetDir","enterFieldEntry","useCallback","nextMode","initialValues","runPrecheck","dir","result","precheckTargetDir","resolveSubDirAndConfirm","finalValues","findAvailableSubDir","err","runWrite","createPlugin","useInput","input","key","field","current","fieldName","prev","updated","prevField","prevName","buffer","valueToStore","nextField","nextName","existing","nextBuffer","lastField","lastName","options","Box","AppHeader","opt","i","selected","reason","activeField","fieldError","targetLine","isActive","displayValue","isRequired","label","manifest","buildManifest","join","mkdir","readFile","readdir","writeFile","homedir","dirname","join","ENVIRONMENTS","GLOBAL_CREDENTIALS_DIR","join","homedir","GLOBAL_CREDENTIALS_PATH","DEFAULT_PROFILE_NAME","isValidEnvironment","value","ENVIRONMENTS","parseCredentials","raw","obj","env","loadCredentialsFromFile","filePath","content","readFile","loadGlobalCredentials","saveGlobalCredentials","credentials","mkdir","dirname","writeFile","getProfilePath","name","listCredentialProfiles","profiles","entries","readdir","entry","saveCredentialProfile","loadCredentialProfile","createCommand","program","parentDir","defaultBusinessId","loadGlobalCredentials","waitUntilExit","render","createElement","CreateUI","createElement","render","useCallback","useEffect","useRef","useState","Box","Text","useInput","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","createProxyCache","options","cache","onChange","emitChange","evict","fetcher","existing","oldest","pending","error","MIME_TYPES","mkdir","readFile","writeFile","join","loadConfig","outputDir","content","saveConfig","config","spawn","writeFile","rm","mkdtemp","access","join","tmpdir","WRAPPER_SCRIPT","DEFAULT_TIMEOUT","VENV_DIR","join","VENV_PACKAGES","venvReady","resolvePythonBinary","runtime","match","runCommand","bin","args","onLine","resolve","reject","proc","spawn","pipeLines","source","stream","captured","buffer","chunk","idx","line","stderrCaptured","code","tail","detail","installListeners","emitInstall","event","listener","ensureVenv","venvPython","access","systemPython","err","message","rm","parseResult","stdout","startMarker","endMarker","startIdx","endIdx","userStdout","jsonStr","result","executePythonStep","params","timeout","pythonBin","start","tmpDir","mkdtemp","tmpdir","wrapperPath","scriptPath","writeFile","env","exitCode","stderr","stdoutChunks","stderrChunks","settled","timer","finish","durationMs","base","TEXT_EXTENSIONS","proxyLogEntryToString","entry","cache","SOURCE_FILE_MAX_BYTES","SKIP_FILES","isLocalHost","host","hostname","PROXY_ALLOWED_DOMAINS","isAllowedProxyTarget","target","url","domain","isLocalOrigin","origin","resolveSafePath","realPluginDir","relParam","rel","abs","resolve","sep","realAbs","realpath","isInsideSkippedDir","pluginDir","segment","SKIP_DIRS","getViewerPath","filename","fileURLToPath","join","dirname","fileExists","filePath","access","createRequestHandler","viewerPath","createServerLog","createProxyLog","credentialsRef","activeProfileRef","outputDir","broadcast","onProxyCacheChange","lastPathRef","proxyCache","createProxyCache","realpathSync","req","res","profiles","listCredentialProfiles","chunks","chunk","profileName","creds","loadGlobalCredentials","loadCredentialProfile","active","saveConfig","bundlePath","content","readFile","body","currentConfig","loadConfig","stepParams","event","result","executePythonStep","proxyTarget","upstreamPath","upstreamUrl","method","_drop","forwardHeaders","cacheKey","cached","fromCache","resolvedBody","upstream","responseHeaders","sanitizeUpstreamHeaders","responseBody","readBodyWithLimit","MAX_PROXY_BYTES","dirEntries","readdir","entries","entry","kind","stats","stat","a","b","normalizedPath","err","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","parseProp","prop","valuePreview","p","a","b","obj","serializeArg","arg","preview","serializeArgAsync","client","val","installDockIcon","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","sessionId","targetInfo","handleTarget","type","args","level","serialized","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","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","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","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","watcher","watch","_","filename","normalized","prefix","viewerPath","getViewerPath","fileExists","viewerBuilt","handler","createRequestHandler","server","createServer","wss","WebSocketServer","ws","CredentialSetupUI","elapsedSeconds","elapsedLabel","Box","AppHeader","Text","Spinner","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","waitUntilExit","DevUI","pkgPath","join","dirname","fileURLToPath","pkg","readFileSync","program","createCommand","buildCommand","devCommand"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/commands/build.ts","../src/ui/BuildUI.tsx","../src/lib/runBuild.ts","../src/lib/readFiles.ts","../shared/lib/formatBytes.ts","../src/ui/AppHeader.tsx","../src/ui/Logo.tsx","../src/ui/Spinner.tsx","../src/lib/gitignore.ts","../src/commands/create.ts","../src/ui/CreateUI.tsx","../src/lib/createPlugin.ts","../src/lib/credentials.ts","../shared/lib/credentials.ts","../src/commands/dev.ts","../src/ui/DevUI.tsx","../src/server/requestHandler.ts","../src/lib/proxyCache.ts","../src/lib/constants.ts","../src/lib/config.ts","../src/server/pythonExecutor.ts","../shared/lib/fileExtensions.ts","../shared/lib/proxy.ts","../src/chrome/launcher.ts","../src/hooks/useLogHistory.ts","../src/ui/CredentialSetupUI.tsx","../src/commands/report.ts"],"sourcesContent":["import { readFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { program } from 'commander';\nimport { buildCommand } from './commands/build.js';\nimport { createCommand } from './commands/create.js';\nimport { devCommand } from './commands/dev.js';\nimport { reportCommand } from './commands/report.js';\n\nconst pkgPath = join(dirname(fileURLToPath(import.meta.url)), '..', 'package.json');\nconst pkg = JSON.parse(readFileSync(pkgPath, 'utf-8')) as { version: string };\n\nprogram.name('appbuilder').description('Kizen plugin app builder').version(pkg.version);\n\ncreateCommand(program);\n\nbuildCommand(program);\n\ndevCommand(program);\n\nreportCommand(program);\n\nprogram.parse();\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 { 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';\n\ntype BuildStep = BuildStepName | 'done' | 'error';\n\ninterface BuildUIProps {\n outputDir: string;\n pluginDir: string;\n}\n\nconst STEPS: BuildStepName[] = [\n 'creating-dir',\n 'reading-files',\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 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 [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 app.exit();\n })\n .catch((err: unknown) => {\n const message = err instanceof Error ? err.message : String(err);\n\n setErrorMessage(message);\n setStep('error');\n app.exit();\n });\n }, [outputDir, pluginDir, app]);\n\n const currentIndex = STEPS.indexOf(step as BuildStepName);\n const isError = step === 'error';\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 = isError && 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 {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","import { mkdir, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { minifyFiles, packagePlugin, transformDeployablePlugin } from '@kizenapps/packager';\nimport type { DeployablePlugin } from '@kizenapps/packager';\nimport { readLocalFiles } from './readFiles.js';\n\nconst REQUIRED_MANIFEST_FIELDS = ['name', 'api_name', 'version', 'entry'] as const;\n\ntype ParsedManifest = Parameters<typeof packagePlugin>[1];\n\nfunction validateManifestObject(manifest: Record<string, unknown>, index?: number): void {\n const label = index === undefined ? 'kizen.json' : `kizen.json entry #${String(index + 1)}`;\n\n for (const field of REQUIRED_MANIFEST_FIELDS) {\n const value = manifest[field];\n\n if (typeof value !== 'string' || value === '') {\n throw new Error(\n `${label} is missing required field \"${field}\" (expected a non-empty string).`,\n );\n }\n }\n}\n\nfunction parseManifest(content: string): ParsedManifest {\n let parsed: unknown;\n\n try {\n parsed = JSON.parse(content);\n } catch (err) {\n const detail = err instanceof Error ? err.message : String(err);\n\n throw new Error(`kizen.json is not valid JSON: ${detail}`);\n }\n\n if (Array.isArray(parsed)) {\n parsed.forEach((entry, i) => {\n if (typeof entry !== 'object' || entry === null) {\n throw new Error(`kizen.json entry #${String(i + 1)} is not a JSON object.`);\n }\n\n validateManifestObject(entry as Record<string, unknown>, i);\n });\n\n return parsed as ParsedManifest;\n }\n\n if (typeof parsed !== 'object' || parsed === null) {\n throw new Error('kizen.json must be a JSON object (or array of objects).');\n }\n\n validateManifestObject(parsed as Record<string, unknown>);\n\n return parsed as ParsedManifest;\n}\n\nexport type BuildStepName =\n | 'creating-dir'\n | 'reading-files'\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 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 onStep?.('reading-files');\n\n const files = await readLocalFiles(pluginDir);\n\n onStep?.('minifying');\n\n const minified = await minifyFiles(files);\n\n onStep?.('packaging');\n\n const manifestFile = minified.find((f) => f.path === 'kizen.json');\n\n if (!manifestFile) {\n throw new Error('kizen.json not found in plugin directory.');\n }\n\n const manifests = parseManifest(manifestFile.content);\n const packaged = packagePlugin(minified, manifests);\n const deployable = Object.values(packaged).map(transformDeployablePlugin);\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(['node_modules', '.git', '.kizenapp', '.github']);\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(rootDir: string): 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 if (BINARY_EXTENSIONS.has(ext)) {\n const buf = await readFile(absPath);\n\n return { path: relPath, content: '', binaryData: buf };\n }\n\n const content = await readFile(absPath, 'utf-8');\n\n return { path: relPath, content };\n }),\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 { 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 { 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 * 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 { createElement } from 'react';\nimport { render } from 'ink';\nimport type { Command } from 'commander';\nimport { CreateUI } from '../ui/CreateUI.js';\nimport { loadGlobalCredentials } from '../lib/credentials.js';\n\nexport function createCommand(program: Command): void {\n program\n .command('create')\n .description('Scaffold a new Kizen plugin project')\n .action(async () => {\n const parentDir = process.cwd();\n const globalCreds = await loadGlobalCredentials();\n const defaultBusinessId = globalCreds?.businessId ?? '';\n\n const { waitUntilExit } = render(createElement(CreateUI, { parentDir, defaultBusinessId }), {\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 { AppHeader } from './AppHeader.js';\n\nconst FIELDS = ['name', 'apiName', 'externalLink', 'description', 'developerBusinessId'] as const;\n\ntype FieldName = (typeof FIELDS)[number];\n\nconst 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\nconst REQUIRED_FIELDS: readonly FieldName[] = ['name', 'apiName'];\n\nfunction inferApiName(name: string): string {\n return name\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '_')\n .replace(/^_+|_+$/g, '');\n}\n\ntype FieldValues = Record<FieldName, string>;\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 | { type: 'resolving-target' }\n | { type: 'confirm'; values: FieldValues }\n | { type: 'writing' }\n | { type: 'done'; targetDir: string }\n | { type: 'error'; message: string };\n\ninterface CreateUIProps {\n parentDir: string;\n defaultBusinessId: string;\n}\n\nconst Hint: FC<{ text: string }> = ({ text }) => <Text dimColor>{text}</Text>;\n\nfunction emptyValues(defaultBusinessId: string): FieldValues {\n return {\n name: '',\n apiName: '',\n externalLink: '',\n description: '',\n developerBusinessId: defaultBusinessId,\n };\n}\n\nexport const CreateUI: FC<CreateUIProps> = ({ parentDir, defaultBusinessId }) => {\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 [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): Promise<void> => {\n try {\n const dir = await findAvailableSubDir(parentDir, finalValues.apiName);\n\n setTargetDir(dir);\n\n setPhase({ type: 'confirm', values: finalValues });\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(async (finalValues: FieldValues, dir: string): 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 });\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\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 buffer = inputBuffer.trim();\n const isRequired = REQUIRED_FIELDS.includes(fieldName);\n\n if (isRequired && !buffer) {\n setPhase({\n type: 'field-entry',\n field,\n values: current,\n fieldError: `${FIELD_LABELS[fieldName]} is required`,\n });\n\n return;\n }\n\n const valueToStore = fieldName === 'description' ? inputBuffer : buffer;\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 if (mode === 'sub-dir') {\n setPhase({ type: 'resolving-target' });\n\n void resolveSubDirAndConfirm(updated);\n } else {\n setPhase({ type: 'confirm', values: updated });\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 === 'confirm') {\n if (key.escape) {\n const lastField = FIELDS.length - 1;\n const lastName = FIELDS[lastField];\n\n setPhase({ type: 'field-entry', field: lastField, values: phase.values });\n\n setInputBuffer(lastName ? phase.values[lastName] : '');\n\n return;\n }\n\n if (key.return) {\n setPhase({ type: 'writing' });\n\n void runWrite(phase.values, targetDir);\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 === '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 });\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 dimColor>Also creates:</Text>\n <Text dimColor>\n {' '}\n {join(targetDir, 'src/')}\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>{' '}appbuilder dev</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 { join } from 'node:path';\nimport { ensureGitignore } from './gitignore.js';\n\nexport interface CreatePluginInput {\n targetDir: string;\n name: string;\n apiName: string;\n externalLink: string;\n description: string;\n developerBusinessId: string;\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 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: ['prod'],\n config_template: {},\n base_config: {},\n developer_business_id: input.developerBusinessId,\n };\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 ensureGitignore(input.targetDir);\n}\n","import { mkdir, readFile, readdir, writeFile } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { dirname, join } from 'node:path';\nimport { ENVIRONMENTS, type Environment, type Credentials } from '../../shared/lib/credentials.js';\nexport { ENVIRONMENTS, type Environment, type Credentials } 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 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 = obj.environment;\n\n return {\n apiKey: typeof obj.apiKey === 'string' ? obj.apiKey : '',\n userId: typeof obj.userId === 'string' ? obj.userId : '',\n businessId: typeof obj.businessId === 'string' ? obj.businessId : '',\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 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","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","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 .action(\n async (options: {\n port: string;\n credentials?: string;\n debug?: boolean;\n verbose?: boolean;\n viewer?: 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\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 }),\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 { 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';\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}\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}) => {\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 [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 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 const message = err instanceof Error ? err.message : String(err);\n\n setBuildError(message);\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 );\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]);\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 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' && <Text color=\"red\">✗ {buildError ?? 'unknown 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 {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 ● {proxyCacheSize} key{proxyCacheSize !== 1 ? 's' : ''} in the network cache ·{' '}\n {proxyCacheHits} hit · {proxyCacheMisses} miss\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 { executePythonStep } from './pythonExecutor.js';\nimport { SKIP_DIRS } from '../lib/readFiles.js';\nimport { TEXT_EXTENSIONS } from '../../shared/lib/fileExtensions.js';\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\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\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): (req: IncomingMessage, res: ServerResponse) => void {\n const proxyCache = createProxyCache({ onChange: onProxyCacheChange });\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(credentialsRef.current !== null ? JSON.stringify(credentialsRef.current) : '{}');\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\n await saveConfig(outputDir, {\n credentialMode: 'global',\n ...(active !== undefined && { activeCredentialProfile: active }),\n });\n\n broadcast({ type: 'credentials-updated', credentials: creds });\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/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, string>;\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 scriptRuntime: body.scriptRuntime ?? 'python-3.9',\n inputs: 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.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 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 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}\n\ninterface CacheEntry {\n insertedAt: number;\n promise: Promise<CachedResponse>;\n}\n\nexport function createProxyCache(options: ProxyCacheOptions = {}): ProxyCache {\n const cache = new Map<string, CacheEntry>();\n const { onChange } = options;\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(async (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 .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","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}\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 { 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 { type ExecutionResult, type HttpRequests } 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, string>;\n secrets: Record<string, string>;\n timeout?: number;\n onInstallProgress?: VenvInstallListener;\n}\n\nconst VENV_DIR = join(process.cwd(), '.kizenapp', 'venv');\nconst VENV_PACKAGES = [\n 'awslambdaric',\n 'bcrypt',\n 'fpdf2',\n 'lxml',\n 'msgpack',\n 'numpy',\n 'paramiko',\n 'pyjwt',\n 'pypdf',\n 'pytz',\n 'requests',\n 'tzdata',\n];\n\nlet venvReady: Promise<string> | null = null;\n\nfunction resolvePythonBinary(runtime: string): string {\n // e.g. \"python-3.9\" -> try \"python3.9\" first\n const match = /^python-(\\d+\\.\\d+)$/.exec(runtime);\n\n if (match?.[1]) {\n return `python${match[1]}`;\n }\n\n return 'python3';\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\nconst installListeners = new Set<VenvInstallListener>();\n\nfunction emitInstall(event: VenvInstallEvent): void {\n for (const listener of installListeners) {\n listener(event);\n }\n}\n\nfunction ensureVenv(runtime: string, listener?: VenvInstallListener): Promise<string> {\n if (listener) {\n installListeners.add(listener);\n }\n\n if (!venvReady) {\n venvReady = (async () => {\n const venvPython = join(VENV_DIR, 'bin', 'python');\n\n try {\n await access(venvPython);\n } catch {\n const systemPython = resolvePythonBinary(runtime);\n\n await runCommand(systemPython, ['-m', 'venv', VENV_DIR]);\n }\n\n emitInstall({ kind: 'start' });\n\n try {\n await runCommand(\n venvPython,\n ['-m', 'pip', 'install', '--disable-pip-version-check', ...VENV_PACKAGES],\n (line, stream) => {\n emitInstall({ kind: 'log', line, stream });\n },\n );\n\n emitInstall({ kind: 'complete' });\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n\n emitInstall({ kind: 'error', message });\n\n // Reset so the next call retries rather than returning the cached\n // rejection forever. Also nuke the venv dir: if `python -m venv`\n // failed mid-create, the remnants will confuse the access() check\n // on the next attempt. rm is best-effort — we'll rebuild either 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 installListeners.clear();\n }\n\n return venvPython;\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\nexport async function executePythonStep(params: ExecuteStepParams): Promise<ExecutionResult> {\n const timeout = params.timeout ?? DEFAULT_TIMEOUT;\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","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 | { kind: 'request'; method: string; status: number; fromCache: boolean; url: string }\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\n return `${entry.method} ${entry.url} → ${String(entry.status)}${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 CDPRemoteObject {\n type: string;\n subtype?: string;\n value?: unknown;\n description?: string;\n objectId?: string;\n preview?: CDPObjectPreview;\n}\n\ninterface CDPPropertyPreview {\n name: string;\n type: string;\n value?: string;\n subtype?: string;\n valuePreview?: CDPObjectPreview;\n}\n\ninterface CDPObjectPreview {\n type: string;\n subtype?: string;\n overflow: boolean;\n properties: CDPPropertyPreview[];\n}\n\ninterface CDPConsoleEvent {\n type: string;\n args: CDPRemoteObject[];\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 Runtime: {\n enable: () => Promise<void>;\n consoleAPICalled: (handler: (params: CDPConsoleEvent) => void) => void;\n callFunctionOn: (opts: {\n objectId: string;\n functionDeclaration: string;\n returnByValue: boolean;\n }) => Promise<{ result: { value?: unknown } }>;\n };\n Target: {\n setAutoAttach: (opts: {\n autoAttach: boolean;\n waitForDebuggerOnStart: boolean;\n flatten: boolean;\n }) => Promise<void>;\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) => 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 CDPAttachedToTargetEvent {\n sessionId: string;\n targetInfo: { targetId: string; type: string; url: string };\n waitingForDebugger: boolean;\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\nfunction parseProp(prop: CDPPropertyPreview): unknown {\n if (prop.type === 'number') {\n return Number(prop.value);\n }\n\n if (prop.type === 'boolean') {\n return prop.value === 'true';\n }\n\n if (prop.type === 'undefined') {\n return undefined;\n }\n\n if (prop.type === 'object' && prop.value === 'null') {\n return null;\n }\n\n if (prop.type === 'object' && prop.valuePreview) {\n const { valuePreview } = prop;\n\n if (valuePreview.subtype === 'array') {\n return valuePreview.properties\n .filter((p) => /^\\d+$/.test(p.name))\n .sort((a, b) => parseInt(a.name) - parseInt(b.name))\n .map(parseProp);\n }\n\n const obj: Record<string, unknown> = {};\n\n for (const p of valuePreview.properties) {\n obj[p.name] = parseProp(p);\n }\n\n return obj;\n }\n\n return prop.value ?? `[${prop.type}]`;\n}\n\nfunction serializeArg(arg: CDPRemoteObject): unknown {\n if (arg.value !== undefined) {\n return arg.value;\n }\n\n if (arg.preview) {\n const { preview } = arg;\n\n if (preview.subtype === 'array') {\n return preview.properties\n .filter((p) => /^\\d+$/.test(p.name))\n .sort((a, b) => parseInt(a.name) - parseInt(b.name))\n .map(parseProp);\n }\n\n const obj: Record<string, unknown> = {};\n\n for (const prop of preview.properties) {\n obj[prop.name] = parseProp(prop);\n }\n\n return obj;\n }\n\n return arg.description ?? `[${arg.type}]`;\n}\n\nasync function serializeArgAsync(client: CDPClient, arg: CDPRemoteObject): Promise<unknown> {\n if (arg.type === 'object' && arg.objectId) {\n try {\n const result = await client.Runtime.callFunctionOn({\n objectId: arg.objectId,\n functionDeclaration:\n 'function() { const seen = new WeakSet(); return JSON.stringify(this, function(k,v) { if (typeof v === \"object\" && v !== null) { if (seen.has(v)) return \"[Circular]\"; seen.add(v); } return v; }); }',\n returnByValue: true,\n });\n const val = result.result.value;\n\n if (typeof val === 'string') {\n return JSON.parse(val) as unknown;\n }\n } catch {\n // fall through to preview-based serialization\n }\n }\n\n return serializeArg(arg);\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 ],\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 await c.send('Runtime.enable', { generatePreview: true });\n\n // Child targets (iframes, popups, nested pages) auto-attach with their own\n // sessionIds. Runtime.enable is per-session, so without this the main page\n // works but sandbox/plugin frames are silent. Register before setAutoAttach\n // so we don't miss the first attach event.\n c.on('Target.attachedToTarget', (rawParams: unknown) => {\n const params = rawParams as CDPAttachedToTargetEvent;\n const { sessionId, targetInfo } = params;\n\n vb(`attached session ${sessionId} (${targetInfo.type} ${targetInfo.url})`);\n\n void c.send('Runtime.enable', { generatePreview: true }, sessionId).catch((e: unknown) => {\n vb(` Runtime.enable on session ${sessionId} failed: ${(e as Error).message}`);\n });\n });\n\n await c.Target.setAutoAttach({\n autoAttach: true,\n waitForDebuggerOnStart: false,\n flatten: true,\n });\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 c.on('Runtime.consoleAPICalled', (rawParams: unknown) => {\n void (async () => {\n const { type, args } = rawParams as CDPConsoleEvent;\n\n if (args[0]?.type === 'string' && String(args[0].value).includes('Chrome Security')) {\n return;\n }\n\n const level =\n type === 'warning'\n ? 'warn'\n : ['log', 'warn', 'error', 'info'].includes(type)\n ? type\n : 'log';\n\n vb(`console.${level} (${String(args.length)} arg(s))`);\n\n const serialized = await Promise.all(args.map((arg) => serializeArgAsync(c, arg)));\n\n opts.broadcast({ type: 'console-message', level, args: serialized });\n })().catch((e: unknown) => {\n vb(`console serialization failed: ${(e as Error).message}`);\n });\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 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 apiKey: values.apiKey ?? '',\n userId: values.userId ?? '',\n businessId: values.businessId ?? '',\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 { 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 type { FileContent } from '@kizenapps/packager';\n\nconst SENSITIVE_FIELDS = new Set(['developer_business_id']);\n\nfunction 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\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\ninterface TreeNode {\n name: string;\n children: Map<string, TreeNode>;\n isFile: boolean;\n filePath: string;\n}\n\nfunction 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 fileId(path: string): string {\n return 'file-' + path.replace(/[^a-zA-Z0-9]/g, '-');\n}\n\nfunction esc(str: string): string {\n return str\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"');\n}\n\nfunction renderTree(node: TreeNode): string {\n const sorted = [...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 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 fileExt(path: string): string {\n const idx = path.lastIndexOf('.');\n\n return idx >= 0 ? path.slice(idx).toLowerCase() : '';\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\nfunction generateHtml(manifest: Record<string, unknown>, files: FileContent[]): string {\n const filtered = 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 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 = files.filter(\n (f) => f.path !== 'kizen.json' && f.path !== 'plugin-report.html',\n );\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\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 outputPath = options.output ?? join(EXAMPLES_DIR, `${apiName}.html`);\n\n const files = await readLocalFiles(pluginDir);\n const html = generateHtml(manifest, files);\n\n await mkdir(join(outputPath, '..'), { recursive: true });\n await writeFile(outputPath, html, 'utf-8');\n console.log(`Plugin report written to: ${outputPath}`);\n });\n}\n"],"mappings":"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","names":["readFileSync","dirname","join","fileURLToPath","program","createElement","render","useEffect","useState","Box","Text","useApp","mkdir","writeFile","join","minifyFiles","packagePlugin","transformDeployablePlugin","readdir","readFile","join","relative","IMAGE_EXTENSIONS","BINARY_EXTENSIONS","SKIP_FILES","SKIP_DIRS","walk","dir","rootDir","entries","paths","entry","readLocalFiles","absolutePaths","absPath","relPath","dotIndex","ext","buf","content","REQUIRED_MANIFEST_FIELDS","validateManifestObject","manifest","index","label","field","value","parseManifest","content","parsed","err","detail","entry","i","serializePlugin","plugin","allReleaseNotes","runBuild","pluginDir","outputDir","onStep","mkdir","files","readLocalFiles","minified","minifyFiles","manifestFile","f","manifests","packaged","packagePlugin","deployable","transformDeployablePlugin","bundle","notesDir","a","b","jsonStr","stripReleaseNotes","key","bundleSize","writeFile","join","formatBytes","n","Box","Text","Box","Text","jsx","LOGO_LINES","Logo","line","i","Fragment","jsx","jsxs","AppHeader","marginBottom","Logo","Box","Text","useEffect","useState","Text","jsx","SPINNER_FRAMES","Spinner","frame","setFrame","id","prev","Fragment","jsx","jsxs","STEPS","STEP_LABELS","BuildUI","outputDir","pluginDir","app","useApp","step","setStep","useState","errorMessage","setErrorMessage","bundleSize","setBundleSize","useEffect","runBuild","size","err","message","currentIndex","isError","isDone","Box","AppHeader","s","i","isActive","isStepDone","Text","Spinner","formatBytes","fs","path","ensureGitignore","projectDir","gitignorePath","entry","contents","lines","l","addition","buildCommand","program","pluginDir","outputDir","ensureGitignore","waitUntilExit","render","createElement","BuildUI","createElement","render","useCallback","useState","Box","Text","useApp","useInput","join","access","mkdir","writeFile","join","pathExists","path","access","precheckTargetDir","dir","join","findAvailableSubDir","parentDir","baseName","base","i","candidate","buildManifest","input","createPlugin","mkdir","manifest","writeFile","ensureGitignore","jsx","jsxs","FIELDS","FIELD_LABELS","REQUIRED_FIELDS","inferApiName","name","Hint","text","Text","emptyValues","defaultBusinessId","CreateUI","parentDir","app","useApp","phase","setPhase","useState","mode","setMode","values","setValues","inputBuffer","setInputBuffer","targetDir","setTargetDir","enterFieldEntry","useCallback","nextMode","initialValues","runPrecheck","dir","result","precheckTargetDir","resolveSubDirAndConfirm","finalValues","findAvailableSubDir","err","runWrite","createPlugin","useInput","input","key","field","current","fieldName","prev","updated","prevField","prevName","buffer","valueToStore","nextField","nextName","existing","nextBuffer","lastField","lastName","options","Box","AppHeader","opt","i","selected","reason","activeField","fieldError","targetLine","isActive","displayValue","isRequired","label","manifest","buildManifest","join","mkdir","readFile","readdir","writeFile","homedir","dirname","join","ENVIRONMENTS","GLOBAL_CREDENTIALS_DIR","join","homedir","GLOBAL_CREDENTIALS_PATH","DEFAULT_PROFILE_NAME","isValidEnvironment","value","ENVIRONMENTS","parseCredentials","raw","obj","env","loadCredentialsFromFile","filePath","content","readFile","loadGlobalCredentials","saveGlobalCredentials","credentials","mkdir","dirname","writeFile","getProfilePath","name","listCredentialProfiles","profiles","entries","readdir","entry","saveCredentialProfile","loadCredentialProfile","createCommand","program","parentDir","defaultBusinessId","loadGlobalCredentials","waitUntilExit","render","createElement","CreateUI","createElement","render","useCallback","useEffect","useRef","useState","Box","Text","useInput","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","createProxyCache","options","cache","onChange","emitChange","evict","fetcher","existing","oldest","pending","error","MIME_TYPES","mkdir","readFile","writeFile","join","loadConfig","outputDir","content","saveConfig","config","spawn","writeFile","rm","mkdtemp","access","join","tmpdir","WRAPPER_SCRIPT","DEFAULT_TIMEOUT","VENV_DIR","join","VENV_PACKAGES","venvReady","resolvePythonBinary","runtime","match","runCommand","bin","args","onLine","resolve","reject","proc","spawn","pipeLines","source","stream","captured","buffer","chunk","idx","line","stderrCaptured","code","tail","detail","installListeners","emitInstall","event","listener","ensureVenv","venvPython","access","systemPython","err","message","rm","parseResult","stdout","startMarker","endMarker","startIdx","endIdx","userStdout","jsonStr","result","executePythonStep","params","timeout","pythonBin","start","tmpDir","mkdtemp","tmpdir","wrapperPath","scriptPath","writeFile","env","exitCode","stderr","stdoutChunks","stderrChunks","settled","timer","finish","durationMs","base","TEXT_EXTENSIONS","proxyLogEntryToString","entry","cache","SOURCE_FILE_MAX_BYTES","SKIP_FILES","isLocalHost","host","hostname","PROXY_ALLOWED_DOMAINS","isAllowedProxyTarget","target","url","domain","isLocalOrigin","origin","resolveSafePath","realPluginDir","relParam","rel","abs","resolve","sep","realAbs","realpath","isInsideSkippedDir","pluginDir","segment","SKIP_DIRS","getViewerPath","filename","fileURLToPath","join","dirname","fileExists","filePath","access","createRequestHandler","viewerPath","createServerLog","createProxyLog","credentialsRef","activeProfileRef","outputDir","broadcast","onProxyCacheChange","lastPathRef","proxyCache","createProxyCache","realpathSync","req","res","profiles","listCredentialProfiles","chunks","chunk","profileName","creds","loadGlobalCredentials","loadCredentialProfile","active","saveConfig","bundlePath","content","readFile","body","currentConfig","loadConfig","stepParams","event","result","executePythonStep","proxyTarget","upstreamPath","upstreamUrl","method","_drop","forwardHeaders","cacheKey","cached","fromCache","resolvedBody","upstream","responseHeaders","sanitizeUpstreamHeaders","responseBody","readBodyWithLimit","MAX_PROXY_BYTES","dirEntries","readdir","entries","entry","kind","stats","stat","a","b","normalizedPath","err","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","parseProp","prop","valuePreview","p","a","b","obj","serializeArg","arg","preview","serializeArgAsync","client","val","installDockIcon","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","sessionId","targetInfo","handleTarget","type","args","level","serialized","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","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","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","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","watcher","watch","_","filename","normalized","prefix","viewerPath","getViewerPath","fileExists","viewerBuilt","handler","createRequestHandler","server","createServer","wss","WebSocketServer","ws","CredentialSetupUI","elapsedSeconds","elapsedLabel","Box","AppHeader","Text","Spinner","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","waitUntilExit","DevUI","mkdir","writeFile","readFile","join","SENSITIVE_FIELDS","redactServices","services","svc","s","redacted","k","IMAGE_MIME","buildTree","files","root","file","parts","node","part","i","next","fileId","path","esc","str","renderTree","a","b","child","fileExt","idx","renderFileSection","body","generateHtml","manifest","filtered","v","name","version","description","sourceFiles","f","treeHtml","fileSections","EXAMPLES_DIR","join","GLOBAL_CREDENTIALS_DIR","reportCommand","program","options","pluginDir","raw","readFile","parsed","apiName","outputPath","readLocalFiles","html","mkdir","writeFile","pkgPath","join","dirname","fileURLToPath","pkg","readFileSync","program","createCommand","buildCommand","devCommand","reportCommand"]}
|