@kittl/cli 0.0.5 → 0.0.7

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.
@@ -2,7 +2,7 @@ import {
2
2
  API_CONFIG,
3
3
  CLI_CONFIG,
4
4
  parseJsonObjectFromFile
5
- } from "./chunk-BGJHRFGJ.js";
5
+ } from "./chunk-F62NYF5U.js";
6
6
 
7
7
  // src/core/error.ts
8
8
  import { isAxiosError } from "axios";
@@ -140,4 +140,4 @@ export {
140
140
  readInternalConfig,
141
141
  writeInternalConfig
142
142
  };
143
- //# sourceMappingURL=chunk-A2IV54MU.js.map
143
+ //# sourceMappingURL=chunk-344EUO2O.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  BaseCommand
3
- } from "./chunk-BGJHRFGJ.js";
3
+ } from "./chunk-F62NYF5U.js";
4
4
 
5
5
  // src/commands/auth/whoami.ts
6
6
  import { jwtDecode } from "jwt-decode";
@@ -26,4 +26,4 @@ var AuthWhoAmI = class _AuthWhoAmI extends BaseCommand {
26
26
  export {
27
27
  AuthWhoAmI
28
28
  };
29
- //# sourceMappingURL=chunk-O3BDWSZ5.js.map
29
+ //# sourceMappingURL=chunk-7OPTDFSA.js.map
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  formatZodErrorSummary
3
- } from "./chunk-A2IV54MU.js";
3
+ } from "./chunk-344EUO2O.js";
4
4
  import {
5
5
  parseJsonObjectFromFile
6
- } from "./chunk-BGJHRFGJ.js";
6
+ } from "./chunk-F62NYF5U.js";
7
7
 
8
8
  // src/services/extensions.service.ts
9
9
  import { z as z2 } from "zod";
@@ -99,4 +99,4 @@ export {
99
99
  createExtensionDraftVersion,
100
100
  markExtensionDraftReadyForReview
101
101
  };
102
- //# sourceMappingURL=chunk-75SESNHC.js.map
102
+ //# sourceMappingURL=chunk-E5EOPARA.js.map
@@ -101,7 +101,7 @@ function chunkArray(items, chunkSize) {
101
101
  // package.json
102
102
  var package_default = {
103
103
  name: "@kittl/cli",
104
- version: "0.0.5",
104
+ version: "0.0.7",
105
105
  license: "Apache-2.0",
106
106
  private: false,
107
107
  type: "module",
@@ -127,7 +127,7 @@ var package_default = {
127
127
  "dist"
128
128
  ],
129
129
  scripts: {
130
- prepack: "pnpm run build && clean-package",
130
+ prepack: "npx --yes only-allow pnpm && pnpm run build && clean-package",
131
131
  postpack: "clean-package restore",
132
132
  build: "tsup && oclif manifest",
133
133
  "build:watch": 'tsup --watch --onSuccess "oclif manifest"',
@@ -139,6 +139,8 @@ var package_default = {
139
139
  },
140
140
  dependencies: {
141
141
  "@oclif/core": "^4.10.2",
142
+ "@oclif/plugin-autocomplete": "^3.2.45",
143
+ "@oclif/plugin-warn-if-update-available": "^3.1.60",
142
144
  axios: "^1.13.6",
143
145
  "cross-keychain": "^1.1.0",
144
146
  ink: "^6.8.0",
@@ -164,10 +166,25 @@ var package_default = {
164
166
  vitest: "^4.1.1"
165
167
  },
166
168
  oclif: {
169
+ additionalHelpFlags: [
170
+ "-h"
171
+ ],
172
+ additionalVersionFlags: [
173
+ "-v"
174
+ ],
167
175
  bin: "kittl",
168
176
  commands: "./dist/commands",
169
177
  dirname: "kittl",
170
- topicSeparator: " "
178
+ plugins: [
179
+ "@oclif/plugin-autocomplete",
180
+ "@oclif/plugin-warn-if-update-available"
181
+ ],
182
+ topicSeparator: " ",
183
+ "warn-if-update-available": {
184
+ frequency: 10,
185
+ frequencyUnit: "minutes",
186
+ message: "\n<%= chalk.yellow('A newer Kittl CLI is available!') %> <%= chalk.dim(config.version) %> -> <%= chalk.greenBright(latest) %>\n<%= chalk.cyan('Update: npm i -g @kittl/cli@latest') %>\n"
187
+ }
171
188
  }
172
189
  };
173
190
 
@@ -781,4 +798,4 @@ export {
781
798
  authService,
782
799
  BaseCommand
783
800
  };
784
- //# sourceMappingURL=chunk-BGJHRFGJ.js.map
801
+ //# sourceMappingURL=chunk-F62NYF5U.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/files.ts","../src/core/utils.ts","../package.json","../src/constants.ts","../src/services/auth.service.ts","../src/services/session-vault.service.ts","../src/core/core.command.ts","../src/services/api.service.ts","../src/ui/renderer.ts"],"sourcesContent":["import { basename } from 'node:path';\nimport { lookup } from 'mime-types';\nimport { glob } from 'tinyglobby';\n\n/**\n * Last path segment\n */\nexport function getFileNameFromPath(filePath: string): string | undefined {\n const leaf = basename(filePath.trim());\n if (leaf === '' || leaf === '.' || leaf === '..') {\n return undefined;\n }\n return leaf;\n}\n\n/**\n * All files under `rootAbs` (recursive), absolute paths.\n * Does not traverse symlinked directories.\n */\nexport async function listAllFilesUnderDir(rootAbs: string): Promise<string[]> {\n return glob('**/*', {\n cwd: rootAbs,\n absolute: true,\n onlyFiles: true,\n dot: true,\n followSymbolicLinks: false,\n });\n}\n\n/**\n * Extension-based MIME for a path or basename. Unknown fallback to `application/octet-stream` (S3-safe).\n */\nexport function contentTypeForPath(filePath: string): string {\n const mime = lookup(filePath);\n return mime === false ? 'application/octet-stream' : mime;\n}\n","import { mkdir, readFile, stat } from 'node:fs/promises';\nimport type { Key } from 'ink';\nimport { getFileNameFromPath } from './files';\n\n/**\n * Parses a JSON string into a plain object.\n */\nexport function parseJsonObject(\n jsonText: string,\n errorContext: string,\n): Record<string, unknown> {\n let parsed: unknown;\n try {\n parsed = JSON.parse(jsonText) as unknown;\n } catch {\n throw new Error(`Invalid JSON (${errorContext})`);\n }\n if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {\n throw new Error(\n `JSON must be an object, not array or null (${errorContext})`,\n );\n }\n return parsed as Record<string, unknown>;\n}\n\n// Reads a file and parses its contents as a JSON object.\nexport async function parseJsonObjectFromFile(\n filePath: string,\n): Promise<Record<string, unknown>> {\n const jsonText = await readFile(filePath, 'utf8');\n return parseJsonObject(jsonText, filePath);\n}\n\n/**\n * Ensures `dirPath` exists as a directory: creates it (and parents) when\n * missing, or throws if the path exists and is not a directory.\n */\nexport async function ensureDirectory(dirPath: string): Promise<void> {\n try {\n const s = await stat(dirPath);\n if (!s.isDirectory()) {\n throw new Error(`${dirPath} exists and is not a directory.`);\n }\n } catch (e) {\n // Not `isSystemError` from `./error`: this module is imported by `constants.ts`.\n if (\n e instanceof Error &&\n 'code' in e &&\n (e as NodeJS.ErrnoException).code === 'ENOENT'\n ) {\n await mkdir(dirPath, { recursive: true });\n return;\n }\n throw e;\n }\n}\n\n// Silent UI teardown (e.g. Ink unmount). not user-initiated cancel.\nexport const INK_VIEW_UNMOUNT_REASON = Symbol('INK_VIEW_UNMOUNT_REASON');\n\n/**\n * Reads `process.env[envKey]` as a TCP port, or {@link defaultPort} when unset/blank.\n * Must be an integer in 1–65535 when set.\n */\nexport function parsePortFromEnv(envKey: string, defaultPort: number): number {\n const raw = process.env[envKey];\n const n = Number(raw?.trim() || defaultPort);\n if (!Number.isInteger(n) || n < 1 || n > 65_535) {\n throw new Error(\n `${envKey} must be an integer between 1 and 65535 (got ${JSON.stringify(raw)}).`,\n );\n }\n return n;\n}\n\n// Fixed localhost OAuth callback path for Authorization Code + PKCE.\nexport function localhostOAuthRedirectUri(port: number): string {\n return `http://localhost:${port}/callback`;\n}\n\nexport function getKittlEnvEntries(): string[] {\n return Object.entries(process.env)\n .filter(([key]) => key.startsWith('KITTL_'))\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([key, value]) => `${key}=${value ?? ''}`);\n}\n\n// Enter key across terminal variants (`return` + optional `enter`).\nexport function isSubmitKey(key: Key): boolean {\n if (key.return) {\n return true;\n }\n return Boolean((key as Key & { enter?: boolean }).enter);\n}\n\n/**\n * Resolves a file name from an env value via {@link getFileNameFromPath};\n * empty or invalid values fall back to `defaultFileName`.\n */\nexport function resolveFileNameFromEnv(\n envValue: string | undefined,\n defaultFileName: string,\n): string {\n const raw = envValue?.trim() ?? '';\n if (raw === '') {\n return defaultFileName;\n }\n return getFileNameFromPath(raw) ?? defaultFileName;\n}\n\n// Split an array into consecutive slices of at most `chunkSize` items.\nexport function chunkArray<T>(items: T[], chunkSize: number): T[][] {\n if (chunkSize < 1) {\n throw new Error('chunkSize must be at least 1');\n }\n const n = Math.ceil(items.length / chunkSize);\n return Array.from({ length: n }, (_, i) =>\n items.slice(i * chunkSize, i * chunkSize + chunkSize),\n );\n}\n","{\n \"name\": \"@kittl/cli\",\n \"version\": \"0.0.7\",\n \"license\": \"Apache-2.0\",\n \"private\": false,\n \"type\": \"module\",\n \"engines\": {\n \"node\": \">=18\"\n },\n \"bin\": {\n \"kittl\": \"./bin/run.js\",\n \"kittl-dev\": \"./bin/dev.js\"\n },\n \"publishConfig\": {\n \"access\": \"public\",\n \"bin\": {\n \"kittl\": \"./bin/run.js\"\n }\n },\n \"files\": [\n \"LICENSE\",\n \"oclif.manifest.json\",\n \"bin/bootstrap.js\",\n \"bin/run.cmd\",\n \"bin/run.js\",\n \"dist\"\n ],\n \"scripts\": {\n \"prepack\": \"npx --yes only-allow pnpm && pnpm run build && clean-package\",\n \"postpack\": \"clean-package restore\",\n \"build\": \"tsup && oclif manifest\",\n \"build:watch\": \"tsup --watch --onSuccess \\\"oclif manifest\\\"\",\n \"dev\": \"node ./bin/dev.js\",\n \"dev:watch\": \"node --watch --watch-path=./src --watch-path=./bin ./bin/dev.js\",\n \"typecheck\": \"tsc --noEmit\",\n \"test\": \"vitest run\",\n \"test:watch\": \"vitest\"\n },\n \"dependencies\": {\n \"@oclif/core\": \"^4.10.2\",\n \"@oclif/plugin-autocomplete\": \"^3.2.45\",\n \"@oclif/plugin-warn-if-update-available\": \"^3.1.60\",\n \"axios\": \"^1.13.6\",\n \"cross-keychain\": \"^1.1.0\",\n \"ink\": \"^6.8.0\",\n \"ink-text-input\": \"^6.0.0\",\n \"jwt-decode\": \"^4.0.0\",\n \"mime-types\": \"^3.0.1\",\n \"open\": \"^11.0.0\",\n \"openid-client\": \"^6.8.2\",\n \"react\": \"catalog:\",\n \"tinyglobby\": \"^0.2.15\",\n \"zod\": \"catalog:\"\n },\n \"devDependencies\": {\n \"@types/mime-types\": \"^3.0.1\",\n \"@types/node\": \"^25.5.0\",\n \"@types/react\": \"catalog:\",\n \"clean-package\": \"^2.2.0\",\n \"ink-testing-library\": \"^4.0.0\",\n \"oclif\": \"^4.22.96\",\n \"tsup\": \"catalog:\",\n \"tsx\": \"catalog:\",\n \"typescript\": \"catalog:\",\n \"vitest\": \"^4.1.1\"\n },\n \"oclif\": {\n \"additionalHelpFlags\": [\n \"-h\"\n ],\n \"additionalVersionFlags\": [\n \"-v\"\n ],\n \"bin\": \"kittl\",\n \"commands\": \"./dist/commands\",\n \"dirname\": \"kittl\",\n \"plugins\": [\n \"@oclif/plugin-autocomplete\",\n \"@oclif/plugin-warn-if-update-available\"\n ],\n \"topicSeparator\": \" \",\n \"warn-if-update-available\": {\n \"frequency\": 10,\n \"frequencyUnit\": \"minutes\",\n \"message\": \"\\n<%= chalk.yellow('A newer Kittl CLI is available!') %> <%= chalk.dim(config.version) %> -> <%= chalk.greenBright(latest) %>\\n<%= chalk.cyan('Update: npm i -g @kittl/cli@latest') %>\\n\"\n }\n }\n}\n","import pkg from '../package.json' with { type: 'json' };\nimport {\n localhostOAuthRedirectUri,\n parsePortFromEnv,\n resolveFileNameFromEnv,\n} from './core/utils';\n\nconst { version } = pkg;\n\nconst CLI_CONFIG_DIR = '.kittl' as const;\nconst CLI_CONFIG_DEFAULT_FILENAME = 'config.json' as const;\nconst CLI_MANIFEST_DEFAULT_FILENAME = 'manifest.json' as const;\n\nexport const PRODUCTION = {\n issuer: 'https://keycloak.kittl.dev/auth/realms/kittl',\n apiBaseUrl: 'https://api.kittl.com',\n clientId: 'kittl-cli',\n redirectPort: 51771,\n scaffoldViteDevPort: 5173,\n} as const;\n\n// -----------------------------------------------------------------------------\n// CLI configs\n// -----------------------------------------------------------------------------\n\nexport const CLI_CONFIG = {\n configDir: CLI_CONFIG_DIR,\n defaultConfigFileName: CLI_CONFIG_DEFAULT_FILENAME,\n configFileName: resolveFileNameFromEnv(\n process.env.KITTL_CONFIG_FILENAME,\n CLI_CONFIG_DEFAULT_FILENAME,\n ),\n defaultManifestFileName: CLI_MANIFEST_DEFAULT_FILENAME,\n manifestFileName: resolveFileNameFromEnv(\n process.env.KITTL_EXTENSION_MANIFEST_FILENAME,\n CLI_MANIFEST_DEFAULT_FILENAME,\n ),\n scaffoldViteDevPort: parsePortFromEnv(\n 'KITTL_SCAFFOLD_VITE_DEV_PORT',\n PRODUCTION.scaffoldViteDevPort,\n ),\n} as const;\n\n// -----------------------------------------------------------------------------\n// OAuth / OIDC (PKCE login, keychain session)\n// -----------------------------------------------------------------------------\n\nconst authRedirectPort = parsePortFromEnv(\n 'KITTL_REDIRECT_PORT',\n PRODUCTION.redirectPort,\n);\n\nexport const AUTH_CONFIG = {\n issuer: process.env.KITTL_OAUTH_ISSUER_URL ?? PRODUCTION.issuer,\n clientId: process.env.KITTL_OAUTH_CLIENT_ID ?? PRODUCTION.clientId,\n redirectPort: authRedirectPort,\n redirectUri: localhostOAuthRedirectUri(authRedirectPort),\n scope: process.env.KITTL_OAUTH_SCOPE ?? 'openid profile email offline_access',\n // https://www.keycloak.org/docs/latest/server_admin/index.html#_authentication-sessions\n authPrompt: process.env.KITTL_OAUTH_PROMPT || 'login',\n oauthCallbackTimeoutMs: Number(\n process.env.KITTL_OAUTH_CALLBACK_TIMEOUT_MS ?? 120_000,\n ),\n /** Optional 302 after OAuth; if undefined it renders a fallback HTML. */\n oauthSuccessRedirectUrl:\n process.env.KITTL_OAUTH_SUCCESS_REDIRECT_URL || undefined,\n serviceName: 'kittl-cli',\n accountName: 'oauth-session',\n} as const;\n\n// -----------------------------------------------------------------------------\n// HTTP API (Axios base URL for Kittl APIs)\n// -----------------------------------------------------------------------------\n\nexport const API_CONFIG = {\n baseUrl: process.env.KITTL_API_BASE_URL ?? PRODUCTION.apiBaseUrl,\n timeoutMs: 30_000,\n userAgent: `kittl-cli/${version}`,\n} as const;\n","import { createServer } from 'node:http';\nimport { URL } from 'node:url';\nimport open from 'open';\nimport * as oidc from 'openid-client';\nimport { z } from 'zod';\nimport { AUTH_CONFIG } from '../constants';\nimport type { Session } from '../types/session';\nimport { sessionVault } from './session-vault.service';\n\n// Seconds before access token expiry when we proactively refresh.\nconst ACCESS_TOKEN_REFRESH_BUFFER_SEC = 60;\n\nconst OAUTH2_TOKEN_ERROR_INVALID_GRANT = 'invalid_grant';\n\nexport type LoginOptions = {\n signal?: AbortSignal;\n};\n\nexport type CallbackResult = {\n callbackUrl: URL;\n};\n\nconst authConfigSchema = z.object({\n issuer: z.url(),\n clientId: z.string().min(1),\n redirectUri: z.url(),\n redirectPort: z.number().int().min(1).max(65_535),\n scope: z.string().min(1),\n authPrompt: z.string().min(1),\n oauthCallbackTimeoutMs: z.number().int().min(5_000).max(3_600_000),\n oauthSuccessRedirectUrl: z.url().optional(),\n});\n\nexport class LoginCancelledError extends Error {\n public constructor() {\n super('Login cancelled.');\n this.name = 'LoginCancelledError';\n }\n}\n\nexport class AuthService {\n private readonly config = authConfigSchema.parse(AUTH_CONFIG);\n\n // concurrent refresh attempts are merged into a single promise\n private refreshSessionPromise: Promise<Session | null> | null = null;\n\n /**\n * raw vault read.\n */\n public async getStoredSession(): Promise<Session | null> {\n return sessionVault.getSession();\n }\n\n /**\n * ensures token freshness (by silently refresh if needed)\n */\n public async getSession(): Promise<Session | null> {\n await this.getAccessToken();\n return this.getStoredSession();\n }\n\n /**\n * Returns a usable access token, silently refreshing when `expiresAt` is within {@link ACCESS_TOKEN_REFRESH_BUFFER_SEC}\n * seconds (or in the past). based on Session.expiresAt.\n */\n public async getAccessToken(): Promise<string | undefined> {\n const session = await this.getStoredSession();\n if (!session?.accessToken) return undefined;\n\n if (!this.shouldRefreshAccessToken(session)) {\n return session.accessToken;\n }\n\n if (!session.refreshToken) {\n await sessionVault.clear();\n return undefined;\n }\n\n const refreshed = await this.refreshSession();\n return refreshed?.accessToken;\n }\n\n /**\n * Refresh tokens via the OIDC token endpoint. On hard failure (e.g. `invalid_grant`), clears the vault.\n */\n public async refreshSession(): Promise<Session | null> {\n if (this.refreshSessionPromise) {\n return this.refreshSessionPromise;\n }\n this.refreshSessionPromise = this.performRefreshSession().finally(() => {\n this.refreshSessionPromise = null;\n });\n return this.refreshSessionPromise;\n }\n\n private shouldRefreshAccessToken(session: Session): boolean {\n if (session.expiresAt === undefined) return false;\n const now = Math.floor(Date.now() / 1000);\n return session.expiresAt <= now + ACCESS_TOKEN_REFRESH_BUFFER_SEC;\n }\n\n private async performRefreshSession(): Promise<Session | null> {\n const session = await this.getStoredSession();\n if (!session?.refreshToken) {\n await sessionVault.clear();\n return null;\n }\n\n try {\n const oidcConfig = await this.discoverOidcConfiguration();\n\n const tokenSet = await oidc.refreshTokenGrant(\n oidcConfig,\n session.refreshToken,\n { scope: this.config.scope },\n undefined,\n );\n\n const newSession = this.mapTokenSetToSession(tokenSet, session);\n\n await sessionVault.saveSession(newSession);\n return newSession;\n } catch (error) {\n if (\n error instanceof oidc.ResponseBodyError &&\n error.error === OAUTH2_TOKEN_ERROR_INVALID_GRANT\n ) {\n await sessionVault.clear();\n return null;\n }\n return null;\n }\n }\n\n private async discoverOidcConfiguration(): Promise<oidc.Configuration> {\n const issuerUrl = new URL(this.config.issuer);\n return oidc.discovery(\n issuerUrl,\n this.config.clientId,\n undefined,\n undefined,\n {\n ...(issuerUrl.protocol === 'http:'\n ? { execute: [oidc.allowInsecureRequests] as const }\n : {}),\n } as Parameters<typeof oidc.discovery>[4],\n );\n }\n\n public async login(options?: LoginOptions): Promise<Session> {\n const { signal } = options ?? {};\n\n const oidcConfig = await this.discoverOidcConfiguration();\n signal?.throwIfAborted();\n\n const codeVerifier = oidc.randomPKCECodeVerifier();\n const codeChallenge = await oidc.calculatePKCECodeChallenge(codeVerifier);\n const state = oidc.randomState();\n const nonce = oidc.randomNonce();\n\n const authorizationUrl = oidc.buildAuthorizationUrl(oidcConfig, {\n redirect_uri: this.config.redirectUri,\n response_type: 'code',\n scope: this.config.scope,\n code_challenge: codeChallenge,\n code_challenge_method: 'S256',\n state,\n nonce,\n prompt: this.config.authPrompt,\n });\n\n signal?.throwIfAborted();\n await this.openBrowser(authorizationUrl.toString());\n\n const callback = await this.waitForCallback(signal);\n\n const tokenSet = await oidc.authorizationCodeGrant(\n oidcConfig,\n callback.callbackUrl,\n {\n pkceCodeVerifier: codeVerifier,\n expectedState: state,\n expectedNonce: nonce,\n },\n );\n\n const session = this.mapTokenSetToSession(tokenSet);\n\n await sessionVault.saveSession(session);\n return session;\n }\n\n public async logout(): Promise<void> {\n await sessionVault.clear();\n }\n\n /**\n * Starts a short-lived `http` server on the host/port from the configured `redirectUri` so the IdP can\n * redirect the browser to `…/callback?code=…&state=…` (Authorization Code + PKCE). The first matching request\n * stops the server and resolves with that URL for the token exchange (`authorizationCodeGrant`).\n *\n * - **Success response:** HTTP 302 to {@link AUTH_CONFIG.oauthSuccessRedirectUrl} when set; otherwise a minimal inline HTML page.\n */\n private async waitForCallback(signal?: AbortSignal): Promise<CallbackResult> {\n const redirectUrl = new URL(this.config.redirectUri);\n const hostname = redirectUrl.hostname;\n const port = Number(redirectUrl.port);\n const pathname = redirectUrl.pathname;\n\n const timeoutSignal = AbortSignal.timeout(\n this.config.oauthCallbackTimeoutMs,\n );\n const combinedSignal =\n signal !== undefined\n ? AbortSignal.any([signal, timeoutSignal])\n : timeoutSignal;\n\n return new Promise((resolve, reject) => {\n let closed = false;\n\n const server = createServer((req, res) => {\n try {\n const requestUrl = new URL(req.url ?? '', this.config.redirectUri);\n if (requestUrl.pathname !== pathname) {\n res.statusCode = 404;\n res.end('Not Found');\n return;\n }\n\n const callbackUrl = new URL(this.config.redirectUri);\n callbackUrl.search = requestUrl.search;\n\n const brandUrl = this.config.oauthSuccessRedirectUrl;\n if (brandUrl) {\n res.writeHead(302, { Location: brandUrl });\n res.end();\n } else {\n res.statusCode = 200;\n res.setHeader('content-type', 'text/html; charset=utf-8');\n res.end(\n '<!doctype html><html><body><h2>Authentication complete.</h2><p>You can close this tab and return to the terminal.</p></body></html>',\n );\n }\n\n closeServer((closeErr?: Error) => {\n if (closeErr) {\n reject(closeErr);\n return;\n }\n resolve({ callbackUrl });\n });\n } catch (error) {\n closeServer(() => reject(error));\n }\n });\n\n const closeServer = (onClosed: (closeErr?: Error) => void): void => {\n if (closed) return;\n closed = true;\n combinedSignal.removeEventListener('abort', onCombinedAbort);\n if (!server.listening) {\n onClosed();\n return;\n }\n server.closeAllConnections();\n server.close((closeErr) => {\n onClosed(closeErr ?? undefined);\n });\n };\n\n function onCombinedAbort(): void {\n closeServer((closeErr?: Error) => {\n if (closeErr) {\n reject(closeErr);\n return;\n }\n if (signal?.aborted) {\n reject(signal.reason ?? new LoginCancelledError());\n return;\n }\n if (timeoutSignal.aborted) {\n reject(new Error('Login timed out. Please try again.'));\n return;\n }\n reject(new LoginCancelledError());\n });\n }\n\n server.on('error', (error: NodeJS.ErrnoException) => {\n closeServer(() => {\n if (error.code === 'EADDRINUSE') {\n const inUsePort =\n (error as NodeJS.ErrnoException & { port?: number }).port ?? port;\n reject(\n new Error(\n `Port ${String(inUsePort)} is already in use. Close the other app using it or set KITTL_REDIRECT_PORT to a free port, then try again.`,\n ),\n );\n return;\n }\n reject(error);\n });\n });\n\n // 1. Abort before any listen: avoids a half-started server; early exit skips `listen` entirely.\n combinedSignal.addEventListener('abort', onCombinedAbort, { once: true });\n if (combinedSignal.aborted) {\n onCombinedAbort();\n return;\n }\n\n server.listen(port, hostname);\n });\n }\n\n private async openBrowser(url: string): Promise<void> {\n await open(url);\n }\n\n private mapTokenSetToSession(\n tokenSet: oidc.TokenEndpointResponse,\n currentSession?: Session,\n ): Session {\n return {\n accessToken: tokenSet.access_token,\n refreshToken: tokenSet.refresh_token ?? currentSession?.refreshToken,\n idToken: tokenSet.id_token ?? currentSession?.idToken,\n tokenType: tokenSet.token_type ?? currentSession?.tokenType,\n expiresAt: tokenSet.expires_in\n ? Math.floor(Date.now() / 1000) + tokenSet.expires_in\n : undefined,\n };\n }\n}\n\nexport const authService = new AuthService();\n","import { deletePassword, getPassword, setPassword } from 'cross-keychain';\nimport { AUTH_CONFIG } from '../constants';\nimport type { Session } from '../types/session';\n\nconst SESSION_META_VERSION = 2 as const;\n\n// suffix for split v2 accounts: `{AUTH_CONFIG.accountName}.{suffix}`.\nconst SESSION_V2_KEY_SUFFIX = {\n meta: 'meta',\n access: 'access',\n refresh: 'refresh',\n id: 'id',\n} as const;\n\ntype SessionMetaV2 = {\n v: typeof SESSION_META_VERSION;\n tokenType?: string;\n expiresAt?: number;\n};\n\n/**\n * Persists OIDC session (tokens) in the OS credential store (e.g. Keychain).\n */\nexport class SessionVault {\n private readonly keychainService = this.buildKeychainServiceName();\n private readonly keychainAccount = AUTH_CONFIG.accountName;\n\n private buildKeychainServiceName(): string {\n try {\n const issuerUrl = new URL(AUTH_CONFIG.issuer);\n const issuerKey = this.sanitizeKeychainSegment(\n `${issuerUrl.hostname}${issuerUrl.port ? `-${issuerUrl.port}` : ''}`,\n );\n return `${AUTH_CONFIG.serviceName}-${issuerKey}`;\n } catch {\n // Keep previous behavior when issuer is not a valid URL.\n return AUTH_CONFIG.serviceName;\n }\n }\n\n private sanitizeKeychainSegment(value: string): string {\n return value.replace(/[^a-zA-Z0-9._@-]/g, '-');\n }\n\n private account(suffix: string): string {\n return `${this.keychainAccount}.${suffix}`;\n }\n\n public async getSession(): Promise<Session | null> {\n const metaRaw = await getPassword(\n this.keychainService,\n this.account(SESSION_V2_KEY_SUFFIX.meta),\n );\n\n let meta: SessionMetaV2 | null = null;\n if (metaRaw) {\n try {\n const parsed = JSON.parse(metaRaw) as SessionMetaV2;\n if (parsed.v === SESSION_META_VERSION) {\n meta = parsed;\n }\n } catch {\n meta = null;\n }\n }\n // if meta is present, read based on v2\n if (meta) {\n const accessRaw = await getPassword(\n this.keychainService,\n this.account(SESSION_V2_KEY_SUFFIX.access),\n );\n // fallback, if not defined, to legacy monolithic read\n const accessToken = accessRaw?.trim();\n if (accessToken) {\n const refreshRaw = await getPassword(\n this.keychainService,\n this.account(SESSION_V2_KEY_SUFFIX.refresh),\n );\n const idRaw = await getPassword(\n this.keychainService,\n this.account(SESSION_V2_KEY_SUFFIX.id),\n );\n\n return {\n accessToken,\n refreshToken: refreshRaw ?? undefined,\n idToken: idRaw ?? undefined,\n tokenType: meta.tokenType,\n expiresAt: meta.expiresAt,\n };\n }\n }\n // read based on legacy monolithic\n const raw = await getPassword(this.keychainService, this.keychainAccount);\n if (!raw) return null;\n\n try {\n return JSON.parse(raw) as Session;\n } catch {\n return null;\n }\n }\n\n public async saveSession(session: Session): Promise<void> {\n const meta: SessionMetaV2 = {\n v: SESSION_META_VERSION,\n tokenType: session.tokenType,\n expiresAt: session.expiresAt,\n };\n\n const accessToken = session.accessToken.trim();\n await setPassword(\n this.keychainService,\n this.account(SESSION_V2_KEY_SUFFIX.access),\n accessToken,\n );\n await this.setOrDeleteTokenAccount(\n SESSION_V2_KEY_SUFFIX.refresh,\n session.refreshToken,\n );\n await this.setOrDeleteTokenAccount(\n SESSION_V2_KEY_SUFFIX.id,\n session.idToken,\n );\n await setPassword(\n this.keychainService,\n this.account(SESSION_V2_KEY_SUFFIX.meta),\n JSON.stringify(meta),\n );\n\n await this.deleteLegacyMonolithicIfPresent();\n }\n\n // when auth omits an optional token, remove any previously stored value as well\n private async setOrDeleteTokenAccount(\n suffix:\n | typeof SESSION_V2_KEY_SUFFIX.refresh\n | typeof SESSION_V2_KEY_SUFFIX.id,\n token: string | undefined,\n ): Promise<void> {\n const acc = this.account(suffix);\n const trimmed = token?.trim();\n if (trimmed) {\n await setPassword(this.keychainService, acc, trimmed);\n return;\n }\n const existing = await getPassword(this.keychainService, acc);\n if (existing) {\n await deletePassword(this.keychainService, acc);\n }\n }\n\n // older releases stored the whole session JSON under {@link keychainAccount} only\n private async deleteLegacyMonolithicIfPresent(): Promise<void> {\n const legacy = await getPassword(\n this.keychainService,\n this.keychainAccount,\n );\n if (!legacy) return;\n try {\n await deletePassword(this.keychainService, this.keychainAccount);\n } catch {\n // ignore, best effort cleanup\n }\n }\n\n public async clear(): Promise<void> {\n const accounts = [\n ...Object.values(SESSION_V2_KEY_SUFFIX).map((suffix) =>\n this.account(suffix),\n ),\n this.keychainAccount,\n ];\n for (const account of accounts) {\n const existing = await getPassword(this.keychainService, account);\n if (existing) {\n try {\n await deletePassword(this.keychainService, account);\n } catch {\n // ignore\n }\n }\n }\n }\n}\n\nexport const sessionVault = new SessionVault();\n","import { Command } from '@oclif/core';\nimport type { AxiosInstance } from 'axios';\nimport type { FC } from 'react';\nimport { API_CONFIG } from '../constants';\nimport { kittlApiService } from '../services/api.service';\nimport { authService } from '../services/auth.service';\nimport type { Session } from '../types/session';\nimport { runInteractiveView, type ViewWithDone } from '../ui/renderer';\nimport { getKittlEnvEntries } from './utils';\n\nexport abstract class BaseCommand extends Command {\n protected session: Session | null = null;\n\n public override async init(): Promise<void> {\n await super.init();\n this.session = await authService.getSession();\n kittlApiService.setAccessTokenProvider(async () =>\n authService.getAccessToken(),\n );\n\n const envEntries = getKittlEnvEntries();\n this.debug(`API base URL: ${API_CONFIG.baseUrl}`);\n this.debug(`KITTL_* variables:\\n${envEntries.join('\\n') || '(none)'}`);\n }\n\n protected getKittlApiClient(): AxiosInstance {\n return kittlApiService.getClient();\n }\n\n /**\n * Ensures a valid access token (+ refreshes when the accessToken is near expiry).\n */\n protected async ensureAuthenticated(): Promise<Session> {\n const session = await authService.getSession();\n if (!session?.accessToken) {\n this.error(\n `Session expired. Run \\`${this.config.bin} auth login\\` first.`,\n { exit: 2 },\n );\n }\n\n this.session = session;\n return session;\n }\n\n /**\n * Run an Ink view that reports a result via `onDone`, then unmount and return.\n * PRO TIP: use `this.log` / `this.error` after this resolves, not inside the view!! for final line stays on stdout.\n */\n protected async renderView<R>(View: FC<ViewWithDone<R>>): Promise<R>;\n protected async renderView<R, P extends object>(\n View: FC<P & ViewWithDone<R>>,\n props: P,\n ): Promise<R>;\n protected async renderView<R, P extends object>(\n View: FC<P & ViewWithDone<R>>,\n ...args: Partial<P> extends P ? [props?: P] : [props: P]\n ): Promise<R> {\n return runInteractiveView<R, P>(View, ...args);\n }\n}\n","import axios, {\n type AxiosError,\n AxiosHeaders,\n type AxiosInstance,\n type InternalAxiosRequestConfig,\n} from 'axios';\nimport { API_CONFIG } from '../constants';\nimport { authService } from './auth.service';\n\ntype AccessTokenProvider = () => Promise<string | undefined>;\ntype RetriableRequestConfig = InternalAxiosRequestConfig & {\n _retry?: boolean;\n};\n\nexport class KittlApiService {\n private readonly client: AxiosInstance;\n private accessTokenProvider?: AccessTokenProvider;\n\n public constructor() {\n this.client = axios.create({\n baseURL: API_CONFIG.baseUrl,\n timeout: API_CONFIG.timeoutMs,\n headers: {\n 'User-Agent': API_CONFIG.userAgent,\n },\n });\n\n this.client.interceptors.request.use(\n async (config: RetriableRequestConfig) => {\n if (config.skipAuth) {\n return config;\n }\n const token = await this.accessTokenProvider?.();\n if (token) {\n this.setAuthorizationHeader(config, token);\n }\n return config;\n },\n );\n\n this.client.interceptors.response.use(\n (response) => response,\n async (error: AxiosError) => {\n const originalRequest = error.config as\n | RetriableRequestConfig\n | undefined;\n // Retry only first-time 401 responses with a valid original request.\n if (\n error.response?.status !== 401 ||\n !originalRequest ||\n originalRequest.skipAuth ||\n originalRequest._retry\n ) {\n throw error;\n }\n\n // Mark as retried to avoid infinite retry loops.\n originalRequest._retry = true;\n // Force-refresh the token before replaying the request.\n const refreshedSession = await authService.refreshSession();\n const refreshedToken = refreshedSession?.accessToken;\n if (!refreshedToken) {\n throw error;\n }\n\n // Re-run the original request with updated Authorization header.\n this.setAuthorizationHeader(originalRequest, refreshedToken);\n return this.client.request(originalRequest);\n },\n );\n }\n\n public setAccessTokenProvider(provider: AccessTokenProvider): void {\n this.accessTokenProvider = provider;\n }\n\n public getClient(): AxiosInstance {\n return this.client;\n }\n\n private setAuthorizationHeader(\n config: InternalAxiosRequestConfig,\n token: string,\n ): void {\n const headers = AxiosHeaders.from(config.headers);\n headers.set('Authorization', `Bearer ${token}`);\n config.headers = headers;\n }\n}\n\nexport const kittlApiService = new KittlApiService();\n","import { render } from 'ink';\nimport React, { type FC } from 'react';\n\n/**\n * Standard shape for a view that reports a result.\n */\nexport type ViewWithDone<R> = { onDone: (result: R) => void };\n\n/**\n * The entrypoint that touches Ink's render process.\n */\nexport async function runInteractiveView<R, P extends object>(\n View: FC<P & ViewWithDone<R>>,\n ...args: Partial<P> extends P ? [props?: P] : [props: P]\n): Promise<R> {\n const props = args[0];\n\n return new Promise<R>((resolve, reject) => {\n const app = render(\n React.createElement(View, {\n ...(props ?? ({} as P)),\n onDone: (result: R) => {\n void (async () => {\n app.unmount();\n await app.waitUntilExit();\n resolve(result);\n })().catch(reject);\n },\n } as P & ViewWithDone<R>),\n );\n });\n}\n"],"mappings":"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","names":["URL","URL"]}
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  createExtensionDraftVersion
3
- } from "../../chunk-75SESNHC.js";
3
+ } from "../../chunk-E5EOPARA.js";
4
4
  import {
5
5
  formatHttpClientError,
6
6
  internalConfigExists,
7
7
  internalConfigPath,
8
8
  isSystemError,
9
9
  writeInternalConfig
10
- } from "../../chunk-A2IV54MU.js";
10
+ } from "../../chunk-344EUO2O.js";
11
11
  import {
12
12
  useTerminalWidth
13
13
  } from "../../chunk-EKU4DKQK.js";
@@ -23,7 +23,7 @@ import {
23
23
  ensureDirectory,
24
24
  getFileNameFromPath,
25
25
  isSubmitKey
26
- } from "../../chunk-BGJHRFGJ.js";
26
+ } from "../../chunk-F62NYF5U.js";
27
27
 
28
28
  // src/commands/app/init.ts
29
29
  import { join as join2, relative, resolve } from "node:path";
@@ -92,7 +92,7 @@ function packageJsonTemplate(displayName) {
92
92
  "@kittl/sdk": "^0.0.1"
93
93
  },
94
94
  devDependencies: {
95
- vite: "^5.0.0"
95
+ vite: "^8.0.0"
96
96
  }
97
97
  },
98
98
  null,
@@ -103,19 +103,85 @@ function packageJsonTemplate(displayName) {
103
103
  `;
104
104
  }
105
105
  function viteConfigTemplate() {
106
- return `import { defineConfig } from 'vite';
106
+ return `import { readdirSync } from 'node:fs';
107
+ import { basename, dirname, join } from 'node:path';
108
+ import { fileURLToPath } from 'node:url';
109
+ import { defineConfig } from 'vite';
110
+
111
+ const __dirname = dirname(fileURLToPath(import.meta.url));
112
+
113
+ function htmlBuildInputs(): Record<string, string> {
114
+ return Object.fromEntries(
115
+ readdirSync(__dirname)
116
+ .filter((name) => name.endsWith('.html'))
117
+ .map((name) => [basename(name, '.html'), join(__dirname, name)]),
118
+ );
119
+ }
120
+
121
+ const contentSecurityPolicy =
122
+ "default-src 'self'; style-src 'self' 'unsafe-inline'; img-src https: data: blob:; connect-src 'self' https: ws: wss: http://localhost:* http://127.0.0.1:*; frame-ancestors 'self' https://*.kittl.io https://*.kittl.com http://localhost:* http://127.0.0.1:*";
107
123
 
108
124
  export default defineConfig({
109
125
  server: {
110
126
  port: ${CLI_CONFIG.scaffoldViteDevPort},
127
+ headers: {
128
+ 'Content-Security-Policy': contentSecurityPolicy,
129
+ },
111
130
  },
112
131
  publicDir: 'public',
113
132
  build: {
114
133
  outDir: 'dist',
134
+ rolldownOptions: {
135
+ input: htmlBuildInputs(),
136
+ },
115
137
  },
138
+ base: './',
116
139
  });
117
140
  `;
118
141
  }
142
+ function agentsMdTemplate(displayName) {
143
+ const name = displayName.trim() || "Unnamed extension";
144
+ return `# Kittl app
145
+
146
+ **${name}** \u2014 [Kittl](https://www.kittl.com) starter from \`kittl app init\`. Kittl runs this app **inside a sandboxed iframe** in the editor; **@kittl/sdk** talks to the **Kittl canvas and design** (layers, artboards, export, drag-and-drop). **${CLI_CONFIG.manifestFileName}** holds scopes, install page, and embed paths.
147
+
148
+ ## AI instructions
149
+
150
+ - **SDK (agents / LLMs):** \`https://sdk-docs.kittl.dev/llms-full.txt\` is the source of truth for \`@kittl/sdk\` APIs.
151
+ - **SDK (humans):** https://sdk-docs.kittl.dev/
152
+ - **Build:** Vite 8; production uses **Rolldown** via \`build.rolldownOptions\` (see \`vite.config.ts\`).
153
+ - **Entries:** Do not hardcode HTML entry points. \`htmlBuildInputs()\` maps every root \`*.html\` to \`build.rolldownOptions.input\`.
154
+ - **Rule (Security):** Never remove \`localhost\`, \`127.0.0.1\`, or \`ws:\` from the CSP in \`vite.config.ts\`.
155
+ - **Reason:** These are required for the Kittl Live Bridge and Vite HMR. Removing them will break the connection between the Kittl Canvas and this local app.
156
+
157
+ ## Project structure
158
+
159
+ - **${CLI_CONFIG.manifestFileName}**: Extension metadata. [Schema](${EXTENSION_MANIFEST_JSON_SCHEMA_URL})
160
+ - **.kittl/**: Local Kittl CLI state (developer org, extension id); not shipped with the UI bundle.
161
+ - **src/**: TypeScript imported from each root HTML shell.
162
+ - **dist/**: \`pnpm run build\` output; manifest \`embed\` paths usually target files here after upload.
163
+ - **\`*.html\` (next to \`vite.config.ts\`): Each file is a Rolldown entry (chunk name = basename without \`.html\`).
164
+
165
+ ## Workflow & commands
166
+
167
+ | Command | Action |
168
+ | :--- | :--- |
169
+ | \`pnpm install\` | Install dependencies (once per clone or after lockfile changes). |
170
+ | \`pnpm run dev\` | Vite dev server + HMR (port in \`vite.config.ts\`). |
171
+ | \`pnpm run build\` | Production bundle into \`dist/\` (Rolldown). |
172
+ | \`kittl app update\` | Push manifest changes to Kittl. |
173
+ | \`kittl app upload\` | Upload the current \`dist/\` to Kittl. |
174
+ | \`kittl app --help\` | Other \`kittl app\` subcommands. |
175
+
176
+ **Note for agents:** A typical deployment sequence is \`pnpm run build\` \u2192 \`kittl app update\` \u2192 \`kittl app upload\`.
177
+
178
+ ## Terminology
179
+
180
+ - **Extension:** Technical implementation\u2014manifest, scopes, embeds, platform APIs.
181
+ - **App:** Product name in Kittl and in the CLI (\`kittl app ...\`); same codebase as an extension.
182
+ - **Sandboxed iframe:** The UI is embedded in an iframe (sandboxed); use **@kittl/sdk** to reach the host and canvas\u2014do not assume unfettered access to the parent page.
183
+ `;
184
+ }
119
185
  function indexHtmlTemplate(displayName) {
120
186
  return `<!DOCTYPE html>
121
187
  <html lang="en">
@@ -199,6 +265,11 @@ async function scaffoldExtension(cwd, displayName) {
199
265
  path: packageJsonPath,
200
266
  content: packageJsonTemplate(displayName)
201
267
  },
268
+ {
269
+ rel: "AGENTS.md",
270
+ path: join(cwd, "AGENTS.md"),
271
+ content: agentsMdTemplate(displayName)
272
+ },
202
273
  {
203
274
  rel: "vite.config.ts",
204
275
  path: join(cwd, "vite.config.ts"),
@@ -616,7 +687,7 @@ function AppInitWizardView({
616
687
 
617
688
  // src/commands/app/init.ts
618
689
  var AppInit = class _AppInit extends BaseCommand {
619
- static description = "Initialize a Kittl app in the current directory or a new folder";
690
+ static description = "Initialize a Kittl app in the current directory OR in a custom PATH";
620
691
  static args = {
621
692
  path: Args.string({
622
693
  description: "Directory for the app (created if it does not exist)",
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/commands/app/init.ts","../../../src/core/scaffolder.ts","../../../src/core/templates.ts","../../../src/services/developer-organizations.service.ts","../../../src/ui/views/app-init/AppInitWizardView.tsx","../../../src/ui/views/app-init/AppsInitOrgPickerView.tsx","../../../src/ui/views/app-init/TextInputView.tsx"],"sourcesContent":["import { join, relative, resolve } from 'node:path';\nimport { Args } from '@oclif/core';\nimport { CLI_CONFIG } from '../../constants';\nimport { BaseCommand } from '../../core/core.command';\nimport { formatHttpClientError } from '../../core/error';\nimport { getFileNameFromPath } from '../../core/files';\nimport {\n internalConfigExists,\n internalConfigPath,\n writeInternalConfig,\n} from '../../core/internal.config';\nimport { scaffoldExtension } from '../../core/scaffolder';\nimport { ensureDirectory } from '../../core/utils';\nimport {\n type DeveloperOrganization,\n listDeveloperOrganizations,\n} from '../../services/developer-organizations.service';\nimport { createExtensionDraftVersion } from '../../services/extensions.service';\nimport { AppInitWizardView } from '../../ui/views/app-init';\n\nexport default class AppInit extends BaseCommand {\n public static override description =\n 'Initialize a Kittl app in the current directory or a new folder';\n\n public static override args = {\n path: Args.string({\n description: 'Directory for the app (created if it does not exist)',\n default: '.',\n required: false,\n }),\n };\n\n public async run(): Promise<void> {\n const { args } = await this.parse(AppInit);\n\n await this.ensureAuthenticated();\n\n const targetDir = resolve(process.cwd(), args.path);\n\n try {\n await ensureDirectory(targetDir);\n } catch (e) {\n this.error(e instanceof Error ? e.message : String(e), { exit: 2 });\n }\n\n if (await internalConfigExists(targetDir)) {\n this.error(\n `Kittl config already exists at ${internalConfigPath(targetDir)}. Remove it or choose a different directory.`,\n { exit: 2 },\n );\n }\n\n const client = this.getKittlApiClient();\n let organizations: DeveloperOrganization[];\n try {\n organizations = await listDeveloperOrganizations(client);\n } catch (e) {\n this.error(formatHttpClientError(e), { exit: 2 });\n }\n\n const extensionNameSuggestion =\n args.path === '.' ? undefined : getFileNameFromPath(targetDir);\n\n const wizardResult = await this.renderView(AppInitWizardView, {\n organizations,\n client,\n extensionNameSuggestion,\n });\n\n if (wizardResult.kind === 'cancelled') {\n this.exit(130);\n }\n\n const { data } = wizardResult;\n\n const configFilePath = await writeInternalConfig(targetDir, {\n developerOrganizationId: data.developerOrganizationId,\n extensionId: data.extensionId,\n });\n // controls init message for getting started with starter scaffold\n let starterScaffoldWritten = false;\n try {\n const { skipped, existingPackageJson, createdManifestOnly } =\n await scaffoldExtension(targetDir, data.extensionName);\n starterScaffoldWritten = !existingPackageJson;\n if (existingPackageJson) {\n if (createdManifestOnly) {\n this.log(\n `package.json found; created ${CLI_CONFIG.manifestFileName} only (starter scaffold skipped).`,\n );\n } else {\n this.log(\n 'package.json found; skipped starter scaffold (manifest already present).',\n );\n }\n } else if (skipped.length > 0) {\n this.log(\n `Skipped starter files (already present): ${skipped.join(', ')}`,\n );\n }\n } catch (e) {\n this.error(e instanceof Error ? e.message : String(e), { exit: 2 });\n }\n\n try {\n await createExtensionDraftVersion(\n client,\n data.extensionId,\n join(targetDir, CLI_CONFIG.manifestFileName),\n );\n } catch (e) {\n this.error(formatHttpClientError(e), { exit: 2 });\n }\n\n if (data.isNewDeveloperOrganizationCreated) {\n this.log(`Created organization: \"${data.developerOrganizationName}\".`);\n } else {\n this.log(`Developer organization: \"${data.developerOrganizationName}\".`);\n }\n this.log(`Created app: \"${data.extensionName}\".`);\n this.debug(`Generated config file at ${configFilePath}`);\n\n this.log('');\n this.log(`Success! Extension \"${data.extensionName}\" is ready.`);\n this.log('Next steps:');\n let step = 1;\n const isCurrentDir = resolve(process.cwd()) === targetDir;\n const displayPath = relative(process.cwd(), targetDir);\n if (!isCurrentDir) {\n this.log(` ${step++}. cd ${JSON.stringify(displayPath)}`);\n }\n if (starterScaffoldWritten) {\n this.log(` ${step++}. npm install`);\n this.log(` ${step++}. npm run dev`);\n this.log(\n ` → http://localhost:${String(CLI_CONFIG.scaffoldViteDevPort)} (see vite.config.ts)`,\n );\n }\n this.log(\n ` ${step++}. Edit ${CLI_CONFIG.manifestFileName} as needed, then run 'kittl app update'`,\n );\n this.log(` ${step++}. When you have a build, run 'kittl app upload'`);\n }\n}\n","import { access, mkdir, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { CLI_CONFIG } from '../constants';\nimport { isSystemError } from './error';\nimport {\n ICON_SVG_TEMPLATE,\n indexHtmlTemplate,\n indexTypescriptTemplate,\n manifestTemplate,\n packageJsonTemplate,\n viteConfigTemplate,\n} from './templates';\n\nexport type ScaffoldExtensionResult = {\n // Paths relative to `cwd` that were created.\n written: string[];\n // Paths relative to `cwd` that already existed and were left unchanged.\n skipped: string[];\n /**\n * `package.json` was already present, Vite/HTML scaffolding was skipped.\n * The extension manifest file is still ensured (see {@link createdManifestOnly}).\n */\n existingPackageJson?: true;\n createdManifestOnly?: true;\n};\n\nasync function fileExists(filePath: string): Promise<boolean> {\n try {\n await access(filePath);\n return true;\n } catch (e) {\n if (isSystemError(e, 'ENOENT')) {\n return false;\n }\n throw e;\n }\n}\n\n/**\n * Writes a minimal Vite + HTML starter in the extension root after init (internal CLI config lives under `.kittl/`).\n * If `package.json` already exists, skips the starter kit but still creates the extension manifest when missing.\n * Otherwise, existing paths are left unchanged and only missing files are written.\n */\nexport async function scaffoldExtension(\n cwd: string,\n displayName: string,\n): Promise<ScaffoldExtensionResult> {\n const manifestPath = join(cwd, CLI_CONFIG.manifestFileName);\n const packageJsonPath = join(cwd, 'package.json');\n\n if (await fileExists(packageJsonPath)) {\n if (await fileExists(manifestPath)) {\n return {\n written: [],\n skipped: [],\n existingPackageJson: true,\n };\n }\n await writeFile(manifestPath, manifestTemplate(displayName), 'utf8');\n return {\n written: [CLI_CONFIG.manifestFileName],\n skipped: [],\n existingPackageJson: true,\n createdManifestOnly: true,\n };\n }\n\n const files: { rel: string; path: string; content: string }[] = [\n {\n rel: CLI_CONFIG.manifestFileName,\n path: manifestPath,\n content: manifestTemplate(displayName),\n },\n {\n rel: 'package.json',\n path: packageJsonPath,\n content: packageJsonTemplate(displayName),\n },\n {\n rel: 'vite.config.ts',\n path: join(cwd, 'vite.config.ts'),\n content: viteConfigTemplate(),\n },\n {\n rel: 'index.html',\n path: join(cwd, 'index.html'),\n content: indexHtmlTemplate(displayName),\n },\n {\n rel: join('public', 'icon.svg'),\n path: join(cwd, 'public', 'icon.svg'),\n content: ICON_SVG_TEMPLATE,\n },\n {\n rel: join('src', 'index.ts'),\n path: join(cwd, 'src', 'index.ts'),\n content: indexTypescriptTemplate(displayName),\n },\n ];\n\n await mkdir(join(cwd, 'public'), { recursive: true });\n await mkdir(join(cwd, 'src'), { recursive: true });\n\n const written: string[] = [];\n const skipped: string[] = [];\n\n for (const f of files) {\n if (await fileExists(f.path)) {\n skipped.push(f.rel);\n continue;\n }\n await writeFile(f.path, f.content, 'utf8');\n written.push(f.rel);\n }\n\n return { written, skipped };\n}\n","/**\n * Default extension scaffold strings. Adjust here to change the baseline Kittl extension layout.\n */\n\nimport { CLI_CONFIG } from '../constants';\nimport type { ExtensionManifest } from './schemas/extension-manifest';\n\n/**\n * Default legal placeholder links used in the generated manifest.\n * These are intentionally obvious placeholders so they get replaced before release.\n */\nconst DEFAULT_TERMS_URL = 'https://example.com/terms';\nconst DEFAULT_PRIVACY_URL = 'https://example.com/privacy';\n\n/**\n * Default embedded app entrypoint produced by the Vite scaffold build.\n * This path is interpreted relative to the built artifact root (Vite `outDir`).\n */\nconst DEFAULT_MAIN_APP_PANEL_PATH = 'index.html';\n\n// manifest JSON Schema URL for `manifest.json`\nexport const EXTENSION_MANIFEST_JSON_SCHEMA_URL =\n 'https://api.kittl.com/extensions/manifest/schema.json';\n\nfunction packageNameFromExtensionName(name: string): string {\n const slug = name\n .trim()\n .toLowerCase()\n .replace(/\\s+/g, '-')\n .replace(/[^a-z0-9-]/g, '');\n return slug.length > 0 ? slug : 'kittl-extension';\n}\n\n/**\n * Default manifest object written to `manifest.json` and pushed as the first draft version.\n * The scaffold includes every required field from the current manifest schema.\n */\nexport function initialExtensionManifest(\n displayName: string,\n): ExtensionManifest {\n const value = displayName.trim() || 'Unnamed extension';\n return {\n $schema: EXTENSION_MANIFEST_JSON_SCHEMA_URL,\n displayName: value,\n icon: 'icon.svg',\n tagline: `${value} for Kittl.`,\n installPage: {\n description: `Install ${value} to use this extension in Kittl.`,\n coverImage: 'icon.svg',\n termsAndConditionsLink: DEFAULT_TERMS_URL,\n privacyPolicyLink: DEFAULT_PRIVACY_URL,\n },\n config: {\n // New projects start without privileged scopes and can opt into them later.\n scopes: ['design:state:read', 'design:state:write'],\n embed: {\n mainAppPanel: {\n path: DEFAULT_MAIN_APP_PANEL_PATH,\n },\n },\n },\n };\n}\n\n/**\n * Serialized manifest file contents written by the CLI scaffold.\n */\nexport function manifestTemplate(displayName: string): string {\n return `${JSON.stringify(\n initialExtensionManifest(displayName),\n null, // replacer: none - default serialization\n 2, // space: 2-space indent + line breaks\n )}\\n`;\n}\n\nexport function packageJsonTemplate(displayName: string): string {\n return `${JSON.stringify(\n {\n name: packageNameFromExtensionName(displayName),\n private: true,\n version: '0.0.0',\n type: 'module',\n scripts: {\n dev: 'vite',\n build: 'vite build',\n preview: 'vite preview',\n },\n dependencies: {\n '@kittl/sdk': '^0.0.1',\n },\n devDependencies: {\n vite: '^5.0.0',\n },\n },\n null, // replacer: none, default serialization\n 2, // space: 2-space indent + line breaks\n )}\\n`;\n}\n\nexport function viteConfigTemplate(): string {\n return `import { defineConfig } from 'vite';\n\nexport default defineConfig({\n server: {\n port: ${CLI_CONFIG.scaffoldViteDevPort},\n },\n publicDir: 'public',\n build: {\n outDir: 'dist',\n },\n});\n`;\n}\n\nexport function indexHtmlTemplate(displayName: string): string {\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.0\" />\n <title>${displayName}</title>\n </head>\n <body>\n <div id=\"app\">\n <h1>Hello Kittl!</h1>\n <p>Welcome to your new extension: ${displayName}</p>\n <button id=\"doSomething\" type=\"button\">Do some magic!</button>\n </div>\n <script type=\"module\" src=\"/src/index.ts\"></script>\n </body>\n</html>\n`;\n}\n\nexport function indexTypescriptTemplate(displayName: string): string {\n return `import { kittl } from '@kittl/sdk';\n\ndocument.getElementById('doSomething')?.addEventListener('click', async () => {\n await kittl.design.text.addText({\n text: 'Hello ${displayName} from Kittl SDK!',\n position: {\n relative: {\n to: 'viewport',\n location: 'center',\n },\n },\n size: {\n height: 100,\n width: 400,\n },\n });\n});\n`;\n}\n\n// kittl logo\nexport const ICON_SVG_TEMPLATE =\n '<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"128\" height=\"128\" viewBox=\"0 0 1024 1024\"><rect width=\"1024\" height=\"1024\" rx=\"225\" fill=\"#DEFE00\"/><path fill=\"#080B10\" transform=\"translate(581,235)\" d=\"M0 0 C-7.93 26.81 -15.97 53.57 -24.12 80.31 C-24.35 81.04 -24.57 81.76 -24.79 82.5 C-25.92 86.19 -27.04 89.88 -28.17 93.57 C-28.5 94.67 -28.5 94.67 -28.85 95.8 C-29.3 97.29 -29.76 98.78 -30.21 100.27 C-35.39 117.26 -40.54 134.25 -45.69 151.25 C-46.09 152.58 -46.49 153.92 -46.9 155.25 C-47.68 157.83 -48.46 160.4 -49.24 162.98 C-50 165.48 -50.75 167.98 -51.51 170.48 C-53.37 176.6 -55.22 182.72 -57.06 188.84 C-57.99 191.91 -58.92 194.99 -59.84 198.06 C-60.29 199.54 -60.74 201.02 -61.18 202.51 C-61.8 204.56 -62.42 206.61 -63.04 208.67 C-63.4 209.84 -63.75 211.02 -64.12 212.23 C-65 215 -65 215 -66 217 C-31.32 207.79 -0.81 191.01 25.38 166.43 C27.48 164.48 29.6 162.63 31.81 160.81 C34.85 158.23 37.44 155.4 40.01 152.35 C41.45 150.66 42.91 148.99 44.39 147.34 C73.97 114.11 93.03 70.13 98 26 C113.47 23.05 128.96 20.3 144.5 17.74 C155.19 15.98 165.86 14.18 176.54 12.36 C178.95 11.95 181.37 11.54 183.79 11.13 C184.59 10.99 185.4 10.85 186.23 10.71 C187.86 10.44 189.49 10.16 191.13 9.88 C195.22 9.18 199.31 8.49 203.41 7.79 C207.32 7.12 211.22 6.45 215.13 5.79 C216.6 5.54 218.06 5.29 219.52 5.04 C221.55 4.69 223.57 4.35 225.6 4.01 C226.74 3.81 227.89 3.62 229.07 3.42 C232 3 232 3 236 3 C236.16 11.12 235.76 19 234.75 27.06 C234.62 28.15 234.48 29.23 234.34 30.35 C226.13 93.59 192.52 153.61 144 195 C143.05 195.84 142.11 196.67 141.13 197.53 C115.92 219.57 86.53 236.49 56 250 C55.6 259.92 56.83 269.35 58.31 279.13 C58.55 280.7 58.78 282.28 59.01 283.86 C59.57 287.61 60.14 291.36 60.71 295.11 C61.08 297.53 61.43 299.95 61.79 302.37 C64.96 323.35 70.45 343.85 77 364 C77.44 365.35 77.87 366.69 78.31 368.04 C87.9 397.66 98.51 426.64 111.58 454.91 C112.79 457.54 113.99 460.18 115.18 462.82 C120.11 473.66 125.8 484.06 131.59 494.45 C132.83 496.69 134.06 498.93 135.28 501.18 C144 517.14 153.68 532.57 165 546.81 C165.51 547.45 166.02 548.1 166.55 548.76 C167 549.32 167.45 549.87 167.92 550.45 C169 552 169 552 170 555 C169.42 555.28 168.83 555.56 168.23 555.85 C154.35 562.49 140.48 569.18 126.63 575.9 C115.75 581.18 104.87 586.45 93.98 591.7 C86.76 595.18 79.56 598.67 72.36 602.17 C66.13 605.19 59.89 608.21 53.66 611.23 C51.35 612.34 49.05 613.46 46.75 614.58 C44.04 615.89 41.33 617.2 38.63 618.5 C37.87 618.87 37.12 619.24 36.34 619.61 C33.37 621.03 31.33 622 28 622 C7.88 582.22 -1.64 541.14 -9.53 497.6 C-9.84 495.9 -10.14 494.21 -10.45 492.52 C-11.93 484.45 -13.35 476.42 -14.12 468.25 C-14.61 462.97 -14.61 462.97 -15.48 457.76 C-16.15 454.21 -16.43 450.66 -16.72 447.07 C-16.78 446.31 -16.84 445.56 -16.91 444.78 C-17.11 442.37 -17.3 439.97 -17.5 437.56 C-17.7 435.16 -17.89 432.76 -18.09 430.36 C-18.21 428.87 -18.34 427.38 -18.45 425.89 C-18.7 422.94 -18.99 420.04 -19.49 417.13 C-19.98 414.12 -20.26 411.19 -20.46 408.15 C-20.54 407.02 -20.62 405.88 -20.7 404.71 C-20.78 403.49 -20.86 402.26 -20.94 401 C-21.06 399.08 -21.06 399.08 -21.19 397.11 C-21.47 392.93 -21.74 388.75 -22 384.56 C-22.05 383.85 -22.09 383.14 -22.14 382.4 C-24.41 346.58 -25.21 310.89 -25 275 C-26.05 275.24 -27.1 275.48 -28.19 275.73 C-47.22 279.84 -66.64 281.24 -86 283 C-94.42 309.89 -102.59 336.84 -110.71 363.82 C-112.14 368.58 -113.57 373.34 -115 378.09 C-115.36 379.3 -115.36 379.3 -115.73 380.52 C-122.46 402.89 -129.26 425.23 -136.06 447.57 C-137.03 450.75 -137.99 453.93 -138.96 457.11 C-139.6 459.21 -140.24 461.32 -140.88 463.42 C-145.3 477.93 -149.64 492.47 -154 507 C-195.58 507 -237.16 507 -280 507 C-278.24 499.96 -276.51 493.16 -274.25 486.31 C-271.9 479.06 -269.79 471.77 -267.77 464.42 C-264.19 451.54 -260.37 438.73 -256.5 425.94 C-255.24 421.76 -253.98 417.58 -252.72 413.4 C-252.41 412.37 -252.1 411.35 -251.78 410.29 C-249.63 403.13 -247.52 395.96 -245.44 388.79 C-242.47 378.56 -239.41 368.37 -236.32 358.19 C-230.85 340.22 -230.85 340.22 -225.56 322.19 C-222.19 310.48 -218.62 298.84 -215.06 287.19 C-210.72 272.95 -206.4 258.7 -202.19 244.42 C-200.36 238.2 -198.51 231.98 -196.65 225.77 C-196.35 224.76 -196.05 223.75 -195.74 222.71 C-195.12 220.63 -194.5 218.55 -193.88 216.47 C-188.13 197.22 -188.13 197.22 -182.5 177.94 C-178.85 165.29 -174.97 152.72 -171.13 140.13 C-164.93 119.8 -158.75 99.46 -153 79 C-188.09 81.55 -226.46 97.99 -253 121 C-253.83 121.71 -254.66 122.42 -255.51 123.14 C-274.69 139.92 -289.02 161.6 -291.21 187.46 C-293.11 216.05 -280.75 245.26 -264.87 268.69 C-264.26 269.78 -263.64 270.87 -263 272 C-264.07 275.31 -265.83 276.91 -268.61 278.89 C-269.36 279.43 -270.1 279.96 -270.86 280.52 C-271.67 281.09 -272.48 281.66 -273.31 282.25 C-275.05 283.51 -276.79 284.76 -278.53 286.02 C-279.43 286.68 -280.33 287.33 -281.27 288 C-285.68 291.23 -290.03 294.55 -294.37 297.88 C-295.25 298.54 -296.12 299.21 -297.01 299.89 C-299.68 301.93 -302.34 303.96 -305 306 C-316.83 315.06 -328.7 324.04 -340.71 332.85 C-346.17 336.86 -351.59 340.92 -357 345 C-361.44 343.43 -363.83 339.89 -366.62 336.31 C-367.42 335.31 -367.42 335.31 -368.22 334.28 C-401.71 291.18 -419.04 237.97 -413.54 183.33 C-412.98 179.14 -412.11 175.08 -411 171 C-410.81 170.29 -410.62 169.57 -410.43 168.84 C-405.86 152.16 -397.84 136.47 -387 123 C-386.27 122.07 -385.54 121.14 -384.79 120.18 C-377.09 110.54 -368.68 102.62 -359 95 C-358.12 94.29 -357.24 93.58 -356.33 92.85 C-316.02 61.35 -264.24 45.67 -214.89 35.25 C-214.08 35.08 -213.27 34.91 -212.43 34.73 C-192.67 30.58 -172.78 27.22 -152.85 23.93 C-147.76 23.09 -142.68 22.24 -137.59 21.39 C-129.1 19.97 -120.6 18.56 -112.1 17.15 C-102.3 15.53 -92.51 13.9 -82.71 12.26 C-73.2 10.67 -63.69 9.09 -54.19 7.51 C-50.17 6.84 -46.15 6.17 -42.13 5.5 C-37.42 4.71 -32.71 3.93 -28 3.15 C-26.28 2.87 -24.56 2.58 -22.83 2.29 C-20.48 1.9 -18.12 1.51 -15.77 1.12 C-14.76 0.95 -14.76 0.95 -13.72 0.77 C-9.08 0.03 -4.68 -0.09 0 0 Z\"/></svg>';\n","import type { AxiosInstance } from 'axios';\nimport { z } from 'zod';\n\nconst developerOrganizationSchema = z.object({\n id: z.string(),\n name: z.string(),\n createdAt: z.string().optional(),\n updatedAt: z.string().optional(),\n});\n\nconst listResponseSchema = z.object({\n success: z.literal(true),\n result: z.object({\n developerOrganizations: z.array(developerOrganizationSchema),\n }),\n});\n\nconst createOrgResponseSchema = z.object({\n success: z.literal(true),\n result: z.object({\n developerOrganizationId: z.string(),\n }),\n});\n\nconst createExtensionResponseSchema = z.object({\n success: z.literal(true),\n result: z.object({\n extensionId: z.string(),\n }),\n});\n\nexport type DeveloperOrganization = z.infer<typeof developerOrganizationSchema>;\n\nexport async function listDeveloperOrganizations(\n client: AxiosInstance,\n): Promise<DeveloperOrganization[]> {\n const { data } = await client.get('/developer-organizations');\n const parsed = listResponseSchema.parse(data);\n return parsed.result.developerOrganizations;\n}\n\nexport async function createDeveloperOrganization(\n client: AxiosInstance,\n name: string,\n): Promise<string> {\n const { data } = await client.post('/developer-organizations', {\n name,\n });\n const parsed = createOrgResponseSchema.parse(data);\n return parsed.result.developerOrganizationId;\n}\n\nexport async function createExtensionInDeveloperOrganization(\n client: AxiosInstance,\n developerOrganizationId: string,\n body: { name: string; id?: string },\n): Promise<string> {\n const path = `/developer-organizations/${developerOrganizationId}/extensions`;\n const { data } = await client.post(path, body);\n const parsed = createExtensionResponseSchema.parse(data);\n return parsed.result.extensionId;\n}\n","import type { AxiosInstance } from 'axios';\nimport { Box, Text } from 'ink';\nimport type { ReactNode } from 'react';\nimport { useCallback, useState } from 'react';\nimport { formatHttpClientError } from '../../../core/error';\nimport {\n createDeveloperOrganization,\n createExtensionInDeveloperOrganization,\n type DeveloperOrganization,\n} from '../../../services/developer-organizations.service';\nimport { useTerminalWidth } from '../../hooks';\nimport { layoutStyles, textStyles } from '../../theme/styles';\nimport { spacing } from '../../theme/tokens';\nimport type { AppsInitOrgPickerResult } from './AppsInitOrgPickerView';\nimport { AppsInitOrgPickerView } from './AppsInitOrgPickerView';\nimport type { TextInputViewDone } from './TextInputView';\nimport { TextInputView } from './TextInputView';\n\nexport type AppInitWizardSuccess = {\n developerOrganizationId: string;\n developerOrganizationName: string;\n extensionId: string;\n extensionName: string;\n // True when the org was created in this wizard (vs chosen from the list).\n isNewDeveloperOrganizationCreated: boolean;\n};\n\nexport type AppInitWizardResult =\n | { kind: 'cancelled' }\n | { kind: 'success'; data: AppInitWizardSuccess };\n\ntype Step = 'pick' | 'org_name' | 'ext_name';\n\ntype WizardDraft = {\n developerOrganizationId?: string;\n developerOrganizationName?: string;\n isNewDeveloperOrganizationCreated?: boolean;\n};\n\nexport type AppInitWizardViewProps = {\n organizations: DeveloperOrganization[];\n client: AxiosInstance;\n extensionNameSuggestion?: string;\n onDone: (result: AppInitWizardResult) => void;\n};\n\nfunction AppInitStepShell({\n width,\n apiError,\n isLoading,\n loadingText,\n children,\n}: {\n width: number | string;\n apiError: string | null;\n isLoading: boolean;\n loadingText: string;\n children: ReactNode;\n}) {\n return (\n <Box flexDirection=\"column\" width={width} minWidth={0}>\n {apiError ? (\n <Box marginLeft={spacing.sm} marginBottom={spacing.sm}>\n <Text {...textStyles.error}>{apiError}</Text>\n </Box>\n ) : null}\n {isLoading ? (\n <Box {...layoutStyles.viewColumn}>\n <Text {...textStyles.muted}>{loadingText}…</Text>\n </Box>\n ) : (\n children\n )}\n </Box>\n );\n}\n\nexport function AppInitWizardView({\n organizations,\n client,\n extensionNameSuggestion,\n onDone,\n}: AppInitWizardViewProps) {\n const width = useTerminalWidth();\n const w = width > 0 ? width : '100%';\n\n const [step, setStep] = useState<Step>('pick');\n const [draft, setDraft] = useState<WizardDraft>({});\n const [apiError, setApiError] = useState<string | null>(null);\n const [isLoading, setIsLoading] = useState(false);\n\n const runTask = useCallback(async (task: () => Promise<void>) => {\n setApiError(null);\n setIsLoading(true);\n try {\n await task();\n } catch (e) {\n setApiError(formatHttpClientError(e));\n } finally {\n setIsLoading(false);\n }\n }, []);\n\n const handlePick = useCallback(\n (r: AppsInitOrgPickerResult) => {\n if (r.kind === 'cancelled') {\n onDone({ kind: 'cancelled' });\n return;\n }\n setApiError(null);\n if (r.kind === 'selected') {\n setDraft({\n developerOrganizationId: r.developerOrganizationId,\n developerOrganizationName: r.name,\n isNewDeveloperOrganizationCreated: false,\n });\n setStep('ext_name');\n return;\n }\n setDraft({});\n setStep('org_name');\n },\n [onDone],\n );\n\n const handleOrgName = useCallback(\n (r: TextInputViewDone) => {\n if (r.kind === 'cancelled') {\n onDone({ kind: 'cancelled' });\n return;\n }\n void runTask(async () => {\n const developerOrganizationId = await createDeveloperOrganization(\n client,\n r.value,\n );\n setDraft({\n developerOrganizationId,\n developerOrganizationName: r.value,\n isNewDeveloperOrganizationCreated: true,\n });\n setStep('ext_name');\n });\n },\n [client, onDone, runTask],\n );\n\n const handleExtName = useCallback(\n (r: TextInputViewDone) => {\n if (r.kind === 'cancelled') {\n onDone({ kind: 'cancelled' });\n return;\n }\n const orgId = draft.developerOrganizationId;\n const orgName = draft.developerOrganizationName;\n if (!orgId || !orgName) {\n return;\n }\n const isNewDeveloperOrganizationCreated = Boolean(\n draft.isNewDeveloperOrganizationCreated,\n );\n void runTask(async () => {\n const extensionId = await createExtensionInDeveloperOrganization(\n client,\n orgId,\n { name: r.value },\n );\n onDone({\n kind: 'success',\n data: {\n developerOrganizationId: orgId,\n developerOrganizationName: orgName,\n extensionId,\n extensionName: r.value,\n isNewDeveloperOrganizationCreated,\n },\n });\n });\n },\n [client, draft, onDone, runTask],\n );\n\n switch (step) {\n case 'pick':\n return (\n <AppsInitOrgPickerView\n organizations={organizations}\n onDone={handlePick}\n />\n );\n case 'org_name':\n return (\n <AppInitStepShell\n width={w}\n apiError={apiError}\n isLoading={isLoading}\n loadingText=\"Creating organization\"\n >\n <TextInputView\n key=\"wizard-org-name\"\n label=\"New organization name:\"\n placeholder=\"e.g. Functor Fountain Org\"\n onDone={handleOrgName}\n />\n </AppInitStepShell>\n );\n case 'ext_name':\n return (\n <AppInitStepShell\n width={w}\n apiError={apiError}\n isLoading={isLoading}\n loadingText=\"Creating extension\"\n >\n <TextInputView\n key=\"wizard-ext-name\"\n label=\"Extension name:\"\n placeholder=\"e.g. WASM-powered toaster\"\n initialValue={extensionNameSuggestion}\n onDone={handleExtName}\n />\n </AppInitStepShell>\n );\n }\n}\n","import { Box, type Key, Text, useInput } from 'ink';\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { isSubmitKey } from '../../../core/utils';\nimport { useTerminalWidth } from '../../hooks';\nimport { layoutStyles, textStyles } from '../../theme/styles';\nimport { colors } from '../../theme/tokens';\n\nexport type DeveloperOrganizationRow = {\n id: string;\n name: string;\n};\n\nexport type AppsInitOrgPickerResult =\n | { kind: 'selected'; developerOrganizationId: string; name: string }\n | { kind: 'create_new' }\n | { kind: 'cancelled' };\n\nexport type AppsInitOrgPickerViewProps = {\n organizations: DeveloperOrganizationRow[];\n onDone: (result: AppsInitOrgPickerResult) => void;\n};\n\nconst CREATE_NEW_LABEL = 'Create new organization';\n\nexport function AppsInitOrgPickerView({\n organizations,\n onDone,\n}: AppsInitOrgPickerViewProps) {\n const width = useTerminalWidth();\n const [index, setIndex] = useState(0);\n\n const indexRef = useRef(index);\n const organizationsRef = useRef(organizations);\n const onDoneRef = useRef(onDone);\n\n indexRef.current = index;\n organizationsRef.current = organizations;\n onDoneRef.current = onDone;\n\n useEffect(() => {\n const maxIndex = organizations.length;\n setIndex((i) => (i > maxIndex ? maxIndex : i));\n }, [organizations]);\n\n const labels = useMemo(\n () => [...organizations.map((o) => o.name), CREATE_NEW_LABEL],\n [organizations],\n );\n\n const handleInput = useCallback((_input: string, key: Key) => {\n if (key.escape) {\n onDoneRef.current({ kind: 'cancelled' });\n return;\n }\n if (isSubmitKey(key)) {\n const idx = indexRef.current;\n const orgs = organizationsRef.current;\n if (idx === orgs.length) {\n onDoneRef.current({ kind: 'create_new' });\n return;\n }\n const org = orgs[idx];\n onDoneRef.current({\n kind: 'selected',\n developerOrganizationId: org.id,\n name: org.name,\n });\n return;\n }\n if (key.upArrow) {\n setIndex((i) => {\n const rc = organizationsRef.current.length + 1;\n const next = i <= 0 ? rc - 1 : i - 1;\n indexRef.current = next;\n return next;\n });\n return;\n }\n if (key.downArrow) {\n setIndex((i) => {\n const rc = organizationsRef.current.length + 1;\n const next = i >= rc - 1 ? 0 : i + 1;\n indexRef.current = next;\n return next;\n });\n }\n }, []);\n\n useInput(handleInput);\n\n const empty = organizations.length === 0;\n\n return (\n <Box\n {...layoutStyles.viewColumn}\n width={width > 0 ? width : '100%'}\n minWidth={0}\n >\n <Text {...textStyles.title}>Select developer organization</Text>\n <Text {...textStyles.muted}>↑↓ move · Enter confirm · Esc cancel</Text>\n <Box {...layoutStyles.section} flexDirection=\"column\">\n {empty ? (\n <Box marginBottom={1}>\n <Text {...textStyles.muted}>\n {\"No organizations found. Let's make one!\"}\n </Text>\n </Box>\n ) : null}\n {labels.map((label, i) => {\n const isSelected = i === index;\n return (\n <Text\n key={`${label}-${i}`}\n bold={isSelected}\n color={isSelected ? colors.accent : undefined}\n >\n {isSelected ? '› ' : ' '}\n {label}\n </Text>\n );\n })}\n </Box>\n </Box>\n );\n}\n","import { Box, Text, useInput } from 'ink';\nimport TextInput from 'ink-text-input';\nimport { useCallback, useState } from 'react';\nimport { useTerminalWidth } from '../../hooks';\nimport { layoutStyles, textStyles } from '../../theme/styles';\n\nexport type TextInputViewDone =\n | { kind: 'submit'; value: string }\n | { kind: 'cancelled' };\n\nexport type TextInputViewProps = {\n label: string;\n placeholder?: string;\n /** Initial field value (trimmed once on mount). */\n initialValue?: string;\n // When true, Enter on whitespace-only keeps you on the screen with an error.\n requireNonEmpty?: boolean;\n onDone: (result: TextInputViewDone) => void;\n};\n\n/**\n * text input field using Ink + `ink-text-input`.\n */\nexport function TextInputView({\n label,\n placeholder,\n initialValue,\n requireNonEmpty = true,\n onDone,\n}: TextInputViewProps) {\n const width = useTerminalWidth();\n const [value, setValue] = useState(() => initialValue?.trim() ?? '');\n const [error, setError] = useState<string | null>(null);\n\n const finish = useCallback(\n (result: TextInputViewDone) => {\n onDone(result);\n },\n [onDone],\n );\n\n useInput((_input, key) => {\n if (key.escape) {\n finish({ kind: 'cancelled' });\n }\n });\n\n const handleSubmit = useCallback(\n (submitted: string) => {\n const trimmed = submitted.trim();\n if (requireNonEmpty && trimmed.length === 0) {\n setError('Cannot be empty.');\n return;\n }\n setError(null);\n finish({ kind: 'submit', value: trimmed });\n },\n [finish, requireNonEmpty],\n );\n\n return (\n <Box\n {...layoutStyles.viewColumn}\n width={width > 0 ? width : '100%'}\n minWidth={0}\n >\n <Text {...textStyles.title}>{label}</Text>\n <Box {...layoutStyles.section} flexDirection=\"row\" flexWrap=\"wrap\">\n <TextInput\n value={value}\n onChange={(v) => {\n setValue(v);\n if (error) {\n setError(null);\n }\n }}\n onSubmit={handleSubmit}\n placeholder={placeholder ?? ''}\n />\n </Box>\n {error ? (\n <Text {...textStyles.error}>{error}</Text>\n ) : (\n <Text {...textStyles.muted}>Enter confirm · Esc cancel</Text>\n )}\n </Box>\n );\n}\n"],"mappings":"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","names":["join","Box","Text","useCallback","useState","Box","Text","useInput","useCallback","useState","jsx","jsxs","useState","useCallback","useInput","Box","Text","jsx","jsxs","Box","Text","useState","useCallback","join"]}
1
+ {"version":3,"sources":["../../../src/commands/app/init.ts","../../../src/core/scaffolder.ts","../../../src/core/templates.ts","../../../src/services/developer-organizations.service.ts","../../../src/ui/views/app-init/AppInitWizardView.tsx","../../../src/ui/views/app-init/AppsInitOrgPickerView.tsx","../../../src/ui/views/app-init/TextInputView.tsx"],"sourcesContent":["import { join, relative, resolve } from 'node:path';\nimport { Args } from '@oclif/core';\nimport { CLI_CONFIG } from '../../constants';\nimport { BaseCommand } from '../../core/core.command';\nimport { formatHttpClientError } from '../../core/error';\nimport { getFileNameFromPath } from '../../core/files';\nimport {\n internalConfigExists,\n internalConfigPath,\n writeInternalConfig,\n} from '../../core/internal.config';\nimport { scaffoldExtension } from '../../core/scaffolder';\nimport { ensureDirectory } from '../../core/utils';\nimport {\n type DeveloperOrganization,\n listDeveloperOrganizations,\n} from '../../services/developer-organizations.service';\nimport { createExtensionDraftVersion } from '../../services/extensions.service';\nimport { AppInitWizardView } from '../../ui/views/app-init';\n\nexport default class AppInit extends BaseCommand {\n public static override description =\n 'Initialize a Kittl app in the current directory OR in a custom PATH';\n\n public static override args = {\n path: Args.string({\n description: 'Directory for the app (created if it does not exist)',\n default: '.',\n required: false,\n }),\n };\n\n public async run(): Promise<void> {\n const { args } = await this.parse(AppInit);\n\n await this.ensureAuthenticated();\n\n const targetDir = resolve(process.cwd(), args.path);\n\n try {\n await ensureDirectory(targetDir);\n } catch (e) {\n this.error(e instanceof Error ? e.message : String(e), { exit: 2 });\n }\n\n if (await internalConfigExists(targetDir)) {\n this.error(\n `Kittl config already exists at ${internalConfigPath(targetDir)}. Remove it or choose a different directory.`,\n { exit: 2 },\n );\n }\n\n const client = this.getKittlApiClient();\n let organizations: DeveloperOrganization[];\n try {\n organizations = await listDeveloperOrganizations(client);\n } catch (e) {\n this.error(formatHttpClientError(e), { exit: 2 });\n }\n\n const extensionNameSuggestion =\n args.path === '.' ? undefined : getFileNameFromPath(targetDir);\n\n const wizardResult = await this.renderView(AppInitWizardView, {\n organizations,\n client,\n extensionNameSuggestion,\n });\n\n if (wizardResult.kind === 'cancelled') {\n this.exit(130);\n }\n\n const { data } = wizardResult;\n\n const configFilePath = await writeInternalConfig(targetDir, {\n developerOrganizationId: data.developerOrganizationId,\n extensionId: data.extensionId,\n });\n // controls init message for getting started with starter scaffold\n let starterScaffoldWritten = false;\n try {\n const { skipped, existingPackageJson, createdManifestOnly } =\n await scaffoldExtension(targetDir, data.extensionName);\n starterScaffoldWritten = !existingPackageJson;\n if (existingPackageJson) {\n if (createdManifestOnly) {\n this.log(\n `package.json found; created ${CLI_CONFIG.manifestFileName} only (starter scaffold skipped).`,\n );\n } else {\n this.log(\n 'package.json found; skipped starter scaffold (manifest already present).',\n );\n }\n } else if (skipped.length > 0) {\n this.log(\n `Skipped starter files (already present): ${skipped.join(', ')}`,\n );\n }\n } catch (e) {\n this.error(e instanceof Error ? e.message : String(e), { exit: 2 });\n }\n\n try {\n await createExtensionDraftVersion(\n client,\n data.extensionId,\n join(targetDir, CLI_CONFIG.manifestFileName),\n );\n } catch (e) {\n this.error(formatHttpClientError(e), { exit: 2 });\n }\n\n if (data.isNewDeveloperOrganizationCreated) {\n this.log(`Created organization: \"${data.developerOrganizationName}\".`);\n } else {\n this.log(`Developer organization: \"${data.developerOrganizationName}\".`);\n }\n this.log(`Created app: \"${data.extensionName}\".`);\n this.debug(`Generated config file at ${configFilePath}`);\n\n this.log('');\n this.log(`Success! Extension \"${data.extensionName}\" is ready.`);\n this.log('Next steps:');\n let step = 1;\n const isCurrentDir = resolve(process.cwd()) === targetDir;\n const displayPath = relative(process.cwd(), targetDir);\n if (!isCurrentDir) {\n this.log(` ${step++}. cd ${JSON.stringify(displayPath)}`);\n }\n if (starterScaffoldWritten) {\n this.log(` ${step++}. npm install`);\n this.log(` ${step++}. npm run dev`);\n this.log(\n ` → http://localhost:${String(CLI_CONFIG.scaffoldViteDevPort)} (see vite.config.ts)`,\n );\n }\n this.log(\n ` ${step++}. Edit ${CLI_CONFIG.manifestFileName} as needed, then run 'kittl app update'`,\n );\n this.log(` ${step++}. When you have a build, run 'kittl app upload'`);\n }\n}\n","import { access, mkdir, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { CLI_CONFIG } from '../constants';\nimport { isSystemError } from './error';\nimport {\n agentsMdTemplate,\n ICON_SVG_TEMPLATE,\n indexHtmlTemplate,\n indexTypescriptTemplate,\n manifestTemplate,\n packageJsonTemplate,\n viteConfigTemplate,\n} from './templates';\n\nexport type ScaffoldExtensionResult = {\n // Paths relative to `cwd` that were created.\n written: string[];\n // Paths relative to `cwd` that already existed and were left unchanged.\n skipped: string[];\n /**\n * `package.json` was already present, Vite/HTML scaffolding was skipped.\n * The extension manifest file is still ensured (see {@link createdManifestOnly}).\n */\n existingPackageJson?: true;\n createdManifestOnly?: true;\n};\n\nasync function fileExists(filePath: string): Promise<boolean> {\n try {\n await access(filePath);\n return true;\n } catch (e) {\n if (isSystemError(e, 'ENOENT')) {\n return false;\n }\n throw e;\n }\n}\n\n/**\n * Writes a minimal Vite + HTML starter in the extension root after init (internal CLI config lives under `.kittl/`).\n * If `package.json` already exists, skips the starter kit but still creates the extension manifest when missing.\n * Otherwise, existing paths are left unchanged and only missing files are written.\n */\nexport async function scaffoldExtension(\n cwd: string,\n displayName: string,\n): Promise<ScaffoldExtensionResult> {\n const manifestPath = join(cwd, CLI_CONFIG.manifestFileName);\n const packageJsonPath = join(cwd, 'package.json');\n\n if (await fileExists(packageJsonPath)) {\n if (await fileExists(manifestPath)) {\n return {\n written: [],\n skipped: [],\n existingPackageJson: true,\n };\n }\n await writeFile(manifestPath, manifestTemplate(displayName), 'utf8');\n return {\n written: [CLI_CONFIG.manifestFileName],\n skipped: [],\n existingPackageJson: true,\n createdManifestOnly: true,\n };\n }\n\n const files: { rel: string; path: string; content: string }[] = [\n {\n rel: CLI_CONFIG.manifestFileName,\n path: manifestPath,\n content: manifestTemplate(displayName),\n },\n {\n rel: 'package.json',\n path: packageJsonPath,\n content: packageJsonTemplate(displayName),\n },\n {\n rel: 'AGENTS.md',\n path: join(cwd, 'AGENTS.md'),\n content: agentsMdTemplate(displayName),\n },\n {\n rel: 'vite.config.ts',\n path: join(cwd, 'vite.config.ts'),\n content: viteConfigTemplate(),\n },\n {\n rel: 'index.html',\n path: join(cwd, 'index.html'),\n content: indexHtmlTemplate(displayName),\n },\n {\n rel: join('public', 'icon.svg'),\n path: join(cwd, 'public', 'icon.svg'),\n content: ICON_SVG_TEMPLATE,\n },\n {\n rel: join('src', 'index.ts'),\n path: join(cwd, 'src', 'index.ts'),\n content: indexTypescriptTemplate(displayName),\n },\n ];\n\n await mkdir(join(cwd, 'public'), { recursive: true });\n await mkdir(join(cwd, 'src'), { recursive: true });\n\n const written: string[] = [];\n const skipped: string[] = [];\n\n for (const f of files) {\n if (await fileExists(f.path)) {\n skipped.push(f.rel);\n continue;\n }\n await writeFile(f.path, f.content, 'utf8');\n written.push(f.rel);\n }\n\n return { written, skipped };\n}\n","/**\n * Default extension scaffold strings. Adjust here to change the baseline Kittl extension layout.\n */\n\nimport { CLI_CONFIG } from '../constants';\nimport type { ExtensionManifest } from './schemas/extension-manifest';\n\n/**\n * Default legal placeholder links used in the generated manifest.\n * These are intentionally obvious placeholders so they get replaced before release.\n */\nconst DEFAULT_TERMS_URL = 'https://example.com/terms';\nconst DEFAULT_PRIVACY_URL = 'https://example.com/privacy';\n\n/**\n * Default embedded app entrypoint produced by the Vite scaffold build.\n * This path is interpreted relative to the built artifact root (Vite `outDir`).\n */\nconst DEFAULT_MAIN_APP_PANEL_PATH = 'index.html';\n\n// manifest JSON Schema URL for `manifest.json`\nexport const EXTENSION_MANIFEST_JSON_SCHEMA_URL =\n 'https://api.kittl.com/extensions/manifest/schema.json';\n\nfunction packageNameFromExtensionName(name: string): string {\n const slug = name\n .trim()\n .toLowerCase()\n .replace(/\\s+/g, '-')\n .replace(/[^a-z0-9-]/g, '');\n return slug.length > 0 ? slug : 'kittl-extension';\n}\n\n/**\n * Default manifest object written to `manifest.json` and pushed as the first draft version.\n * The scaffold includes every required field from the current manifest schema.\n */\nexport function initialExtensionManifest(\n displayName: string,\n): ExtensionManifest {\n const value = displayName.trim() || 'Unnamed extension';\n return {\n $schema: EXTENSION_MANIFEST_JSON_SCHEMA_URL,\n displayName: value,\n icon: 'icon.svg',\n tagline: `${value} for Kittl.`,\n installPage: {\n description: `Install ${value} to use this extension in Kittl.`,\n coverImage: 'icon.svg',\n termsAndConditionsLink: DEFAULT_TERMS_URL,\n privacyPolicyLink: DEFAULT_PRIVACY_URL,\n },\n config: {\n // New projects start without privileged scopes and can opt into them later.\n scopes: ['design:state:read', 'design:state:write'],\n embed: {\n mainAppPanel: {\n path: DEFAULT_MAIN_APP_PANEL_PATH,\n },\n },\n },\n };\n}\n\n/**\n * Serialized manifest file contents written by the CLI scaffold.\n */\nexport function manifestTemplate(displayName: string): string {\n return `${JSON.stringify(\n initialExtensionManifest(displayName),\n null, // replacer: none - default serialization\n 2, // space: 2-space indent + line breaks\n )}\\n`;\n}\n\nexport function packageJsonTemplate(displayName: string): string {\n return `${JSON.stringify(\n {\n name: packageNameFromExtensionName(displayName),\n private: true,\n version: '0.0.0',\n type: 'module',\n scripts: {\n dev: 'vite',\n build: 'vite build',\n preview: 'vite preview',\n },\n dependencies: {\n '@kittl/sdk': '^0.0.1',\n },\n devDependencies: {\n vite: '^8.0.0',\n },\n },\n null, // replacer: none, default serialization\n 2, // space: 2-space indent + line breaks\n )}\\n`;\n}\n\nexport function viteConfigTemplate(): string {\n return `import { readdirSync } from 'node:fs';\nimport { basename, dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { defineConfig } from 'vite';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\nfunction htmlBuildInputs(): Record<string, string> {\n return Object.fromEntries(\n readdirSync(__dirname)\n .filter((name) => name.endsWith('.html'))\n .map((name) => [basename(name, '.html'), join(__dirname, name)]),\n );\n}\n\nconst contentSecurityPolicy =\n \"default-src 'self'; style-src 'self' 'unsafe-inline'; img-src https: data: blob:; connect-src 'self' https: ws: wss: http://localhost:* http://127.0.0.1:*; frame-ancestors 'self' https://*.kittl.io https://*.kittl.com http://localhost:* http://127.0.0.1:*\";\n\nexport default defineConfig({\n server: {\n port: ${CLI_CONFIG.scaffoldViteDevPort},\n headers: {\n 'Content-Security-Policy': contentSecurityPolicy,\n },\n },\n publicDir: 'public',\n build: {\n outDir: 'dist',\n rolldownOptions: {\n input: htmlBuildInputs(),\n },\n },\n base: './',\n});\n`;\n}\n\nexport function agentsMdTemplate(displayName: string): string {\n const name = displayName.trim() || 'Unnamed extension';\n return `# Kittl app\n\n**${name}** — [Kittl](https://www.kittl.com) starter from \\`kittl app init\\`. Kittl runs this app **inside a sandboxed iframe** in the editor; **@kittl/sdk** talks to the **Kittl canvas and design** (layers, artboards, export, drag-and-drop). **${CLI_CONFIG.manifestFileName}** holds scopes, install page, and embed paths.\n\n## AI instructions\n\n- **SDK (agents / LLMs):** \\`https://sdk-docs.kittl.dev/llms-full.txt\\` is the source of truth for \\`@kittl/sdk\\` APIs.\n- **SDK (humans):** https://sdk-docs.kittl.dev/\n- **Build:** Vite 8; production uses **Rolldown** via \\`build.rolldownOptions\\` (see \\`vite.config.ts\\`).\n- **Entries:** Do not hardcode HTML entry points. \\`htmlBuildInputs()\\` maps every root \\`*.html\\` to \\`build.rolldownOptions.input\\`.\n- **Rule (Security):** Never remove \\`localhost\\`, \\`127.0.0.1\\`, or \\`ws:\\` from the CSP in \\`vite.config.ts\\`.\n- **Reason:** These are required for the Kittl Live Bridge and Vite HMR. Removing them will break the connection between the Kittl Canvas and this local app.\n\n## Project structure\n\n- **${CLI_CONFIG.manifestFileName}**: Extension metadata. [Schema](${EXTENSION_MANIFEST_JSON_SCHEMA_URL})\n- **.kittl/**: Local Kittl CLI state (developer org, extension id); not shipped with the UI bundle.\n- **src/**: TypeScript imported from each root HTML shell.\n- **dist/**: \\`pnpm run build\\` output; manifest \\`embed\\` paths usually target files here after upload.\n- **\\`*.html\\` (next to \\`vite.config.ts\\`): Each file is a Rolldown entry (chunk name = basename without \\`.html\\`).\n\n## Workflow & commands\n\n| Command | Action |\n| :--- | :--- |\n| \\`pnpm install\\` | Install dependencies (once per clone or after lockfile changes). |\n| \\`pnpm run dev\\` | Vite dev server + HMR (port in \\`vite.config.ts\\`). |\n| \\`pnpm run build\\` | Production bundle into \\`dist/\\` (Rolldown). |\n| \\`kittl app update\\` | Push manifest changes to Kittl. |\n| \\`kittl app upload\\` | Upload the current \\`dist/\\` to Kittl. |\n| \\`kittl app --help\\` | Other \\`kittl app\\` subcommands. |\n\n**Note for agents:** A typical deployment sequence is \\`pnpm run build\\` → \\`kittl app update\\` → \\`kittl app upload\\`.\n\n## Terminology\n\n- **Extension:** Technical implementation—manifest, scopes, embeds, platform APIs.\n- **App:** Product name in Kittl and in the CLI (\\`kittl app ...\\`); same codebase as an extension.\n- **Sandboxed iframe:** The UI is embedded in an iframe (sandboxed); use **@kittl/sdk** to reach the host and canvas—do not assume unfettered access to the parent page.\n`;\n}\n\nexport function indexHtmlTemplate(displayName: string): string {\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.0\" />\n <title>${displayName}</title>\n </head>\n <body>\n <div id=\"app\">\n <h1>Hello Kittl!</h1>\n <p>Welcome to your new extension: ${displayName}</p>\n <button id=\"doSomething\" type=\"button\">Do some magic!</button>\n </div>\n <script type=\"module\" src=\"/src/index.ts\"></script>\n </body>\n</html>\n`;\n}\n\nexport function indexTypescriptTemplate(displayName: string): string {\n return `import { kittl } from '@kittl/sdk';\n\ndocument.getElementById('doSomething')?.addEventListener('click', async () => {\n await kittl.design.text.addText({\n text: 'Hello ${displayName} from Kittl SDK!',\n position: {\n relative: {\n to: 'viewport',\n location: 'center',\n },\n },\n size: {\n height: 100,\n width: 400,\n },\n });\n});\n`;\n}\n\n// kittl logo\nexport const ICON_SVG_TEMPLATE =\n '<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"128\" height=\"128\" viewBox=\"0 0 1024 1024\"><rect width=\"1024\" height=\"1024\" rx=\"225\" fill=\"#DEFE00\"/><path fill=\"#080B10\" transform=\"translate(581,235)\" d=\"M0 0 C-7.93 26.81 -15.97 53.57 -24.12 80.31 C-24.35 81.04 -24.57 81.76 -24.79 82.5 C-25.92 86.19 -27.04 89.88 -28.17 93.57 C-28.5 94.67 -28.5 94.67 -28.85 95.8 C-29.3 97.29 -29.76 98.78 -30.21 100.27 C-35.39 117.26 -40.54 134.25 -45.69 151.25 C-46.09 152.58 -46.49 153.92 -46.9 155.25 C-47.68 157.83 -48.46 160.4 -49.24 162.98 C-50 165.48 -50.75 167.98 -51.51 170.48 C-53.37 176.6 -55.22 182.72 -57.06 188.84 C-57.99 191.91 -58.92 194.99 -59.84 198.06 C-60.29 199.54 -60.74 201.02 -61.18 202.51 C-61.8 204.56 -62.42 206.61 -63.04 208.67 C-63.4 209.84 -63.75 211.02 -64.12 212.23 C-65 215 -65 215 -66 217 C-31.32 207.79 -0.81 191.01 25.38 166.43 C27.48 164.48 29.6 162.63 31.81 160.81 C34.85 158.23 37.44 155.4 40.01 152.35 C41.45 150.66 42.91 148.99 44.39 147.34 C73.97 114.11 93.03 70.13 98 26 C113.47 23.05 128.96 20.3 144.5 17.74 C155.19 15.98 165.86 14.18 176.54 12.36 C178.95 11.95 181.37 11.54 183.79 11.13 C184.59 10.99 185.4 10.85 186.23 10.71 C187.86 10.44 189.49 10.16 191.13 9.88 C195.22 9.18 199.31 8.49 203.41 7.79 C207.32 7.12 211.22 6.45 215.13 5.79 C216.6 5.54 218.06 5.29 219.52 5.04 C221.55 4.69 223.57 4.35 225.6 4.01 C226.74 3.81 227.89 3.62 229.07 3.42 C232 3 232 3 236 3 C236.16 11.12 235.76 19 234.75 27.06 C234.62 28.15 234.48 29.23 234.34 30.35 C226.13 93.59 192.52 153.61 144 195 C143.05 195.84 142.11 196.67 141.13 197.53 C115.92 219.57 86.53 236.49 56 250 C55.6 259.92 56.83 269.35 58.31 279.13 C58.55 280.7 58.78 282.28 59.01 283.86 C59.57 287.61 60.14 291.36 60.71 295.11 C61.08 297.53 61.43 299.95 61.79 302.37 C64.96 323.35 70.45 343.85 77 364 C77.44 365.35 77.87 366.69 78.31 368.04 C87.9 397.66 98.51 426.64 111.58 454.91 C112.79 457.54 113.99 460.18 115.18 462.82 C120.11 473.66 125.8 484.06 131.59 494.45 C132.83 496.69 134.06 498.93 135.28 501.18 C144 517.14 153.68 532.57 165 546.81 C165.51 547.45 166.02 548.1 166.55 548.76 C167 549.32 167.45 549.87 167.92 550.45 C169 552 169 552 170 555 C169.42 555.28 168.83 555.56 168.23 555.85 C154.35 562.49 140.48 569.18 126.63 575.9 C115.75 581.18 104.87 586.45 93.98 591.7 C86.76 595.18 79.56 598.67 72.36 602.17 C66.13 605.19 59.89 608.21 53.66 611.23 C51.35 612.34 49.05 613.46 46.75 614.58 C44.04 615.89 41.33 617.2 38.63 618.5 C37.87 618.87 37.12 619.24 36.34 619.61 C33.37 621.03 31.33 622 28 622 C7.88 582.22 -1.64 541.14 -9.53 497.6 C-9.84 495.9 -10.14 494.21 -10.45 492.52 C-11.93 484.45 -13.35 476.42 -14.12 468.25 C-14.61 462.97 -14.61 462.97 -15.48 457.76 C-16.15 454.21 -16.43 450.66 -16.72 447.07 C-16.78 446.31 -16.84 445.56 -16.91 444.78 C-17.11 442.37 -17.3 439.97 -17.5 437.56 C-17.7 435.16 -17.89 432.76 -18.09 430.36 C-18.21 428.87 -18.34 427.38 -18.45 425.89 C-18.7 422.94 -18.99 420.04 -19.49 417.13 C-19.98 414.12 -20.26 411.19 -20.46 408.15 C-20.54 407.02 -20.62 405.88 -20.7 404.71 C-20.78 403.49 -20.86 402.26 -20.94 401 C-21.06 399.08 -21.06 399.08 -21.19 397.11 C-21.47 392.93 -21.74 388.75 -22 384.56 C-22.05 383.85 -22.09 383.14 -22.14 382.4 C-24.41 346.58 -25.21 310.89 -25 275 C-26.05 275.24 -27.1 275.48 -28.19 275.73 C-47.22 279.84 -66.64 281.24 -86 283 C-94.42 309.89 -102.59 336.84 -110.71 363.82 C-112.14 368.58 -113.57 373.34 -115 378.09 C-115.36 379.3 -115.36 379.3 -115.73 380.52 C-122.46 402.89 -129.26 425.23 -136.06 447.57 C-137.03 450.75 -137.99 453.93 -138.96 457.11 C-139.6 459.21 -140.24 461.32 -140.88 463.42 C-145.3 477.93 -149.64 492.47 -154 507 C-195.58 507 -237.16 507 -280 507 C-278.24 499.96 -276.51 493.16 -274.25 486.31 C-271.9 479.06 -269.79 471.77 -267.77 464.42 C-264.19 451.54 -260.37 438.73 -256.5 425.94 C-255.24 421.76 -253.98 417.58 -252.72 413.4 C-252.41 412.37 -252.1 411.35 -251.78 410.29 C-249.63 403.13 -247.52 395.96 -245.44 388.79 C-242.47 378.56 -239.41 368.37 -236.32 358.19 C-230.85 340.22 -230.85 340.22 -225.56 322.19 C-222.19 310.48 -218.62 298.84 -215.06 287.19 C-210.72 272.95 -206.4 258.7 -202.19 244.42 C-200.36 238.2 -198.51 231.98 -196.65 225.77 C-196.35 224.76 -196.05 223.75 -195.74 222.71 C-195.12 220.63 -194.5 218.55 -193.88 216.47 C-188.13 197.22 -188.13 197.22 -182.5 177.94 C-178.85 165.29 -174.97 152.72 -171.13 140.13 C-164.93 119.8 -158.75 99.46 -153 79 C-188.09 81.55 -226.46 97.99 -253 121 C-253.83 121.71 -254.66 122.42 -255.51 123.14 C-274.69 139.92 -289.02 161.6 -291.21 187.46 C-293.11 216.05 -280.75 245.26 -264.87 268.69 C-264.26 269.78 -263.64 270.87 -263 272 C-264.07 275.31 -265.83 276.91 -268.61 278.89 C-269.36 279.43 -270.1 279.96 -270.86 280.52 C-271.67 281.09 -272.48 281.66 -273.31 282.25 C-275.05 283.51 -276.79 284.76 -278.53 286.02 C-279.43 286.68 -280.33 287.33 -281.27 288 C-285.68 291.23 -290.03 294.55 -294.37 297.88 C-295.25 298.54 -296.12 299.21 -297.01 299.89 C-299.68 301.93 -302.34 303.96 -305 306 C-316.83 315.06 -328.7 324.04 -340.71 332.85 C-346.17 336.86 -351.59 340.92 -357 345 C-361.44 343.43 -363.83 339.89 -366.62 336.31 C-367.42 335.31 -367.42 335.31 -368.22 334.28 C-401.71 291.18 -419.04 237.97 -413.54 183.33 C-412.98 179.14 -412.11 175.08 -411 171 C-410.81 170.29 -410.62 169.57 -410.43 168.84 C-405.86 152.16 -397.84 136.47 -387 123 C-386.27 122.07 -385.54 121.14 -384.79 120.18 C-377.09 110.54 -368.68 102.62 -359 95 C-358.12 94.29 -357.24 93.58 -356.33 92.85 C-316.02 61.35 -264.24 45.67 -214.89 35.25 C-214.08 35.08 -213.27 34.91 -212.43 34.73 C-192.67 30.58 -172.78 27.22 -152.85 23.93 C-147.76 23.09 -142.68 22.24 -137.59 21.39 C-129.1 19.97 -120.6 18.56 -112.1 17.15 C-102.3 15.53 -92.51 13.9 -82.71 12.26 C-73.2 10.67 -63.69 9.09 -54.19 7.51 C-50.17 6.84 -46.15 6.17 -42.13 5.5 C-37.42 4.71 -32.71 3.93 -28 3.15 C-26.28 2.87 -24.56 2.58 -22.83 2.29 C-20.48 1.9 -18.12 1.51 -15.77 1.12 C-14.76 0.95 -14.76 0.95 -13.72 0.77 C-9.08 0.03 -4.68 -0.09 0 0 Z\"/></svg>';\n","import type { AxiosInstance } from 'axios';\nimport { z } from 'zod';\n\nconst developerOrganizationSchema = z.object({\n id: z.string(),\n name: z.string(),\n createdAt: z.string().optional(),\n updatedAt: z.string().optional(),\n});\n\nconst listResponseSchema = z.object({\n success: z.literal(true),\n result: z.object({\n developerOrganizations: z.array(developerOrganizationSchema),\n }),\n});\n\nconst createOrgResponseSchema = z.object({\n success: z.literal(true),\n result: z.object({\n developerOrganizationId: z.string(),\n }),\n});\n\nconst createExtensionResponseSchema = z.object({\n success: z.literal(true),\n result: z.object({\n extensionId: z.string(),\n }),\n});\n\nexport type DeveloperOrganization = z.infer<typeof developerOrganizationSchema>;\n\nexport async function listDeveloperOrganizations(\n client: AxiosInstance,\n): Promise<DeveloperOrganization[]> {\n const { data } = await client.get('/developer-organizations');\n const parsed = listResponseSchema.parse(data);\n return parsed.result.developerOrganizations;\n}\n\nexport async function createDeveloperOrganization(\n client: AxiosInstance,\n name: string,\n): Promise<string> {\n const { data } = await client.post('/developer-organizations', {\n name,\n });\n const parsed = createOrgResponseSchema.parse(data);\n return parsed.result.developerOrganizationId;\n}\n\nexport async function createExtensionInDeveloperOrganization(\n client: AxiosInstance,\n developerOrganizationId: string,\n body: { name: string; id?: string },\n): Promise<string> {\n const path = `/developer-organizations/${developerOrganizationId}/extensions`;\n const { data } = await client.post(path, body);\n const parsed = createExtensionResponseSchema.parse(data);\n return parsed.result.extensionId;\n}\n","import type { AxiosInstance } from 'axios';\nimport { Box, Text } from 'ink';\nimport type { ReactNode } from 'react';\nimport { useCallback, useState } from 'react';\nimport { formatHttpClientError } from '../../../core/error';\nimport {\n createDeveloperOrganization,\n createExtensionInDeveloperOrganization,\n type DeveloperOrganization,\n} from '../../../services/developer-organizations.service';\nimport { useTerminalWidth } from '../../hooks';\nimport { layoutStyles, textStyles } from '../../theme/styles';\nimport { spacing } from '../../theme/tokens';\nimport type { AppsInitOrgPickerResult } from './AppsInitOrgPickerView';\nimport { AppsInitOrgPickerView } from './AppsInitOrgPickerView';\nimport type { TextInputViewDone } from './TextInputView';\nimport { TextInputView } from './TextInputView';\n\nexport type AppInitWizardSuccess = {\n developerOrganizationId: string;\n developerOrganizationName: string;\n extensionId: string;\n extensionName: string;\n // True when the org was created in this wizard (vs chosen from the list).\n isNewDeveloperOrganizationCreated: boolean;\n};\n\nexport type AppInitWizardResult =\n | { kind: 'cancelled' }\n | { kind: 'success'; data: AppInitWizardSuccess };\n\ntype Step = 'pick' | 'org_name' | 'ext_name';\n\ntype WizardDraft = {\n developerOrganizationId?: string;\n developerOrganizationName?: string;\n isNewDeveloperOrganizationCreated?: boolean;\n};\n\nexport type AppInitWizardViewProps = {\n organizations: DeveloperOrganization[];\n client: AxiosInstance;\n extensionNameSuggestion?: string;\n onDone: (result: AppInitWizardResult) => void;\n};\n\nfunction AppInitStepShell({\n width,\n apiError,\n isLoading,\n loadingText,\n children,\n}: {\n width: number | string;\n apiError: string | null;\n isLoading: boolean;\n loadingText: string;\n children: ReactNode;\n}) {\n return (\n <Box flexDirection=\"column\" width={width} minWidth={0}>\n {apiError ? (\n <Box marginLeft={spacing.sm} marginBottom={spacing.sm}>\n <Text {...textStyles.error}>{apiError}</Text>\n </Box>\n ) : null}\n {isLoading ? (\n <Box {...layoutStyles.viewColumn}>\n <Text {...textStyles.muted}>{loadingText}…</Text>\n </Box>\n ) : (\n children\n )}\n </Box>\n );\n}\n\nexport function AppInitWizardView({\n organizations,\n client,\n extensionNameSuggestion,\n onDone,\n}: AppInitWizardViewProps) {\n const width = useTerminalWidth();\n const w = width > 0 ? width : '100%';\n\n const [step, setStep] = useState<Step>('pick');\n const [draft, setDraft] = useState<WizardDraft>({});\n const [apiError, setApiError] = useState<string | null>(null);\n const [isLoading, setIsLoading] = useState(false);\n\n const runTask = useCallback(async (task: () => Promise<void>) => {\n setApiError(null);\n setIsLoading(true);\n try {\n await task();\n } catch (e) {\n setApiError(formatHttpClientError(e));\n } finally {\n setIsLoading(false);\n }\n }, []);\n\n const handlePick = useCallback(\n (r: AppsInitOrgPickerResult) => {\n if (r.kind === 'cancelled') {\n onDone({ kind: 'cancelled' });\n return;\n }\n setApiError(null);\n if (r.kind === 'selected') {\n setDraft({\n developerOrganizationId: r.developerOrganizationId,\n developerOrganizationName: r.name,\n isNewDeveloperOrganizationCreated: false,\n });\n setStep('ext_name');\n return;\n }\n setDraft({});\n setStep('org_name');\n },\n [onDone],\n );\n\n const handleOrgName = useCallback(\n (r: TextInputViewDone) => {\n if (r.kind === 'cancelled') {\n onDone({ kind: 'cancelled' });\n return;\n }\n void runTask(async () => {\n const developerOrganizationId = await createDeveloperOrganization(\n client,\n r.value,\n );\n setDraft({\n developerOrganizationId,\n developerOrganizationName: r.value,\n isNewDeveloperOrganizationCreated: true,\n });\n setStep('ext_name');\n });\n },\n [client, onDone, runTask],\n );\n\n const handleExtName = useCallback(\n (r: TextInputViewDone) => {\n if (r.kind === 'cancelled') {\n onDone({ kind: 'cancelled' });\n return;\n }\n const orgId = draft.developerOrganizationId;\n const orgName = draft.developerOrganizationName;\n if (!orgId || !orgName) {\n return;\n }\n const isNewDeveloperOrganizationCreated = Boolean(\n draft.isNewDeveloperOrganizationCreated,\n );\n void runTask(async () => {\n const extensionId = await createExtensionInDeveloperOrganization(\n client,\n orgId,\n { name: r.value },\n );\n onDone({\n kind: 'success',\n data: {\n developerOrganizationId: orgId,\n developerOrganizationName: orgName,\n extensionId,\n extensionName: r.value,\n isNewDeveloperOrganizationCreated,\n },\n });\n });\n },\n [client, draft, onDone, runTask],\n );\n\n switch (step) {\n case 'pick':\n return (\n <AppsInitOrgPickerView\n organizations={organizations}\n onDone={handlePick}\n />\n );\n case 'org_name':\n return (\n <AppInitStepShell\n width={w}\n apiError={apiError}\n isLoading={isLoading}\n loadingText=\"Creating organization\"\n >\n <TextInputView\n key=\"wizard-org-name\"\n label=\"New organization name:\"\n placeholder=\"e.g. Functor Fountain Org\"\n onDone={handleOrgName}\n />\n </AppInitStepShell>\n );\n case 'ext_name':\n return (\n <AppInitStepShell\n width={w}\n apiError={apiError}\n isLoading={isLoading}\n loadingText=\"Creating extension\"\n >\n <TextInputView\n key=\"wizard-ext-name\"\n label=\"Extension name:\"\n placeholder=\"e.g. WASM-powered toaster\"\n initialValue={extensionNameSuggestion}\n onDone={handleExtName}\n />\n </AppInitStepShell>\n );\n }\n}\n","import { Box, type Key, Text, useInput } from 'ink';\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { isSubmitKey } from '../../../core/utils';\nimport { useTerminalWidth } from '../../hooks';\nimport { layoutStyles, textStyles } from '../../theme/styles';\nimport { colors } from '../../theme/tokens';\n\nexport type DeveloperOrganizationRow = {\n id: string;\n name: string;\n};\n\nexport type AppsInitOrgPickerResult =\n | { kind: 'selected'; developerOrganizationId: string; name: string }\n | { kind: 'create_new' }\n | { kind: 'cancelled' };\n\nexport type AppsInitOrgPickerViewProps = {\n organizations: DeveloperOrganizationRow[];\n onDone: (result: AppsInitOrgPickerResult) => void;\n};\n\nconst CREATE_NEW_LABEL = 'Create new organization';\n\nexport function AppsInitOrgPickerView({\n organizations,\n onDone,\n}: AppsInitOrgPickerViewProps) {\n const width = useTerminalWidth();\n const [index, setIndex] = useState(0);\n\n const indexRef = useRef(index);\n const organizationsRef = useRef(organizations);\n const onDoneRef = useRef(onDone);\n\n indexRef.current = index;\n organizationsRef.current = organizations;\n onDoneRef.current = onDone;\n\n useEffect(() => {\n const maxIndex = organizations.length;\n setIndex((i) => (i > maxIndex ? maxIndex : i));\n }, [organizations]);\n\n const labels = useMemo(\n () => [...organizations.map((o) => o.name), CREATE_NEW_LABEL],\n [organizations],\n );\n\n const handleInput = useCallback((_input: string, key: Key) => {\n if (key.escape) {\n onDoneRef.current({ kind: 'cancelled' });\n return;\n }\n if (isSubmitKey(key)) {\n const idx = indexRef.current;\n const orgs = organizationsRef.current;\n if (idx === orgs.length) {\n onDoneRef.current({ kind: 'create_new' });\n return;\n }\n const org = orgs[idx];\n onDoneRef.current({\n kind: 'selected',\n developerOrganizationId: org.id,\n name: org.name,\n });\n return;\n }\n if (key.upArrow) {\n setIndex((i) => {\n const rc = organizationsRef.current.length + 1;\n const next = i <= 0 ? rc - 1 : i - 1;\n indexRef.current = next;\n return next;\n });\n return;\n }\n if (key.downArrow) {\n setIndex((i) => {\n const rc = organizationsRef.current.length + 1;\n const next = i >= rc - 1 ? 0 : i + 1;\n indexRef.current = next;\n return next;\n });\n }\n }, []);\n\n useInput(handleInput);\n\n const empty = organizations.length === 0;\n\n return (\n <Box\n {...layoutStyles.viewColumn}\n width={width > 0 ? width : '100%'}\n minWidth={0}\n >\n <Text {...textStyles.title}>Select developer organization</Text>\n <Text {...textStyles.muted}>↑↓ move · Enter confirm · Esc cancel</Text>\n <Box {...layoutStyles.section} flexDirection=\"column\">\n {empty ? (\n <Box marginBottom={1}>\n <Text {...textStyles.muted}>\n {\"No organizations found. Let's make one!\"}\n </Text>\n </Box>\n ) : null}\n {labels.map((label, i) => {\n const isSelected = i === index;\n return (\n <Text\n key={`${label}-${i}`}\n bold={isSelected}\n color={isSelected ? colors.accent : undefined}\n >\n {isSelected ? '› ' : ' '}\n {label}\n </Text>\n );\n })}\n </Box>\n </Box>\n );\n}\n","import { Box, Text, useInput } from 'ink';\nimport TextInput from 'ink-text-input';\nimport { useCallback, useState } from 'react';\nimport { useTerminalWidth } from '../../hooks';\nimport { layoutStyles, textStyles } from '../../theme/styles';\n\nexport type TextInputViewDone =\n | { kind: 'submit'; value: string }\n | { kind: 'cancelled' };\n\nexport type TextInputViewProps = {\n label: string;\n placeholder?: string;\n /** Initial field value (trimmed once on mount). */\n initialValue?: string;\n // When true, Enter on whitespace-only keeps you on the screen with an error.\n requireNonEmpty?: boolean;\n onDone: (result: TextInputViewDone) => void;\n};\n\n/**\n * text input field using Ink + `ink-text-input`.\n */\nexport function TextInputView({\n label,\n placeholder,\n initialValue,\n requireNonEmpty = true,\n onDone,\n}: TextInputViewProps) {\n const width = useTerminalWidth();\n const [value, setValue] = useState(() => initialValue?.trim() ?? '');\n const [error, setError] = useState<string | null>(null);\n\n const finish = useCallback(\n (result: TextInputViewDone) => {\n onDone(result);\n },\n [onDone],\n );\n\n useInput((_input, key) => {\n if (key.escape) {\n finish({ kind: 'cancelled' });\n }\n });\n\n const handleSubmit = useCallback(\n (submitted: string) => {\n const trimmed = submitted.trim();\n if (requireNonEmpty && trimmed.length === 0) {\n setError('Cannot be empty.');\n return;\n }\n setError(null);\n finish({ kind: 'submit', value: trimmed });\n },\n [finish, requireNonEmpty],\n );\n\n return (\n <Box\n {...layoutStyles.viewColumn}\n width={width > 0 ? width : '100%'}\n minWidth={0}\n >\n <Text {...textStyles.title}>{label}</Text>\n <Box {...layoutStyles.section} flexDirection=\"row\" flexWrap=\"wrap\">\n <TextInput\n value={value}\n onChange={(v) => {\n setValue(v);\n if (error) {\n setError(null);\n }\n }}\n onSubmit={handleSubmit}\n placeholder={placeholder ?? ''}\n />\n </Box>\n {error ? (\n <Text {...textStyles.error}>{error}</Text>\n ) : (\n <Text {...textStyles.muted}>Enter confirm · Esc cancel</Text>\n )}\n </Box>\n );\n}\n"],"mappings":"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","names":["join","Box","Text","useCallback","useState","Box","Text","useInput","useCallback","useState","jsx","jsxs","useState","useCallback","useInput","Box","Text","jsx","jsxs","Box","Text","useState","useCallback","join"]}
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  markExtensionDraftReadyForReview
3
- } from "../../chunk-75SESNHC.js";
3
+ } from "../../chunk-E5EOPARA.js";
4
4
  import {
5
5
  formatExtensionReadyForReviewHttpError,
6
6
  readInternalConfig
7
- } from "../../chunk-A2IV54MU.js";
7
+ } from "../../chunk-344EUO2O.js";
8
8
  import {
9
9
  layoutStyles,
10
10
  spacing,
@@ -12,7 +12,7 @@ import {
12
12
  } from "../../chunk-3BPIJLS7.js";
13
13
  import {
14
14
  BaseCommand
15
- } from "../../chunk-BGJHRFGJ.js";
15
+ } from "../../chunk-F62NYF5U.js";
16
16
 
17
17
  // src/commands/app/release.ts
18
18
  import { Flags } from "@oclif/core";
@@ -1,14 +1,14 @@
1
1
  import {
2
2
  createExtensionDraftVersion
3
- } from "../../chunk-75SESNHC.js";
3
+ } from "../../chunk-E5EOPARA.js";
4
4
  import {
5
5
  formatHttpClientError,
6
6
  readInternalConfig
7
- } from "../../chunk-A2IV54MU.js";
7
+ } from "../../chunk-344EUO2O.js";
8
8
  import {
9
9
  BaseCommand,
10
10
  CLI_CONFIG
11
- } from "../../chunk-BGJHRFGJ.js";
11
+ } from "../../chunk-F62NYF5U.js";
12
12
 
13
13
  // src/commands/app/update.ts
14
14
  import { join } from "node:path";
@@ -2,7 +2,7 @@ import {
2
2
  formatExtensionArtifactUploadError,
3
3
  isSystemError,
4
4
  readInternalConfig
5
- } from "../../chunk-A2IV54MU.js";
5
+ } from "../../chunk-344EUO2O.js";
6
6
  import {
7
7
  useTerminalWidth
8
8
  } from "../../chunk-EKU4DKQK.js";
@@ -16,7 +16,7 @@ import {
16
16
  chunkArray,
17
17
  contentTypeForPath,
18
18
  listAllFilesUnderDir
19
- } from "../../chunk-BGJHRFGJ.js";
19
+ } from "../../chunk-F62NYF5U.js";
20
20
 
21
21
  // src/commands/app/upload.ts
22
22
  import { stat } from "node:fs/promises";
@@ -9,7 +9,7 @@ import {
9
9
  BaseCommand,
10
10
  INK_VIEW_UNMOUNT_REASON,
11
11
  authService
12
- } from "../../chunk-BGJHRFGJ.js";
12
+ } from "../../chunk-F62NYF5U.js";
13
13
 
14
14
  // src/ui/views/login/LoginView.tsx
15
15
  import { Box, Text as Text2 } from "ink";
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  BaseCommand,
3
3
  authService
4
- } from "../../chunk-BGJHRFGJ.js";
4
+ } from "../../chunk-F62NYF5U.js";
5
5
 
6
6
  // src/commands/auth/logout.ts
7
7
  var AuthLogout = class _AuthLogout extends BaseCommand {
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  AuthWhoAmI
3
- } from "../../chunk-O3BDWSZ5.js";
4
- import "../../chunk-BGJHRFGJ.js";
3
+ } from "../../chunk-7OPTDFSA.js";
4
+ import "../../chunk-F62NYF5U.js";
5
5
  export {
6
6
  AuthWhoAmI as default
7
7
  };
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  AuthWhoAmI
3
- } from "../chunk-O3BDWSZ5.js";
4
- import "../chunk-BGJHRFGJ.js";
3
+ } from "../chunk-7OPTDFSA.js";
4
+ import "../chunk-F62NYF5U.js";
5
5
  export {
6
6
  AuthWhoAmI as default
7
7
  };
@@ -30,7 +30,7 @@
30
30
  "required": false
31
31
  }
32
32
  },
33
- "description": "Initialize a Kittl app in the current directory or a new folder",
33
+ "description": "Initialize a Kittl app in the current directory OR in a custom PATH",
34
34
  "flags": {},
35
35
  "hasDynamicHelp": false,
36
36
  "hiddenAliases": [],
@@ -192,5 +192,5 @@
192
192
  ]
193
193
  }
194
194
  },
195
- "version": "0.0.5"
195
+ "version": "0.0.7"
196
196
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kittl/cli",
3
- "version": "0.0.5",
3
+ "version": "0.0.7",
4
4
  "license": "Apache-2.0",
5
5
  "private": false,
6
6
  "type": "module",
@@ -23,6 +23,8 @@
23
23
  ],
24
24
  "dependencies": {
25
25
  "@oclif/core": "^4.10.2",
26
+ "@oclif/plugin-autocomplete": "^3.2.45",
27
+ "@oclif/plugin-warn-if-update-available": "^3.1.60",
26
28
  "axios": "^1.13.6",
27
29
  "cross-keychain": "^1.1.0",
28
30
  "ink": "^6.8.0",
@@ -36,10 +38,25 @@
36
38
  "zod": "4.3.6"
37
39
  },
38
40
  "oclif": {
41
+ "additionalHelpFlags": [
42
+ "-h"
43
+ ],
44
+ "additionalVersionFlags": [
45
+ "-v"
46
+ ],
39
47
  "bin": "kittl",
40
48
  "commands": "./dist/commands",
41
49
  "dirname": "kittl",
42
- "topicSeparator": " "
50
+ "plugins": [
51
+ "@oclif/plugin-autocomplete",
52
+ "@oclif/plugin-warn-if-update-available"
53
+ ],
54
+ "topicSeparator": " ",
55
+ "warn-if-update-available": {
56
+ "frequency": 10,
57
+ "frequencyUnit": "minutes",
58
+ "message": "\n<%= chalk.yellow('A newer Kittl CLI is available!') %> <%= chalk.dim(config.version) %> -> <%= chalk.greenBright(latest) %>\n<%= chalk.cyan('Update: npm i -g @kittl/cli@latest') %>\n"
59
+ }
43
60
  },
44
61
  "scripts": {}
45
62
  }
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/core/files.ts","../src/core/utils.ts","../package.json","../src/constants.ts","../src/services/auth.service.ts","../src/services/session-vault.service.ts","../src/core/core.command.ts","../src/services/api.service.ts","../src/ui/renderer.ts"],"sourcesContent":["import { basename } from 'node:path';\nimport { lookup } from 'mime-types';\nimport { glob } from 'tinyglobby';\n\n/**\n * Last path segment\n */\nexport function getFileNameFromPath(filePath: string): string | undefined {\n const leaf = basename(filePath.trim());\n if (leaf === '' || leaf === '.' || leaf === '..') {\n return undefined;\n }\n return leaf;\n}\n\n/**\n * All files under `rootAbs` (recursive), absolute paths.\n * Does not traverse symlinked directories.\n */\nexport async function listAllFilesUnderDir(rootAbs: string): Promise<string[]> {\n return glob('**/*', {\n cwd: rootAbs,\n absolute: true,\n onlyFiles: true,\n dot: true,\n followSymbolicLinks: false,\n });\n}\n\n/**\n * Extension-based MIME for a path or basename. Unknown fallback to `application/octet-stream` (S3-safe).\n */\nexport function contentTypeForPath(filePath: string): string {\n const mime = lookup(filePath);\n return mime === false ? 'application/octet-stream' : mime;\n}\n","import { mkdir, readFile, stat } from 'node:fs/promises';\nimport type { Key } from 'ink';\nimport { getFileNameFromPath } from './files';\n\n/**\n * Parses a JSON string into a plain object.\n */\nexport function parseJsonObject(\n jsonText: string,\n errorContext: string,\n): Record<string, unknown> {\n let parsed: unknown;\n try {\n parsed = JSON.parse(jsonText) as unknown;\n } catch {\n throw new Error(`Invalid JSON (${errorContext})`);\n }\n if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {\n throw new Error(\n `JSON must be an object, not array or null (${errorContext})`,\n );\n }\n return parsed as Record<string, unknown>;\n}\n\n// Reads a file and parses its contents as a JSON object.\nexport async function parseJsonObjectFromFile(\n filePath: string,\n): Promise<Record<string, unknown>> {\n const jsonText = await readFile(filePath, 'utf8');\n return parseJsonObject(jsonText, filePath);\n}\n\n/**\n * Ensures `dirPath` exists as a directory: creates it (and parents) when\n * missing, or throws if the path exists and is not a directory.\n */\nexport async function ensureDirectory(dirPath: string): Promise<void> {\n try {\n const s = await stat(dirPath);\n if (!s.isDirectory()) {\n throw new Error(`${dirPath} exists and is not a directory.`);\n }\n } catch (e) {\n // Not `isSystemError` from `./error`: this module is imported by `constants.ts`.\n if (\n e instanceof Error &&\n 'code' in e &&\n (e as NodeJS.ErrnoException).code === 'ENOENT'\n ) {\n await mkdir(dirPath, { recursive: true });\n return;\n }\n throw e;\n }\n}\n\n// Silent UI teardown (e.g. Ink unmount). not user-initiated cancel.\nexport const INK_VIEW_UNMOUNT_REASON = Symbol('INK_VIEW_UNMOUNT_REASON');\n\n/**\n * Reads `process.env[envKey]` as a TCP port, or {@link defaultPort} when unset/blank.\n * Must be an integer in 1–65535 when set.\n */\nexport function parsePortFromEnv(envKey: string, defaultPort: number): number {\n const raw = process.env[envKey];\n const n = Number(raw?.trim() || defaultPort);\n if (!Number.isInteger(n) || n < 1 || n > 65_535) {\n throw new Error(\n `${envKey} must be an integer between 1 and 65535 (got ${JSON.stringify(raw)}).`,\n );\n }\n return n;\n}\n\n// Fixed localhost OAuth callback path for Authorization Code + PKCE.\nexport function localhostOAuthRedirectUri(port: number): string {\n return `http://localhost:${port}/callback`;\n}\n\nexport function getKittlEnvEntries(): string[] {\n return Object.entries(process.env)\n .filter(([key]) => key.startsWith('KITTL_'))\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([key, value]) => `${key}=${value ?? ''}`);\n}\n\n// Enter key across terminal variants (`return` + optional `enter`).\nexport function isSubmitKey(key: Key): boolean {\n if (key.return) {\n return true;\n }\n return Boolean((key as Key & { enter?: boolean }).enter);\n}\n\n/**\n * Resolves a file name from an env value via {@link getFileNameFromPath};\n * empty or invalid values fall back to `defaultFileName`.\n */\nexport function resolveFileNameFromEnv(\n envValue: string | undefined,\n defaultFileName: string,\n): string {\n const raw = envValue?.trim() ?? '';\n if (raw === '') {\n return defaultFileName;\n }\n return getFileNameFromPath(raw) ?? defaultFileName;\n}\n\n// Split an array into consecutive slices of at most `chunkSize` items.\nexport function chunkArray<T>(items: T[], chunkSize: number): T[][] {\n if (chunkSize < 1) {\n throw new Error('chunkSize must be at least 1');\n }\n const n = Math.ceil(items.length / chunkSize);\n return Array.from({ length: n }, (_, i) =>\n items.slice(i * chunkSize, i * chunkSize + chunkSize),\n );\n}\n","{\n \"name\": \"@kittl/cli\",\n \"version\": \"0.0.5\",\n \"license\": \"Apache-2.0\",\n \"private\": false,\n \"type\": \"module\",\n \"engines\": {\n \"node\": \">=18\"\n },\n \"bin\": {\n \"kittl\": \"./bin/run.js\",\n \"kittl-dev\": \"./bin/dev.js\"\n },\n \"publishConfig\": {\n \"access\": \"public\",\n \"bin\": {\n \"kittl\": \"./bin/run.js\"\n }\n },\n \"files\": [\n \"LICENSE\",\n \"oclif.manifest.json\",\n \"bin/bootstrap.js\",\n \"bin/run.cmd\",\n \"bin/run.js\",\n \"dist\"\n ],\n \"scripts\": {\n \"prepack\": \"pnpm run build && clean-package\",\n \"postpack\": \"clean-package restore\",\n \"build\": \"tsup && oclif manifest\",\n \"build:watch\": \"tsup --watch --onSuccess \\\"oclif manifest\\\"\",\n \"dev\": \"node ./bin/dev.js\",\n \"dev:watch\": \"node --watch --watch-path=./src --watch-path=./bin ./bin/dev.js\",\n \"typecheck\": \"tsc --noEmit\",\n \"test\": \"vitest run\",\n \"test:watch\": \"vitest\"\n },\n \"dependencies\": {\n \"@oclif/core\": \"^4.10.2\",\n \"axios\": \"^1.13.6\",\n \"cross-keychain\": \"^1.1.0\",\n \"ink\": \"^6.8.0\",\n \"ink-text-input\": \"^6.0.0\",\n \"jwt-decode\": \"^4.0.0\",\n \"mime-types\": \"^3.0.1\",\n \"open\": \"^11.0.0\",\n \"openid-client\": \"^6.8.2\",\n \"react\": \"catalog:\",\n \"tinyglobby\": \"^0.2.15\",\n \"zod\": \"catalog:\"\n },\n \"devDependencies\": {\n \"@types/mime-types\": \"^3.0.1\",\n \"@types/node\": \"^25.5.0\",\n \"@types/react\": \"catalog:\",\n \"clean-package\": \"^2.2.0\",\n \"ink-testing-library\": \"^4.0.0\",\n \"oclif\": \"^4.22.96\",\n \"tsup\": \"catalog:\",\n \"tsx\": \"catalog:\",\n \"typescript\": \"catalog:\",\n \"vitest\": \"^4.1.1\"\n },\n \"oclif\": {\n \"bin\": \"kittl\",\n \"commands\": \"./dist/commands\",\n \"dirname\": \"kittl\",\n \"topicSeparator\": \" \"\n }\n}\n","import pkg from '../package.json' with { type: 'json' };\nimport {\n localhostOAuthRedirectUri,\n parsePortFromEnv,\n resolveFileNameFromEnv,\n} from './core/utils';\n\nconst { version } = pkg;\n\nconst CLI_CONFIG_DIR = '.kittl' as const;\nconst CLI_CONFIG_DEFAULT_FILENAME = 'config.json' as const;\nconst CLI_MANIFEST_DEFAULT_FILENAME = 'manifest.json' as const;\n\nexport const PRODUCTION = {\n issuer: 'https://keycloak.kittl.dev/auth/realms/kittl',\n apiBaseUrl: 'https://api.kittl.com',\n clientId: 'kittl-cli',\n redirectPort: 51771,\n scaffoldViteDevPort: 5173,\n} as const;\n\n// -----------------------------------------------------------------------------\n// CLI configs\n// -----------------------------------------------------------------------------\n\nexport const CLI_CONFIG = {\n configDir: CLI_CONFIG_DIR,\n defaultConfigFileName: CLI_CONFIG_DEFAULT_FILENAME,\n configFileName: resolveFileNameFromEnv(\n process.env.KITTL_CONFIG_FILENAME,\n CLI_CONFIG_DEFAULT_FILENAME,\n ),\n defaultManifestFileName: CLI_MANIFEST_DEFAULT_FILENAME,\n manifestFileName: resolveFileNameFromEnv(\n process.env.KITTL_EXTENSION_MANIFEST_FILENAME,\n CLI_MANIFEST_DEFAULT_FILENAME,\n ),\n scaffoldViteDevPort: parsePortFromEnv(\n 'KITTL_SCAFFOLD_VITE_DEV_PORT',\n PRODUCTION.scaffoldViteDevPort,\n ),\n} as const;\n\n// -----------------------------------------------------------------------------\n// OAuth / OIDC (PKCE login, keychain session)\n// -----------------------------------------------------------------------------\n\nconst authRedirectPort = parsePortFromEnv(\n 'KITTL_REDIRECT_PORT',\n PRODUCTION.redirectPort,\n);\n\nexport const AUTH_CONFIG = {\n issuer: process.env.KITTL_OAUTH_ISSUER_URL ?? PRODUCTION.issuer,\n clientId: process.env.KITTL_OAUTH_CLIENT_ID ?? PRODUCTION.clientId,\n redirectPort: authRedirectPort,\n redirectUri: localhostOAuthRedirectUri(authRedirectPort),\n scope: process.env.KITTL_OAUTH_SCOPE ?? 'openid profile email offline_access',\n // https://www.keycloak.org/docs/latest/server_admin/index.html#_authentication-sessions\n authPrompt: process.env.KITTL_OAUTH_PROMPT || 'login',\n oauthCallbackTimeoutMs: Number(\n process.env.KITTL_OAUTH_CALLBACK_TIMEOUT_MS ?? 120_000,\n ),\n /** Optional 302 after OAuth; if undefined it renders a fallback HTML. */\n oauthSuccessRedirectUrl:\n process.env.KITTL_OAUTH_SUCCESS_REDIRECT_URL || undefined,\n serviceName: 'kittl-cli',\n accountName: 'oauth-session',\n} as const;\n\n// -----------------------------------------------------------------------------\n// HTTP API (Axios base URL for Kittl APIs)\n// -----------------------------------------------------------------------------\n\nexport const API_CONFIG = {\n baseUrl: process.env.KITTL_API_BASE_URL ?? PRODUCTION.apiBaseUrl,\n timeoutMs: 30_000,\n userAgent: `kittl-cli/${version}`,\n} as const;\n","import { createServer } from 'node:http';\nimport { URL } from 'node:url';\nimport open from 'open';\nimport * as oidc from 'openid-client';\nimport { z } from 'zod';\nimport { AUTH_CONFIG } from '../constants';\nimport type { Session } from '../types/session';\nimport { sessionVault } from './session-vault.service';\n\n// Seconds before access token expiry when we proactively refresh.\nconst ACCESS_TOKEN_REFRESH_BUFFER_SEC = 60;\n\nconst OAUTH2_TOKEN_ERROR_INVALID_GRANT = 'invalid_grant';\n\nexport type LoginOptions = {\n signal?: AbortSignal;\n};\n\nexport type CallbackResult = {\n callbackUrl: URL;\n};\n\nconst authConfigSchema = z.object({\n issuer: z.url(),\n clientId: z.string().min(1),\n redirectUri: z.url(),\n redirectPort: z.number().int().min(1).max(65_535),\n scope: z.string().min(1),\n authPrompt: z.string().min(1),\n oauthCallbackTimeoutMs: z.number().int().min(5_000).max(3_600_000),\n oauthSuccessRedirectUrl: z.url().optional(),\n});\n\nexport class LoginCancelledError extends Error {\n public constructor() {\n super('Login cancelled.');\n this.name = 'LoginCancelledError';\n }\n}\n\nexport class AuthService {\n private readonly config = authConfigSchema.parse(AUTH_CONFIG);\n\n // concurrent refresh attempts are merged into a single promise\n private refreshSessionPromise: Promise<Session | null> | null = null;\n\n /**\n * raw vault read.\n */\n public async getStoredSession(): Promise<Session | null> {\n return sessionVault.getSession();\n }\n\n /**\n * ensures token freshness (by silently refresh if needed)\n */\n public async getSession(): Promise<Session | null> {\n await this.getAccessToken();\n return this.getStoredSession();\n }\n\n /**\n * Returns a usable access token, silently refreshing when `expiresAt` is within {@link ACCESS_TOKEN_REFRESH_BUFFER_SEC}\n * seconds (or in the past). based on Session.expiresAt.\n */\n public async getAccessToken(): Promise<string | undefined> {\n const session = await this.getStoredSession();\n if (!session?.accessToken) return undefined;\n\n if (!this.shouldRefreshAccessToken(session)) {\n return session.accessToken;\n }\n\n if (!session.refreshToken) {\n await sessionVault.clear();\n return undefined;\n }\n\n const refreshed = await this.refreshSession();\n return refreshed?.accessToken;\n }\n\n /**\n * Refresh tokens via the OIDC token endpoint. On hard failure (e.g. `invalid_grant`), clears the vault.\n */\n public async refreshSession(): Promise<Session | null> {\n if (this.refreshSessionPromise) {\n return this.refreshSessionPromise;\n }\n this.refreshSessionPromise = this.performRefreshSession().finally(() => {\n this.refreshSessionPromise = null;\n });\n return this.refreshSessionPromise;\n }\n\n private shouldRefreshAccessToken(session: Session): boolean {\n if (session.expiresAt === undefined) return false;\n const now = Math.floor(Date.now() / 1000);\n return session.expiresAt <= now + ACCESS_TOKEN_REFRESH_BUFFER_SEC;\n }\n\n private async performRefreshSession(): Promise<Session | null> {\n const session = await this.getStoredSession();\n if (!session?.refreshToken) {\n await sessionVault.clear();\n return null;\n }\n\n try {\n const oidcConfig = await this.discoverOidcConfiguration();\n\n const tokenSet = await oidc.refreshTokenGrant(\n oidcConfig,\n session.refreshToken,\n { scope: this.config.scope },\n undefined,\n );\n\n const newSession = this.mapTokenSetToSession(tokenSet, session);\n\n await sessionVault.saveSession(newSession);\n return newSession;\n } catch (error) {\n if (\n error instanceof oidc.ResponseBodyError &&\n error.error === OAUTH2_TOKEN_ERROR_INVALID_GRANT\n ) {\n await sessionVault.clear();\n return null;\n }\n return null;\n }\n }\n\n private async discoverOidcConfiguration(): Promise<oidc.Configuration> {\n const issuerUrl = new URL(this.config.issuer);\n return oidc.discovery(\n issuerUrl,\n this.config.clientId,\n undefined,\n undefined,\n {\n ...(issuerUrl.protocol === 'http:'\n ? { execute: [oidc.allowInsecureRequests] as const }\n : {}),\n } as Parameters<typeof oidc.discovery>[4],\n );\n }\n\n public async login(options?: LoginOptions): Promise<Session> {\n const { signal } = options ?? {};\n\n const oidcConfig = await this.discoverOidcConfiguration();\n signal?.throwIfAborted();\n\n const codeVerifier = oidc.randomPKCECodeVerifier();\n const codeChallenge = await oidc.calculatePKCECodeChallenge(codeVerifier);\n const state = oidc.randomState();\n const nonce = oidc.randomNonce();\n\n const authorizationUrl = oidc.buildAuthorizationUrl(oidcConfig, {\n redirect_uri: this.config.redirectUri,\n response_type: 'code',\n scope: this.config.scope,\n code_challenge: codeChallenge,\n code_challenge_method: 'S256',\n state,\n nonce,\n prompt: this.config.authPrompt,\n });\n\n signal?.throwIfAborted();\n await this.openBrowser(authorizationUrl.toString());\n\n const callback = await this.waitForCallback(signal);\n\n const tokenSet = await oidc.authorizationCodeGrant(\n oidcConfig,\n callback.callbackUrl,\n {\n pkceCodeVerifier: codeVerifier,\n expectedState: state,\n expectedNonce: nonce,\n },\n );\n\n const session = this.mapTokenSetToSession(tokenSet);\n\n await sessionVault.saveSession(session);\n return session;\n }\n\n public async logout(): Promise<void> {\n await sessionVault.clear();\n }\n\n /**\n * Starts a short-lived `http` server on the host/port from the configured `redirectUri` so the IdP can\n * redirect the browser to `…/callback?code=…&state=…` (Authorization Code + PKCE). The first matching request\n * stops the server and resolves with that URL for the token exchange (`authorizationCodeGrant`).\n *\n * - **Success response:** HTTP 302 to {@link AUTH_CONFIG.oauthSuccessRedirectUrl} when set; otherwise a minimal inline HTML page.\n */\n private async waitForCallback(signal?: AbortSignal): Promise<CallbackResult> {\n const redirectUrl = new URL(this.config.redirectUri);\n const hostname = redirectUrl.hostname;\n const port = Number(redirectUrl.port);\n const pathname = redirectUrl.pathname;\n\n const timeoutSignal = AbortSignal.timeout(\n this.config.oauthCallbackTimeoutMs,\n );\n const combinedSignal =\n signal !== undefined\n ? AbortSignal.any([signal, timeoutSignal])\n : timeoutSignal;\n\n return new Promise((resolve, reject) => {\n let closed = false;\n\n const server = createServer((req, res) => {\n try {\n const requestUrl = new URL(req.url ?? '', this.config.redirectUri);\n if (requestUrl.pathname !== pathname) {\n res.statusCode = 404;\n res.end('Not Found');\n return;\n }\n\n const callbackUrl = new URL(this.config.redirectUri);\n callbackUrl.search = requestUrl.search;\n\n const brandUrl = this.config.oauthSuccessRedirectUrl;\n if (brandUrl) {\n res.writeHead(302, { Location: brandUrl });\n res.end();\n } else {\n res.statusCode = 200;\n res.setHeader('content-type', 'text/html; charset=utf-8');\n res.end(\n '<!doctype html><html><body><h2>Authentication complete.</h2><p>You can close this tab and return to the terminal.</p></body></html>',\n );\n }\n\n closeServer((closeErr?: Error) => {\n if (closeErr) {\n reject(closeErr);\n return;\n }\n resolve({ callbackUrl });\n });\n } catch (error) {\n closeServer(() => reject(error));\n }\n });\n\n const closeServer = (onClosed: (closeErr?: Error) => void): void => {\n if (closed) return;\n closed = true;\n combinedSignal.removeEventListener('abort', onCombinedAbort);\n if (!server.listening) {\n onClosed();\n return;\n }\n server.closeAllConnections();\n server.close((closeErr) => {\n onClosed(closeErr ?? undefined);\n });\n };\n\n function onCombinedAbort(): void {\n closeServer((closeErr?: Error) => {\n if (closeErr) {\n reject(closeErr);\n return;\n }\n if (signal?.aborted) {\n reject(signal.reason ?? new LoginCancelledError());\n return;\n }\n if (timeoutSignal.aborted) {\n reject(new Error('Login timed out. Please try again.'));\n return;\n }\n reject(new LoginCancelledError());\n });\n }\n\n server.on('error', (error: NodeJS.ErrnoException) => {\n closeServer(() => {\n if (error.code === 'EADDRINUSE') {\n const inUsePort =\n (error as NodeJS.ErrnoException & { port?: number }).port ?? port;\n reject(\n new Error(\n `Port ${String(inUsePort)} is already in use. Close the other app using it or set KITTL_REDIRECT_PORT to a free port, then try again.`,\n ),\n );\n return;\n }\n reject(error);\n });\n });\n\n // 1. Abort before any listen: avoids a half-started server; early exit skips `listen` entirely.\n combinedSignal.addEventListener('abort', onCombinedAbort, { once: true });\n if (combinedSignal.aborted) {\n onCombinedAbort();\n return;\n }\n\n server.listen(port, hostname);\n });\n }\n\n private async openBrowser(url: string): Promise<void> {\n await open(url);\n }\n\n private mapTokenSetToSession(\n tokenSet: oidc.TokenEndpointResponse,\n currentSession?: Session,\n ): Session {\n return {\n accessToken: tokenSet.access_token,\n refreshToken: tokenSet.refresh_token ?? currentSession?.refreshToken,\n idToken: tokenSet.id_token ?? currentSession?.idToken,\n tokenType: tokenSet.token_type ?? currentSession?.tokenType,\n expiresAt: tokenSet.expires_in\n ? Math.floor(Date.now() / 1000) + tokenSet.expires_in\n : undefined,\n };\n }\n}\n\nexport const authService = new AuthService();\n","import { deletePassword, getPassword, setPassword } from 'cross-keychain';\nimport { AUTH_CONFIG } from '../constants';\nimport type { Session } from '../types/session';\n\nconst SESSION_META_VERSION = 2 as const;\n\n// suffix for split v2 accounts: `{AUTH_CONFIG.accountName}.{suffix}`.\nconst SESSION_V2_KEY_SUFFIX = {\n meta: 'meta',\n access: 'access',\n refresh: 'refresh',\n id: 'id',\n} as const;\n\ntype SessionMetaV2 = {\n v: typeof SESSION_META_VERSION;\n tokenType?: string;\n expiresAt?: number;\n};\n\n/**\n * Persists OIDC session (tokens) in the OS credential store (e.g. Keychain).\n */\nexport class SessionVault {\n private readonly keychainService = this.buildKeychainServiceName();\n private readonly keychainAccount = AUTH_CONFIG.accountName;\n\n private buildKeychainServiceName(): string {\n try {\n const issuerUrl = new URL(AUTH_CONFIG.issuer);\n const issuerKey = this.sanitizeKeychainSegment(\n `${issuerUrl.hostname}${issuerUrl.port ? `-${issuerUrl.port}` : ''}`,\n );\n return `${AUTH_CONFIG.serviceName}-${issuerKey}`;\n } catch {\n // Keep previous behavior when issuer is not a valid URL.\n return AUTH_CONFIG.serviceName;\n }\n }\n\n private sanitizeKeychainSegment(value: string): string {\n return value.replace(/[^a-zA-Z0-9._@-]/g, '-');\n }\n\n private account(suffix: string): string {\n return `${this.keychainAccount}.${suffix}`;\n }\n\n public async getSession(): Promise<Session | null> {\n const metaRaw = await getPassword(\n this.keychainService,\n this.account(SESSION_V2_KEY_SUFFIX.meta),\n );\n\n let meta: SessionMetaV2 | null = null;\n if (metaRaw) {\n try {\n const parsed = JSON.parse(metaRaw) as SessionMetaV2;\n if (parsed.v === SESSION_META_VERSION) {\n meta = parsed;\n }\n } catch {\n meta = null;\n }\n }\n // if meta is present, read based on v2\n if (meta) {\n const accessRaw = await getPassword(\n this.keychainService,\n this.account(SESSION_V2_KEY_SUFFIX.access),\n );\n // fallback, if not defined, to legacy monolithic read\n const accessToken = accessRaw?.trim();\n if (accessToken) {\n const refreshRaw = await getPassword(\n this.keychainService,\n this.account(SESSION_V2_KEY_SUFFIX.refresh),\n );\n const idRaw = await getPassword(\n this.keychainService,\n this.account(SESSION_V2_KEY_SUFFIX.id),\n );\n\n return {\n accessToken,\n refreshToken: refreshRaw ?? undefined,\n idToken: idRaw ?? undefined,\n tokenType: meta.tokenType,\n expiresAt: meta.expiresAt,\n };\n }\n }\n // read based on legacy monolithic\n const raw = await getPassword(this.keychainService, this.keychainAccount);\n if (!raw) return null;\n\n try {\n return JSON.parse(raw) as Session;\n } catch {\n return null;\n }\n }\n\n public async saveSession(session: Session): Promise<void> {\n const meta: SessionMetaV2 = {\n v: SESSION_META_VERSION,\n tokenType: session.tokenType,\n expiresAt: session.expiresAt,\n };\n\n const accessToken = session.accessToken.trim();\n await setPassword(\n this.keychainService,\n this.account(SESSION_V2_KEY_SUFFIX.access),\n accessToken,\n );\n await this.setOrDeleteTokenAccount(\n SESSION_V2_KEY_SUFFIX.refresh,\n session.refreshToken,\n );\n await this.setOrDeleteTokenAccount(\n SESSION_V2_KEY_SUFFIX.id,\n session.idToken,\n );\n await setPassword(\n this.keychainService,\n this.account(SESSION_V2_KEY_SUFFIX.meta),\n JSON.stringify(meta),\n );\n\n await this.deleteLegacyMonolithicIfPresent();\n }\n\n // when auth omits an optional token, remove any previously stored value as well\n private async setOrDeleteTokenAccount(\n suffix:\n | typeof SESSION_V2_KEY_SUFFIX.refresh\n | typeof SESSION_V2_KEY_SUFFIX.id,\n token: string | undefined,\n ): Promise<void> {\n const acc = this.account(suffix);\n const trimmed = token?.trim();\n if (trimmed) {\n await setPassword(this.keychainService, acc, trimmed);\n return;\n }\n const existing = await getPassword(this.keychainService, acc);\n if (existing) {\n await deletePassword(this.keychainService, acc);\n }\n }\n\n // older releases stored the whole session JSON under {@link keychainAccount} only\n private async deleteLegacyMonolithicIfPresent(): Promise<void> {\n const legacy = await getPassword(\n this.keychainService,\n this.keychainAccount,\n );\n if (!legacy) return;\n try {\n await deletePassword(this.keychainService, this.keychainAccount);\n } catch {\n // ignore, best effort cleanup\n }\n }\n\n public async clear(): Promise<void> {\n const accounts = [\n ...Object.values(SESSION_V2_KEY_SUFFIX).map((suffix) =>\n this.account(suffix),\n ),\n this.keychainAccount,\n ];\n for (const account of accounts) {\n const existing = await getPassword(this.keychainService, account);\n if (existing) {\n try {\n await deletePassword(this.keychainService, account);\n } catch {\n // ignore\n }\n }\n }\n }\n}\n\nexport const sessionVault = new SessionVault();\n","import { Command } from '@oclif/core';\nimport type { AxiosInstance } from 'axios';\nimport type { FC } from 'react';\nimport { API_CONFIG } from '../constants';\nimport { kittlApiService } from '../services/api.service';\nimport { authService } from '../services/auth.service';\nimport type { Session } from '../types/session';\nimport { runInteractiveView, type ViewWithDone } from '../ui/renderer';\nimport { getKittlEnvEntries } from './utils';\n\nexport abstract class BaseCommand extends Command {\n protected session: Session | null = null;\n\n public override async init(): Promise<void> {\n await super.init();\n this.session = await authService.getSession();\n kittlApiService.setAccessTokenProvider(async () =>\n authService.getAccessToken(),\n );\n\n const envEntries = getKittlEnvEntries();\n this.debug(`API base URL: ${API_CONFIG.baseUrl}`);\n this.debug(`KITTL_* variables:\\n${envEntries.join('\\n') || '(none)'}`);\n }\n\n protected getKittlApiClient(): AxiosInstance {\n return kittlApiService.getClient();\n }\n\n /**\n * Ensures a valid access token (+ refreshes when the accessToken is near expiry).\n */\n protected async ensureAuthenticated(): Promise<Session> {\n const session = await authService.getSession();\n if (!session?.accessToken) {\n this.error(\n `Session expired. Run \\`${this.config.bin} auth login\\` first.`,\n { exit: 2 },\n );\n }\n\n this.session = session;\n return session;\n }\n\n /**\n * Run an Ink view that reports a result via `onDone`, then unmount and return.\n * PRO TIP: use `this.log` / `this.error` after this resolves, not inside the view!! for final line stays on stdout.\n */\n protected async renderView<R>(View: FC<ViewWithDone<R>>): Promise<R>;\n protected async renderView<R, P extends object>(\n View: FC<P & ViewWithDone<R>>,\n props: P,\n ): Promise<R>;\n protected async renderView<R, P extends object>(\n View: FC<P & ViewWithDone<R>>,\n ...args: Partial<P> extends P ? [props?: P] : [props: P]\n ): Promise<R> {\n return runInteractiveView<R, P>(View, ...args);\n }\n}\n","import axios, {\n type AxiosError,\n AxiosHeaders,\n type AxiosInstance,\n type InternalAxiosRequestConfig,\n} from 'axios';\nimport { API_CONFIG } from '../constants';\nimport { authService } from './auth.service';\n\ntype AccessTokenProvider = () => Promise<string | undefined>;\ntype RetriableRequestConfig = InternalAxiosRequestConfig & {\n _retry?: boolean;\n};\n\nexport class KittlApiService {\n private readonly client: AxiosInstance;\n private accessTokenProvider?: AccessTokenProvider;\n\n public constructor() {\n this.client = axios.create({\n baseURL: API_CONFIG.baseUrl,\n timeout: API_CONFIG.timeoutMs,\n headers: {\n 'User-Agent': API_CONFIG.userAgent,\n },\n });\n\n this.client.interceptors.request.use(\n async (config: RetriableRequestConfig) => {\n if (config.skipAuth) {\n return config;\n }\n const token = await this.accessTokenProvider?.();\n if (token) {\n this.setAuthorizationHeader(config, token);\n }\n return config;\n },\n );\n\n this.client.interceptors.response.use(\n (response) => response,\n async (error: AxiosError) => {\n const originalRequest = error.config as\n | RetriableRequestConfig\n | undefined;\n // Retry only first-time 401 responses with a valid original request.\n if (\n error.response?.status !== 401 ||\n !originalRequest ||\n originalRequest.skipAuth ||\n originalRequest._retry\n ) {\n throw error;\n }\n\n // Mark as retried to avoid infinite retry loops.\n originalRequest._retry = true;\n // Force-refresh the token before replaying the request.\n const refreshedSession = await authService.refreshSession();\n const refreshedToken = refreshedSession?.accessToken;\n if (!refreshedToken) {\n throw error;\n }\n\n // Re-run the original request with updated Authorization header.\n this.setAuthorizationHeader(originalRequest, refreshedToken);\n return this.client.request(originalRequest);\n },\n );\n }\n\n public setAccessTokenProvider(provider: AccessTokenProvider): void {\n this.accessTokenProvider = provider;\n }\n\n public getClient(): AxiosInstance {\n return this.client;\n }\n\n private setAuthorizationHeader(\n config: InternalAxiosRequestConfig,\n token: string,\n ): void {\n const headers = AxiosHeaders.from(config.headers);\n headers.set('Authorization', `Bearer ${token}`);\n config.headers = headers;\n }\n}\n\nexport const kittlApiService = new KittlApiService();\n","import { render } from 'ink';\nimport React, { type FC } from 'react';\n\n/**\n * Standard shape for a view that reports a result.\n */\nexport type ViewWithDone<R> = { onDone: (result: R) => void };\n\n/**\n * The entrypoint that touches Ink's render process.\n */\nexport async function runInteractiveView<R, P extends object>(\n View: FC<P & ViewWithDone<R>>,\n ...args: Partial<P> extends P ? [props?: P] : [props: P]\n): Promise<R> {\n const props = args[0];\n\n return new Promise<R>((resolve, reject) => {\n const app = render(\n React.createElement(View, {\n ...(props ?? ({} as P)),\n onDone: (result: R) => {\n void (async () => {\n app.unmount();\n await app.waitUntilExit();\n resolve(result);\n })().catch(reject);\n },\n } as P & ViewWithDone<R>),\n );\n });\n}\n"],"mappings":"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","names":["URL","URL"]}