Skip to content

Commit 717c8d6

Browse files
authored
Add env vars, clean up ux, and set-up automated npm publishing (#2)
* Add env vars and clean up ux * Bump package and add gh action * Address comments
1 parent 0afaa25 commit 717c8d6

File tree

7 files changed

+100
-64
lines changed

7 files changed

+100
-64
lines changed

.github/workflows/publish.yml

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
name: Publish Package
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
8+
jobs:
9+
publish:
10+
runs-on: ubuntu-latest
11+
steps:
12+
- uses: actions/checkout@v4
13+
with:
14+
fetch-depth: 0 # Required for version bumping
15+
16+
- name: Setup Git
17+
run: |
18+
git config --global user.name 'GitHub Actions'
19+
git config --global user.email '[email protected]'
20+
21+
- name: Setup Node.js
22+
uses: actions/setup-node@v4
23+
with:
24+
node-version: '20'
25+
registry-url: 'https://registry.npmjs.org'
26+
27+
- name: Install dependencies
28+
run: bun install
29+
30+
- name: Run linting
31+
run: bun run lint
32+
33+
- name: Build
34+
run: bun run build
35+
36+
- name: Bump version and push
37+
run: |
38+
git remote set-url origin https://x-access-token:${GITHUB_TOKEN}@github.com/${GITHUB_REPOSITORY}.git
39+
npm version patch -m "chore: bump version to %s [skip ci]"
40+
git push origin HEAD:main --tags
41+
env:
42+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
43+
44+
- name: Publish to NPM
45+
run: npm publish
46+
env:
47+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,17 +41,17 @@ create-kernel-app [app-name] [options]
4141

4242
Create a TypeScript application with a sample app:
4343
```bash
44-
npx create-kernel-app my-app --language typescript --template sample-app
44+
npx @onkernel/create-kernel-app my-app --language typescript --template sample-app
4545
```
4646

4747
Create a Python application with a sample app:
4848
```bash
49-
npx create-kernel-app my-app --language python --template sample-app
49+
npx @onkernel/create-kernel-app my-app --language python --template sample-app
5050
```
5151

5252
Create a Python application with Browser Use template:
5353
```bash
54-
npx create-kernel-app my-app --language python --template browser-use
54+
npx @onkernel/create-kernel-app my-app --language python --template browser-use
5555
```
5656

5757
## Next Steps

index.ts

Lines changed: 44 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,9 @@ const TEMPLATES: Record<TemplateKey, TemplateInfo> = {
4545
};
4646

4747
const INVOKE_SAMPLES: Record<string, string> = {
48-
'ts-basic': 'kernel invoke ts-basic get-page-title --payload \'{"url": "https://www.google.com"}\'',
49-
'python-basic': 'kernel invoke python-basic get-page-title --payload \'{"url": "https://www.google.com"}\'',
50-
'python-bu': 'kernel invoke python-bu bu-task --payload \'{"task": "Compare the price of gpt-4o and DeepSeek-V3", "openai_api_key": "XXX"}\''
48+
'typescript-sample-app': 'kernel invoke ts-basic get-page-title --payload \'{"url": "https://www.google.com"}\'',
49+
'python-sample-app': 'kernel invoke python-basic get-page-title --payload \'{"url": "https://www.google.com"}\'',
50+
'python-browser-use': 'kernel invoke python-bu bu-task --payload \'{"task": "Compare the price of gpt-4o and DeepSeek-V3"}\''
5151
};
5252

5353
const CONFIG = {
@@ -227,52 +227,24 @@ async function setupDependencies(appPath: string, language: LanguageKey): Promis
227227
// Print success message with next steps
228228
function printNextSteps(appName: string, language: LanguageKey, template: TemplateKey): void {
229229
// Determine which sample command to show based on language and template
230-
let sampleCommand = '';
231-
if (language === LANGUAGE_TYPESCRIPT) {
232-
sampleCommand = INVOKE_SAMPLES['ts-basic'];
233-
} else if (language === LANGUAGE_PYTHON) {
234-
sampleCommand = template === TEMPLATE_SAMPLE_APP
235-
? INVOKE_SAMPLES['python-basic']
236-
: INVOKE_SAMPLES['python-bu'];
237-
}
230+
const deployCommand = language === LANGUAGE_TYPESCRIPT ? 'kernel deploy index.ts'
231+
: language === LANGUAGE_PYTHON && template === TEMPLATE_SAMPLE_APP ? 'kernel deploy main.py'
232+
: language === LANGUAGE_PYTHON && template === TEMPLATE_BROWSER_USE ? 'kernel deploy main.py --env OPENAI_API_KEY=XXX'
233+
: '';
238234

235+
239236
console.log(chalk.green(`
240237
🎉 Kernel app created successfully!
241238
242239
Next steps:
243240
cd ${appName}
244-
${language === LANGUAGE_PYTHON ? 'uv venv && source .venv/bin/activate && uv sync' : ''}
245241
export KERNEL_API_KEY=<YOUR_API_KEY>
246-
kernel deploy ${language === LANGUAGE_TYPESCRIPT ? 'index.ts' : 'main.py'}
247-
kernel invoke ${sampleCommand}
242+
${language === LANGUAGE_PYTHON ? 'uv venv && source .venv/bin/activate && uv sync' : ''}
243+
${deployCommand}
244+
${INVOKE_SAMPLES[`${language}-${template}`]}
248245
`));
249246
}
250247

251-
// Validate language and template combination only when both are explicitly provided
252-
function validateLanguageTemplateCombination(language: LanguageKey | null, template: TemplateKey | null): { isValid: boolean; errorMessage?: string } {
253-
// If either is not provided, consider it valid (will be prompted later)
254-
if (!language || !template) {
255-
return { isValid: true };
256-
}
257-
258-
if (!TEMPLATES[template as TemplateKey]) {
259-
return {
260-
isValid: false,
261-
errorMessage: `Invalid template '${template}'. Available templates: ${Object.keys(TEMPLATES).join(', ')}`
262-
};
263-
}
264-
265-
if (!isTemplateValidForLanguage(template, language)) {
266-
return {
267-
isValid: false,
268-
errorMessage: `Template '${template}' is not available for ${LANGUAGES[language].name}. ` +
269-
`This template is only available for: ${TEMPLATES[template as TemplateKey].languages.map(l => LANGUAGES[l].name).join(', ')}`
270-
};
271-
}
272-
273-
return { isValid: true };
274-
}
275-
276248
// Main program
277249
const program = new Command();
278250

@@ -285,22 +257,44 @@ program
285257
.option('-t, --template <template>', `Template type (${TEMPLATE_SAMPLE_APP}, ${TEMPLATE_BROWSER_USE})`)
286258
.action(async (appName: string, options: { language?: string; template?: string }) => {
287259
try {
288-
// Only validate if both language and template are provided
289-
if (options.language?.toLowerCase() && options.template?.toLowerCase()) {
290-
const normalizedLanguage = normalizeLanguage(options.language);
291-
const validation = validateLanguageTemplateCombination(normalizedLanguage, options.template as TemplateKey);
292-
293-
if (!validation.isValid) {
294-
console.error(chalk.red('Error:'), validation.errorMessage);
295-
console.log(chalk.yellow('\nPlease try again with a valid combination.'));
296-
process.exit(1);
260+
let normalizedLanguage: LanguageKey | null = null;
261+
let normalizedTemplate: TemplateKey | null = null;
262+
263+
// Try to normalize and validate language if provided
264+
if (options.language?.toLowerCase()) {
265+
normalizedLanguage = normalizeLanguage(options.language);
266+
if (!normalizedLanguage) {
267+
console.log(chalk.yellow(`\nInvalid language '${options.language}'. Please select a valid language.`));
268+
}
269+
}
270+
271+
// Try to normalize and validate template if provided
272+
if (options.template?.toLowerCase()) {
273+
normalizedTemplate = options.template as TemplateKey;
274+
if (!TEMPLATES[normalizedTemplate]) {
275+
console.log(chalk.yellow(`\nInvalid template '${options.template}'. Please select a valid template.`));
276+
normalizedTemplate = null;
277+
}
278+
}
279+
280+
// If both are provided, validate the combination
281+
if (normalizedLanguage && normalizedTemplate) {
282+
console.log(normalizedLanguage, normalizedTemplate);
283+
const isValid = isTemplateValidForLanguage(normalizedTemplate, normalizedLanguage);
284+
if (!isValid) {
285+
const errorMessage = `Template '${normalizedTemplate}' is not available for ${LANGUAGES[normalizedLanguage].name}. ` +
286+
`This template is only available for: ${TEMPLATES[normalizedTemplate as TemplateKey].languages.map(l => LANGUAGES[l].name).join(', ')}`
287+
console.log(chalk.yellow(`\n${errorMessage}`));
288+
// Reset both to force prompting
289+
normalizedLanguage = null;
290+
normalizedTemplate = null;
297291
}
298292
}
299293

300294
// Get user inputs (with prompts if needed)
301295
const finalAppName = await promptForAppName(appName);
302-
const language = await promptForLanguage(options.language);
303-
const template = await promptForTemplate(language, options.template);
296+
const language = await promptForLanguage(normalizedLanguage || undefined);
297+
const template = await promptForTemplate(language, normalizedTemplate || undefined);
304298

305299
const appPath = path.resolve(finalAppName);
306300

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@onkernel/create-kernel-app",
3-
"version": "0.1.3",
3+
"version": "0.1.5",
44
"description": "Create Kernel sample applications",
55
"main": "dist/index.js",
66
"type": "module",

templates/python/browser-use/README.md

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,4 @@
22

33
This is a simple Kernel application that implements the Browser Use SDK.
44

5-
To set up your Python environment, run:
6-
7-
```bash
8-
python -m venv venv && source venv/bin/activate && pip install -r requirements.txt
9-
```
10-
115
See the [docs](https://docs.onkernel.com/build/browser-frameworks) for information.

templates/python/browser-use/main.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@
1212
class TaskInput(TypedDict):
1313
task: str
1414
openai_api_key: str
15+
16+
# LLM API Keys are set in the environment during `kernel deploy <filename> --env OPENAI_API_KEY=XXX`
17+
# See https://docs.onkernel.com/launch/deploy#environment-variables
18+
llm = ChatOpenAI(model="gpt-4o")
1519

1620
@app.action("bu-task")
1721
async def bu_task(ctx: kernel.KernelContext, input_data: TaskInput):
@@ -25,9 +29,6 @@ async def bu_task(ctx: kernel.KernelContext, input_data: TaskInput):
2529
Returns:
2630
An object with final_result and errors properties
2731
"""
28-
os.environ["OPENAI_API_KEY"] = input_data["openai_api_key"]
29-
30-
llm = ChatOpenAI(model="gpt-4o")
3132

3233
kernel_browser = client.browsers.create(invocation_id=ctx.invocation_id)
3334
print("Kernel browser live view url: ", kernel_browser.browser_live_view_url)

templates/typescript/sample-app/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"typescript": "^5"
88
},
99
"dependencies": {
10-
"@onkernel/sdk": "0.1.0-alpha.11",
10+
"@onkernel/sdk": "0.1.0-alpha.12",
1111
"playwright": "^1.52.0"
1212
}
1313
}

0 commit comments

Comments
 (0)