@agentskit/chat-cli 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs ADDED
@@ -0,0 +1,358 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __export = (target, all) => {
10
+ for (var name in all)
11
+ __defProp(target, name, { get: all[name], enumerable: true });
12
+ };
13
+ var __copyProps = (to, from, except, desc) => {
14
+ if (from && typeof from === "object" || typeof from === "function") {
15
+ for (let key of __getOwnPropNames(from))
16
+ if (!__hasOwnProp.call(to, key) && key !== except)
17
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
18
+ }
19
+ return to;
20
+ };
21
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
22
+ // If the importer is in node compatibility mode or this is not an ESM
23
+ // file that has been converted to a CommonJS file using a Babel-
24
+ // compatible transform (i.e. "__esModule" has not been set), then set
25
+ // "default" to the CommonJS "module.exports" for node compatibility.
26
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
27
+ mod
28
+ ));
29
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
30
+
31
+ // src/index.ts
32
+ var src_exports = {};
33
+ __export(src_exports, {
34
+ CHAT_RENDERERS: () => CHAT_RENDERERS,
35
+ ChatCliError: () => ChatCliError,
36
+ ChatRendererSchema: () => ChatRendererSchema,
37
+ addChatComponent: () => addChatComponent,
38
+ detectRenderer: () => detectRenderer,
39
+ initChatProject: () => initChatProject
40
+ });
41
+ module.exports = __toCommonJS(src_exports);
42
+ var import_promises = require("fs/promises");
43
+ var import_node_path = __toESM(require("path"), 1);
44
+ var import_chat = require("@agentskit/chat");
45
+ var import_zod = require("zod");
46
+ var CHAT_RENDERERS = ["react", "react-native", "ink", "vue", "svelte", "solid", "angular"];
47
+ var ChatRendererSchema = import_zod.z.enum(CHAT_RENDERERS);
48
+ var ChatCliError = class extends Error {
49
+ constructor(code, message) {
50
+ super(message);
51
+ this.code = code;
52
+ this.name = "ChatCliError";
53
+ }
54
+ code;
55
+ };
56
+ var packageJson = (renderer) => JSON.stringify({
57
+ name: "agentskit-chat-app",
58
+ private: true,
59
+ version: "0.0.0",
60
+ type: "module",
61
+ ...renderer === "react-native" ? { main: "expo/AppEntry.js" } : {},
62
+ scripts: { typecheck: renderer === "svelte" ? "svelte-check --tsconfig ./tsconfig.json" : "tsc --noEmit", test: "vitest run", ...["react", "vue", "svelte", "solid", "angular"].includes(renderer) ? { dev: "vite", build: "vite build" } : renderer === "react-native" ? { dev: "expo start", build: "expo export --platform web" } : { dev: "tsx src/index.tsx" } },
63
+ dependencies: {
64
+ "@agentskit/chat": "latest",
65
+ "@agentskit/chat-protocol": "latest",
66
+ "@agentskit/chat-server": "latest",
67
+ "@agentskit/core": "^1.12.2",
68
+ zod: "^4.3.6",
69
+ ...renderer === "react" ? { "@agentskit/chat-react": "latest", "@agentskit/react": "^0.7.1", react: "^19.0.0", "react-dom": "^19.0.0" } : renderer === "react-native" ? { "@agentskit/chat-react-native": "latest", "@agentskit/react-native": "^0.4.4", expo: "^57.0.4", react: "19.2.3", "react-dom": "19.2.3", "react-native": "^0.86.0", "react-native-web": "^0.21.2" } : renderer === "ink" ? { "@agentskit/chat-ink": "latest", "@agentskit/ink": "^0.10.1", ink: "^7.0.0", react: "^19.0.0" } : renderer === "vue" ? { "@agentskit/chat-vue": "latest", "@agentskit/vue": "^0.4.4", vue: "^3.5.0" } : renderer === "svelte" ? { "@agentskit/chat-svelte": "latest", "@agentskit/svelte": "^0.4.4", svelte: "^5.0.0" } : renderer === "solid" ? { "@agentskit/chat-solid": "latest", "@agentskit/solid": "^0.4.4", "solid-js": "^1.9.0" } : { "@agentskit/chat-angular": "latest", "@agentskit/angular": "^0.4.6", "@angular/common": "^21.0.0", "@angular/compiler": "^21.0.0", "@angular/core": "^21.0.0", "@angular/platform-browser": "^21.0.0", rxjs: "^7.8.0", tslib: "^2.8.0", "zone.js": "^0.16.0" }
70
+ },
71
+ devDependencies: { "@types/node": "^25.0.0", tsx: "^4.20.0", typescript: renderer === "angular" ? "^5.9.0" : "^6.0.0", vitest: "^4.0.0", ...["react", "react-native", "ink"].includes(renderer) ? { "@types/react": "^19.0.0" } : {}, ...renderer === "react" ? { "@types/react-dom": "^19.0.0", "@vitejs/plugin-react": "^5.0.0", vite: "^8.0.0" } : renderer === "vue" ? { "@vitejs/plugin-vue": "^6.0.0", vite: "^8.0.0" } : renderer === "svelte" ? { "@sveltejs/vite-plugin-svelte": "^7.0.0", "svelte-check": "^4.0.0", vite: "^8.0.0" } : renderer === "solid" ? { "vite-plugin-solid": "^2.11.0", vite: "^8.0.0" } : renderer === "angular" ? { vite: "^8.0.0" } : {} }
72
+ }, null, 2) + "\n";
73
+ var sharedFiles = () => ({
74
+ "src/chat.ts": `import type { AdapterFactory } from '@agentskit/core'
75
+ import { defineChat } from '@agentskit/chat'
76
+
77
+ const demoAdapter: AdapterFactory = {
78
+ createSource: request => ({
79
+ async *stream() {
80
+ const input = request.messages.filter(message => message.role === 'user').at(-1)?.content ?? ''
81
+ yield { type: 'text', content: \`Echo: \${input}\` }
82
+ yield { type: 'done' }
83
+ },
84
+ abort() {},
85
+ }),
86
+ }
87
+
88
+ export const chat = defineChat({ id: 'starter', chat: { adapter: demoAdapter } })
89
+ `,
90
+ "src/server.ts": `import type { SessionSnapshot } from '@agentskit/chat-protocol'
91
+ import type { SessionStorage } from '@agentskit/chat'
92
+ import { createChatHandler } from '@agentskit/chat-server'
93
+ import { chat } from './chat.js'
94
+
95
+ let snapshot: SessionSnapshot | undefined
96
+ const storage: SessionStorage = {
97
+ load: () => snapshot,
98
+ save: (next, expected) => {
99
+ if (snapshot?.cursor !== expected) return false
100
+ snapshot = structuredClone(next)
101
+ return true
102
+ },
103
+ }
104
+
105
+ export const handleChat = createChatHandler({ resolveDefinition: () => chat, sessionStorage: () => storage })
106
+ `,
107
+ "tests/chat.test.ts": `import { describe, expect, it } from 'vitest'
108
+ import { chat } from '../src/chat.js'
109
+ import { handleChat } from '../src/server.js'
110
+
111
+ describe('generated chat', () => {
112
+ it('exports one runnable shared definition', () => expect(chat.id).toBe('starter'))
113
+ it('serves one complete turn through the Web handler', async () => {
114
+ const event = { protocol: 'agentskit.chat.turn', version: 1, eventId: 'submit', sessionId: 'session', turnId: 'turn', sequence: 0, emittedAt: new Date(0).toISOString(), event: 'client.turn.submit', payload: { input: 'hello' } }
115
+ const response = await handleChat(new Request('http://localhost/chat', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(event) }))
116
+ expect(response.status).toBe(200)
117
+ expect(await response.text()).toContain('Echo: hello')
118
+ })
119
+ })
120
+ `,
121
+ "README.md": `# AgentsKit Chat starter
122
+
123
+ The shared definition lives in \`src/chat.ts\`, the Web-standard server seam in \`src/server.ts\`, and the native renderer entry under \`src\`.
124
+
125
+ Run \`pnpm typecheck && pnpm test\`, then \`pnpm dev\`. Replace the demo adapter in the shared definition with any published AgentsKit adapter.
126
+ `,
127
+ ".gitignore": "node_modules\ndist\n.expo\n.env\n",
128
+ "vitest.config.ts": `import { defineConfig } from 'vitest/config'
129
+ export default defineConfig({ test: { environment: 'node' } })
130
+ `
131
+ });
132
+ var rendererFiles = (renderer) => renderer === "react" ? {
133
+ "index.html": '<!doctype html><html><body><div id="root"></div><script type="module" src="/src/main.tsx"></script></body></html>\n',
134
+ "src/main.tsx": `import '@agentskit/react/theme'
135
+ import { StrictMode } from 'react'
136
+ import { createRoot } from 'react-dom/client'
137
+ import { AgentChat } from '@agentskit/chat-react'
138
+ import { chat } from './chat.js'
139
+
140
+ createRoot(document.getElementById('root')!).render(<StrictMode><AgentChat definition={chat} /></StrictMode>)
141
+ `,
142
+ "src/vite-env.d.ts": `/// <reference types="vite/client" />
143
+ declare module '@agentskit/react/theme'
144
+ `,
145
+ "vite.config.ts": `import react from '@vitejs/plugin-react'
146
+ import { defineConfig } from 'vite'
147
+ export default defineConfig({ plugins: [react()] })
148
+ `
149
+ } : renderer === "react-native" ? {
150
+ "App.tsx": `import { AgentChatNative } from '@agentskit/chat-react-native'
151
+ import { chat } from './src/chat'
152
+ export default function App() { return <AgentChatNative definition={chat} /> }
153
+ `,
154
+ "app.json": JSON.stringify({ expo: { name: "AgentsKit Chat", slug: "agentskit-chat" } }, null, 2) + "\n"
155
+ } : renderer === "ink" ? {
156
+ "src/index.tsx": `import { AgentChat } from '@agentskit/chat-ink'
157
+ import { render } from 'ink'
158
+ import { chat } from './chat.js'
159
+ const app = render(<AgentChat definition={chat} />)
160
+ if (process.env.CI) setTimeout(() => app.unmount(), 0)
161
+ `
162
+ } : renderer === "vue" ? {
163
+ "index.html": '<!doctype html><html><body><div id="app"></div><script type="module" src="/src/main.ts"></script></body></html>\n',
164
+ "src/main.ts": `import { createApp, h } from 'vue'
165
+ import { AgentChat } from '@agentskit/chat-vue'
166
+ import { chat } from './chat.js'
167
+ createApp({ render: () => h(AgentChat, { definition: chat }) }).mount('#app')
168
+ `,
169
+ "vite.config.ts": `import vue from '@vitejs/plugin-vue'
170
+ import { defineConfig } from 'vite'
171
+ export default defineConfig({ plugins: [vue()] })
172
+ `
173
+ } : renderer === "svelte" ? {
174
+ "index.html": '<!doctype html><html><body><div id="app"></div><script type="module" src="/src/main.ts"></script></body></html>\n',
175
+ "src/App.svelte": `<script lang="ts">
176
+ import { AgentChat } from '@agentskit/chat-svelte'
177
+ import { chat } from './chat.js'
178
+ </script>
179
+ <AgentChat definition={chat} />
180
+ `,
181
+ "src/main.ts": `import { mount } from 'svelte'
182
+ import App from './App.svelte'
183
+ mount(App, { target: document.getElementById('app')! })
184
+ `,
185
+ "src/vite-env.d.ts": `/// <reference types="svelte" />
186
+ `,
187
+ "vite.config.ts": `import { svelte } from '@sveltejs/vite-plugin-svelte'
188
+ import { defineConfig } from 'vite'
189
+ export default defineConfig({ plugins: [svelte()] })
190
+ `
191
+ } : renderer === "solid" ? {
192
+ "index.html": '<!doctype html><html><body><div id="app"></div><script type="module" src="/src/main.tsx"></script></body></html>\n',
193
+ "src/main.tsx": `import { render } from 'solid-js/web'
194
+ import { AgentChat } from '@agentskit/chat-solid'
195
+ import { chat } from './chat.js'
196
+ render(() => <AgentChat definition={chat} />, document.getElementById('app')!)
197
+ `,
198
+ "vite.config.ts": `import { defineConfig } from 'vite'
199
+ import solid from 'vite-plugin-solid'
200
+ export default defineConfig({ plugins: [solid()] })
201
+ `
202
+ } : {
203
+ "index.html": '<!doctype html><html><body><app-root></app-root><script type="module" src="/src/main.ts"></script></body></html>\n',
204
+ "src/main.ts": `import 'zone.js'
205
+ import '@angular/compiler'
206
+ import { Component } from '@angular/core'
207
+ import { bootstrapApplication } from '@angular/platform-browser'
208
+ import { AgentChatComponent } from '@agentskit/chat-angular'
209
+ import { chat } from './chat.js'
210
+ @Component({ selector: 'app-root', standalone: true, imports: [AgentChatComponent], template: '<ak-agent-chat [definition]="chat" />' })
211
+ class AppComponent { readonly chat = chat }
212
+ void bootstrapApplication(AppComponent)
213
+ `
214
+ };
215
+ var tsconfig = (renderer) => JSON.stringify({ compilerOptions: {
216
+ target: "ES2022",
217
+ module: "ESNext",
218
+ moduleResolution: "bundler",
219
+ jsx: "react-jsx",
220
+ strict: true,
221
+ noEmit: true,
222
+ skipLibCheck: true,
223
+ ...renderer === "solid" ? { jsx: "preserve", jsxImportSource: "solid-js" } : {},
224
+ ...["react", "vue", "svelte", "solid", "angular"].includes(renderer) ? { lib: ["ES2022", "DOM"] } : {},
225
+ ...renderer === "ink" ? { types: ["node"] } : {}
226
+ }, include: renderer === "react-native" ? ["App.tsx", "src", "tests"] : ["src", "tests"] }, null, 2) + "\n";
227
+ var detectRenderer = async (targetDir) => {
228
+ try {
229
+ const input = JSON.parse(await (0, import_promises.readFile)(import_node_path.default.join(targetDir, "package.json"), "utf8"));
230
+ const manifest = import_zod.z.object({ dependencies: import_zod.z.record(import_zod.z.string(), import_zod.z.string()).optional(), devDependencies: import_zod.z.record(import_zod.z.string(), import_zod.z.string()).optional() }).passthrough().parse(input);
231
+ const dependencies = { ...manifest.dependencies, ...manifest.devDependencies };
232
+ if (dependencies.expo || dependencies["react-native"]) return "react-native";
233
+ if (dependencies.ink) return "ink";
234
+ if (dependencies["@angular/core"]) return "angular";
235
+ if (dependencies.svelte) return "svelte";
236
+ if (dependencies.vue) return "vue";
237
+ if (dependencies["solid-js"]) return "solid";
238
+ return dependencies.react ? "react" : void 0;
239
+ } catch (error) {
240
+ if (error.code === "ENOENT") return void 0;
241
+ throw new ChatCliError("MANIFEST_INVALID", "Could not read a valid package.json for renderer detection.");
242
+ }
243
+ };
244
+ var initChatProject = async (options) => {
245
+ const targetDir = import_node_path.default.resolve(options.targetDir);
246
+ const candidate = options.renderer ?? await detectRenderer(options.detectFromDir ?? targetDir);
247
+ if (!candidate) throw new ChatCliError("RENDERER_REQUIRED", `Choose a renderer with --renderer ${CHAT_RENDERERS.join(", ")}.`);
248
+ const renderer = ChatRendererSchema.parse(candidate);
249
+ const files = { ...sharedFiles(), ...rendererFiles(renderer), "package.json": packageJson(renderer), "tsconfig.json": tsconfig(renderer) };
250
+ const parent = import_node_path.default.dirname(targetDir);
251
+ await (0, import_promises.mkdir)(parent, { recursive: true });
252
+ const staging = await (0, import_promises.mkdtemp)(import_node_path.default.join(parent, `.${import_node_path.default.basename(targetDir)}-`));
253
+ try {
254
+ const writes = await Promise.allSettled(Object.entries(files).map(async ([relative, content]) => {
255
+ const destination = import_node_path.default.join(staging, relative);
256
+ await (0, import_promises.mkdir)(import_node_path.default.dirname(destination), { recursive: true });
257
+ await (0, import_promises.writeFile)(destination, content, { encoding: "utf8", flag: "wx" });
258
+ }));
259
+ const failure = writes.find((result) => result.status === "rejected");
260
+ if (failure?.status === "rejected") throw failure.reason;
261
+ await (0, import_promises.rename)(staging, targetDir);
262
+ } catch (error) {
263
+ await (0, import_promises.rm)(staging, { recursive: true, force: true });
264
+ const code = error.code;
265
+ if (code === "EEXIST" || code === "ENOTEMPTY" || code === "EISDIR" || code === "ENOTDIR") throw new ChatCliError("TARGET_EXISTS", `Refusing to overwrite existing path: ${targetDir}`);
266
+ throw error;
267
+ }
268
+ return Object.keys(files).sort();
269
+ };
270
+ var componentName = (input) => {
271
+ const kebab = input.trim().replace(/([a-z0-9])([A-Z])/g, "$1-$2").replace(/[^A-Za-z0-9]+/g, "-").replace(/^-|-$/g, "").toLowerCase();
272
+ if (!/^[a-z][a-z0-9-]{0,63}$/.test(kebab)) throw new ChatCliError("COMPONENT_INVALID", "Component name must start with a letter and contain only letters, numbers, or dashes.");
273
+ if (import_chat.STANDARD_COMPONENT_KEYS.includes(kebab)) throw new ChatCliError("COMPONENT_INVALID", "Component name is reserved by the standard catalog.");
274
+ return { kebab, pascal: kebab.split("-").map((part) => part[0].toUpperCase() + part.slice(1)).join("") };
275
+ };
276
+ var componentFiles = (name, renderers) => {
277
+ const { kebab, pascal } = componentName(name);
278
+ const shared = `import { z } from 'zod'
279
+ import type { ComponentDefinition } from '@agentskit/chat'
280
+
281
+ export const ${pascal}PropsSchema = z.object({ label: z.string().min(1).max(256) }).strict().readonly()
282
+ export type ${pascal}Props = z.infer<typeof ${pascal}PropsSchema>
283
+ export const ${pascal}Component = { key: '${kebab}', propsSchema: ${pascal}PropsSchema, events: [], accessibility: { role: 'group', keyboard: false, live: 'none' }, capabilities: ['display'], fallback: props => props.label } satisfies ComponentDefinition<${pascal}Props>
284
+ `;
285
+ const files = { [`src/components/${kebab}.ts`]: shared };
286
+ for (const renderer of [...new Set(renderers)]) {
287
+ const relative = `src/components/${renderer}/${kebab}.${renderer === "svelte" ? "svelte" : renderer === "vue" || renderer === "angular" ? "ts" : "tsx"}`;
288
+ files[relative] = renderer === "svelte" ? `<script lang="ts">
289
+ import { StandardComponent } from '@agentskit/chat-svelte'
290
+ import type { ComponentManifest } from '@agentskit/chat'
291
+ import type { ComponentInteractionEvent, ComponentRenderFrame } from '@agentskit/chat-protocol'
292
+ import { ${pascal}PropsSchema } from '../${kebab}.js'
293
+ let { frame, manifest, onInteract, disabled = false }: { frame: ComponentRenderFrame; manifest: ComponentManifest; onInteract: (event: ComponentInteractionEvent) => void; disabled?: boolean } = $props()
294
+ const value = $derived(frame.componentKey === '${kebab}' ? ${pascal}PropsSchema.parse(frame.props) : undefined)
295
+ </script>
296
+ {#if value}<section aria-label={value.label}>{value.label}</section>{:else}<StandardComponent {frame} {manifest} {onInteract} {disabled} />{/if}
297
+ ` : renderer === "vue" ? `import { h, type VNode } from 'vue'
298
+ import { StandardComponent, type StandardComponentProps } from '@agentskit/chat-vue'
299
+ import { ${pascal}PropsSchema } from '../${kebab}.js'
300
+ export const ${pascal} = (slot: StandardComponentProps): VNode[] => { if (slot.frame.componentKey !== '${kebab}') return [h(StandardComponent, slot)]; const props = ${pascal}PropsSchema.parse(slot.frame.props); return [h('section', { 'aria-label': props.label }, props.label)] }
301
+ ` : renderer === "angular" ? `import { Component, Input } from '@angular/core'
302
+ import { StandardComponentComponent } from '@agentskit/chat-angular'
303
+ import type { ComponentManifest } from '@agentskit/chat'
304
+ import type { ComponentInteractionEvent, ComponentRenderFrame } from '@agentskit/chat-protocol'
305
+ import { ${pascal}PropsSchema } from '../${kebab}.js'
306
+ @Component({ selector: 'ak-${kebab}', standalone: true, imports: [StandardComponentComponent], template: '@if (value; as item) { <section [attr.aria-label]="item.label">{{ item.label }}</section> } @else { <ak-standard-component [frame]="frame" [manifest]="manifest" [onInteract]="onInteract" [disabled]="disabled" /> }' })
307
+ export class ${pascal}Component { @Input({ required: true }) frame!: ComponentRenderFrame; @Input({ required: true }) manifest!: ComponentManifest; @Input({ required: true }) onInteract!: (event: ComponentInteractionEvent) => void; @Input() disabled = false; get value() { return this.frame.componentKey === '${kebab}' ? ${pascal}PropsSchema.parse(this.frame.props) : undefined } }
308
+ ` : renderer === "solid" ? `import { StandardComponent, type StandardComponentProps } from '@agentskit/chat-solid'
309
+ import { ${pascal}PropsSchema } from '../${kebab}.js'
310
+ export const ${pascal} = (slot: StandardComponentProps) => { if (slot.frame.componentKey !== '${kebab}') return <StandardComponent {...slot} />; const props = ${pascal}PropsSchema.parse(slot.frame.props); return <section aria-label={props.label}>{props.label}</section> }
311
+ ` : `import { ${renderer === "react-native" ? "StandardComponentNative as DefaultStandardComponent, type StandardComponentNativeProps" : "StandardComponent as DefaultStandardComponent, type StandardComponentProps"} } from '@agentskit/chat-${renderer}'
312
+ import { ${pascal}PropsSchema } from '../${kebab}.js'
313
+ ${renderer === "react-native" ? "import { Text } from 'react-native'\n" : renderer === "ink" ? "import { Text } from 'ink'\n" : ""}export const ${pascal} = (slot: ${renderer === "react-native" ? "StandardComponentNativeProps" : "StandardComponentProps"}) => { if (slot.frame.componentKey !== '${kebab}') return <DefaultStandardComponent {...slot} />; const props = ${pascal}PropsSchema.parse(slot.frame.props); return <${renderer === "react-native" || renderer === "ink" ? "Text" : "section"}${renderer === "react-native" ? " accessibilityLabel={props.label}" : renderer === "ink" ? "" : " aria-label={props.label}"}>{props.label}</${renderer === "react-native" || renderer === "ink" ? "Text" : "section"}> }
314
+ `;
315
+ }
316
+ return files;
317
+ };
318
+ var addChatComponent = async (options) => {
319
+ const projectDir = await (0, import_promises.realpath)(import_node_path.default.resolve(options.projectDir)).catch(() => {
320
+ throw new ChatCliError("MANIFEST_INVALID", "Component generation requires an existing project directory.");
321
+ });
322
+ const renderers = import_zod.z.array(ChatRendererSchema).min(1).parse(options.renderers);
323
+ const files = componentFiles(options.name, renderers);
324
+ const destinations = Object.keys(files).map((relative) => import_node_path.default.join(projectDir, relative));
325
+ for (const destination of destinations) {
326
+ let current = import_node_path.default.dirname(destination);
327
+ while (current !== projectDir) {
328
+ const status = await (0, import_promises.lstat)(current).catch((error) => error.code === "ENOENT" ? void 0 : Promise.reject(error));
329
+ if (status?.isSymbolicLink()) throw new ChatCliError("MANIFEST_INVALID", "Refusing to write through a symbolic-link component directory.");
330
+ current = import_node_path.default.dirname(current);
331
+ }
332
+ }
333
+ const checks = await Promise.all(destinations.map((destination) => (0, import_promises.readFile)(destination).then(() => true, (error) => error.code === "ENOENT" ? false : Promise.reject(error))));
334
+ if (checks.some(Boolean)) throw new ChatCliError("COMPONENT_EXISTS", "Refusing to overwrite an existing component file.");
335
+ const created = [];
336
+ try {
337
+ for (const [relative, content] of Object.entries(files)) {
338
+ const destination = import_node_path.default.join(projectDir, relative);
339
+ await (0, import_promises.mkdir)(import_node_path.default.dirname(destination), { recursive: true });
340
+ await (0, import_promises.writeFile)(destination, content, { encoding: "utf8", flag: "wx" });
341
+ created.push(destination);
342
+ }
343
+ } catch (error) {
344
+ await Promise.all(created.map((destination) => (0, import_promises.rm)(destination, { force: true })));
345
+ if (error.code === "EEXIST") throw new ChatCliError("COMPONENT_EXISTS", "Refusing to overwrite an existing component file.");
346
+ throw error;
347
+ }
348
+ return Object.keys(files).sort();
349
+ };
350
+ // Annotate the CommonJS export names for ESM import in node:
351
+ 0 && (module.exports = {
352
+ CHAT_RENDERERS,
353
+ ChatCliError,
354
+ ChatRendererSchema,
355
+ addChatComponent,
356
+ detectRenderer,
357
+ initChatProject
358
+ });
@@ -0,0 +1,32 @@
1
+ import { z } from 'zod';
2
+
3
+ declare const CHAT_RENDERERS: readonly ["react", "react-native", "ink", "vue", "svelte", "solid", "angular"];
4
+ declare const ChatRendererSchema: z.ZodEnum<{
5
+ react: "react";
6
+ "react-native": "react-native";
7
+ ink: "ink";
8
+ vue: "vue";
9
+ svelte: "svelte";
10
+ solid: "solid";
11
+ angular: "angular";
12
+ }>;
13
+ type ChatRenderer = z.infer<typeof ChatRendererSchema>;
14
+ interface InitChatProjectOptions {
15
+ readonly targetDir: string;
16
+ readonly renderer?: ChatRenderer;
17
+ readonly detectFromDir?: string;
18
+ }
19
+ interface AddComponentOptions {
20
+ readonly projectDir: string;
21
+ readonly name: string;
22
+ readonly renderers: readonly ChatRenderer[];
23
+ }
24
+ declare class ChatCliError extends Error {
25
+ readonly code: 'RENDERER_REQUIRED' | 'TARGET_EXISTS' | 'MANIFEST_INVALID' | 'COMPONENT_INVALID' | 'COMPONENT_EXISTS';
26
+ constructor(code: 'RENDERER_REQUIRED' | 'TARGET_EXISTS' | 'MANIFEST_INVALID' | 'COMPONENT_INVALID' | 'COMPONENT_EXISTS', message: string);
27
+ }
28
+ declare const detectRenderer: (targetDir: string) => Promise<ChatRenderer | undefined>;
29
+ declare const initChatProject: (options: InitChatProjectOptions) => Promise<readonly string[]>;
30
+ declare const addChatComponent: (options: AddComponentOptions) => Promise<readonly string[]>;
31
+
32
+ export { type AddComponentOptions, CHAT_RENDERERS, ChatCliError, type ChatRenderer, ChatRendererSchema, type InitChatProjectOptions, addChatComponent, detectRenderer, initChatProject };
@@ -0,0 +1,32 @@
1
+ import { z } from 'zod';
2
+
3
+ declare const CHAT_RENDERERS: readonly ["react", "react-native", "ink", "vue", "svelte", "solid", "angular"];
4
+ declare const ChatRendererSchema: z.ZodEnum<{
5
+ react: "react";
6
+ "react-native": "react-native";
7
+ ink: "ink";
8
+ vue: "vue";
9
+ svelte: "svelte";
10
+ solid: "solid";
11
+ angular: "angular";
12
+ }>;
13
+ type ChatRenderer = z.infer<typeof ChatRendererSchema>;
14
+ interface InitChatProjectOptions {
15
+ readonly targetDir: string;
16
+ readonly renderer?: ChatRenderer;
17
+ readonly detectFromDir?: string;
18
+ }
19
+ interface AddComponentOptions {
20
+ readonly projectDir: string;
21
+ readonly name: string;
22
+ readonly renderers: readonly ChatRenderer[];
23
+ }
24
+ declare class ChatCliError extends Error {
25
+ readonly code: 'RENDERER_REQUIRED' | 'TARGET_EXISTS' | 'MANIFEST_INVALID' | 'COMPONENT_INVALID' | 'COMPONENT_EXISTS';
26
+ constructor(code: 'RENDERER_REQUIRED' | 'TARGET_EXISTS' | 'MANIFEST_INVALID' | 'COMPONENT_INVALID' | 'COMPONENT_EXISTS', message: string);
27
+ }
28
+ declare const detectRenderer: (targetDir: string) => Promise<ChatRenderer | undefined>;
29
+ declare const initChatProject: (options: InitChatProjectOptions) => Promise<readonly string[]>;
30
+ declare const addChatComponent: (options: AddComponentOptions) => Promise<readonly string[]>;
31
+
32
+ export { type AddComponentOptions, CHAT_RENDERERS, ChatCliError, type ChatRenderer, ChatRendererSchema, type InitChatProjectOptions, addChatComponent, detectRenderer, initChatProject };
package/dist/index.js ADDED
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ CHAT_RENDERERS,
4
+ ChatCliError,
5
+ ChatRendererSchema,
6
+ addChatComponent,
7
+ detectRenderer,
8
+ initChatProject
9
+ } from "./chunk-SWALGE4D.js";
10
+ export {
11
+ CHAT_RENDERERS,
12
+ ChatCliError,
13
+ ChatRendererSchema,
14
+ addChatComponent,
15
+ detectRenderer,
16
+ initChatProject
17
+ };
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "@agentskit/chat-cli",
3
+ "version": "0.1.0",
4
+ "description": "Safe scaffolding for AgentsKit Chat applications.",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/AgentsKit-io/agentskit-chat.git",
9
+ "directory": "packages/cli"
10
+ },
11
+ "homepage": "https://github.com/AgentsKit-io/agentskit-chat#readme",
12
+ "bugs": {
13
+ "url": "https://github.com/AgentsKit-io/agentskit-chat/issues"
14
+ },
15
+ "type": "module",
16
+ "bin": {
17
+ "agentskit-chat": "./dist/bin.js"
18
+ },
19
+ "main": "./dist/index.cjs",
20
+ "module": "./dist/index.js",
21
+ "types": "./dist/index.d.ts",
22
+ "exports": {
23
+ ".": {
24
+ "types": "./dist/index.d.ts",
25
+ "import": "./dist/index.js",
26
+ "require": "./dist/index.cjs"
27
+ }
28
+ },
29
+ "files": [
30
+ "dist"
31
+ ],
32
+ "dependencies": {
33
+ "zod": "^4.3.6",
34
+ "@agentskit/chat": "0.1.0"
35
+ },
36
+ "devDependencies": {
37
+ "@types/node": "^25.0.0",
38
+ "node-pty": "^1.1.0",
39
+ "tsup": "^8.5.1"
40
+ },
41
+ "publishConfig": {
42
+ "access": "public",
43
+ "provenance": true
44
+ },
45
+ "scripts": {
46
+ "build": "tsup",
47
+ "lint": "tsc --noEmit",
48
+ "test": "vitest run --coverage"
49
+ }
50
+ }