@kernel.chat/kbot 3.1.0 → 3.1.1

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.
@@ -1 +1 @@
1
- {"version":3,"file":"gamedev.d.ts","sourceRoot":"","sources":["../../src/tools/gamedev.ts"],"names":[],"mappings":"AA2EA,wBAAgB,oBAAoB,IAAI,IAAI,CA+pV3C"}
1
+ {"version":3,"file":"gamedev.d.ts","sourceRoot":"","sources":["../../src/tools/gamedev.ts"],"names":[],"mappings":"AA2EA,wBAAgB,oBAAoB,IAAI,IAAI,CA0qV3C"}
@@ -77,6 +77,7 @@ function seededRng(seed) {
77
77
  }
78
78
  // ── Registration ─────────────────────────────────────────────────────
79
79
  export function registerGamedevTools() {
80
+ const htmlSafe = (s) => s.replace(/[&<>"']/g, c => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[c] ?? c));
80
81
  // ── Tool 1: scaffold_game ──────────────────────────────────────────
81
82
  /** Per-engine scaffold file generators. Each returns an array of [relativePath, content] */
82
83
  const scaffoldFiles = {
@@ -125,7 +126,7 @@ export function registerGamedevTools() {
125
126
  const is3d = tpl === '3d';
126
127
  return [
127
128
  ['package.json', JSON.stringify({ name: name.toLowerCase().replace(/[^a-z0-9-]/g, '-'), version: '0.1.0', private: true, scripts: { dev: 'vite', build: 'vite build' }, dependencies: { phaser: '^3.80.0' }, devDependencies: { vite: '^5.0.0', typescript: '^5.4.0' } }, null, 2)],
128
- ['index.html', `<!DOCTYPE html>\n<html><head><title>${name}</title></head>\n<body><script type="module" src="/src/main.ts"></script></body></html>\n`],
129
+ ['index.html', `<!DOCTYPE html>\n<html><head><title>${htmlSafe(name)}</title></head>\n<body><script type="module" src="/src/main.ts"></script></body></html>\n`],
129
130
  ['src/main.ts', `import Phaser from 'phaser'\nimport { MainScene } from './scenes/MainScene'\n\nnew Phaser.Game({\n type: Phaser.AUTO,\n width: 800,\n height: 600,\n physics: { default: 'arcade', arcade: { gravity: { x: 0, y: 300 }, debug: false } },\n scene: [MainScene],\n})\n`],
130
131
  ['src/scenes/MainScene.ts', `import Phaser from 'phaser'\n\nexport class MainScene extends Phaser.Scene {\n constructor() { super('MainScene') }\n preload() { }\n create() {\n this.add.text(400, 300, '${name}', { fontSize: '32px', color: '#fff' }).setOrigin(0.5)\n }\n}\n`],
131
132
  ['tsconfig.json', JSON.stringify({ compilerOptions: { target: 'ES2020', module: 'ESNext', moduleResolution: 'bundler', strict: true, esModuleInterop: true }, include: ['src'] }, null, 2)],
@@ -136,7 +137,7 @@ export function registerGamedevTools() {
136
137
  const is3d = true; // Three.js is always 3D
137
138
  return [
138
139
  ['package.json', JSON.stringify({ name: name.toLowerCase().replace(/[^a-z0-9-]/g, '-'), version: '0.1.0', private: true, scripts: { dev: 'vite', build: 'vite build' }, dependencies: { three: '^0.170.0' }, devDependencies: { '@types/three': '^0.170.0', vite: '^5.0.0', typescript: '^5.4.0' } }, null, 2)],
139
- ['index.html', `<!DOCTYPE html>\n<html><head><title>${name}</title><style>body{margin:0;overflow:hidden}canvas{display:block}</style></head>\n<body><script type="module" src="/src/main.ts"></script></body></html>\n`],
140
+ ['index.html', `<!DOCTYPE html>\n<html><head><title>${htmlSafe(name)}</title><style>body{margin:0;overflow:hidden}canvas{display:block}</style></head>\n<body><script type="module" src="/src/main.ts"></script></body></html>\n`],
140
141
  ['src/main.ts', `import * as THREE from 'three'\n\nconst scene = new THREE.Scene()\nconst camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000)\nconst renderer = new THREE.WebGLRenderer({ antialias: true })\nrenderer.setSize(window.innerWidth, window.innerHeight)\ndocument.body.appendChild(renderer.domElement)\n\nconst geometry = new THREE.BoxGeometry()\nconst material = new THREE.MeshStandardMaterial({ color: 0x4488ff })\nconst cube = new THREE.Mesh(geometry, material)\nscene.add(cube)\n\nscene.add(new THREE.AmbientLight(0x404040))\nconst light = new THREE.DirectionalLight(0xffffff, 1)\nlight.position.set(5, 5, 5)\nscene.add(light)\n\ncamera.position.z = 5\n\nfunction animate() {\n requestAnimationFrame(animate)\n cube.rotation.x += 0.01\n cube.rotation.y += 0.01\n renderer.render(scene, camera)\n}\nanimate()\n\nwindow.addEventListener('resize', () => {\n camera.aspect = window.innerWidth / window.innerHeight\n camera.updateProjectionMatrix()\n renderer.setSize(window.innerWidth, window.innerHeight)\n})\n`],
141
142
  ['tsconfig.json', JSON.stringify({ compilerOptions: { target: 'ES2020', module: 'ESNext', moduleResolution: 'bundler', strict: true, esModuleInterop: true }, include: ['src'] }, null, 2)],
142
143
  ['.gitignore', 'node_modules/\ndist/\n'],
@@ -145,7 +146,7 @@ export function registerGamedevTools() {
145
146
  playcanvas(name, tpl) {
146
147
  return [
147
148
  ['package.json', JSON.stringify({ name: name.toLowerCase().replace(/[^a-z0-9-]/g, '-'), version: '0.1.0', private: true, scripts: { dev: 'vite', build: 'vite build' }, dependencies: { playcanvas: '^2.1.0' }, devDependencies: { vite: '^5.0.0', typescript: '^5.4.0' } }, null, 2)],
148
- ['index.html', `<!DOCTYPE html>\n<html><head><title>${name}</title><style>body{margin:0;overflow:hidden}canvas{display:block}</style></head>\n<body><canvas id="app"></canvas><script type="module" src="/src/main.ts"></script></body></html>\n`],
149
+ ['index.html', `<!DOCTYPE html>\n<html><head><title>${htmlSafe(name)}</title><style>body{margin:0;overflow:hidden}canvas{display:block}</style></head>\n<body><canvas id="app"></canvas><script type="module" src="/src/main.ts"></script></body></html>\n`],
149
150
  ['src/main.ts', `import * as pc from 'playcanvas'\n\nconst canvas = document.getElementById('app') as HTMLCanvasElement\nconst app = new pc.Application(canvas, {})\napp.setCanvasFillMode(pc.FILLMODE_FILL_WINDOW)\napp.setCanvasResolution(pc.RESOLUTION_AUTO)\n\nconst camera = new pc.Entity('camera')\ncamera.addComponent('camera', { clearColor: new pc.Color(0.1, 0.1, 0.15) })\ncamera.setPosition(0, 2, 5)\ncamera.lookAt(pc.Vec3.ZERO)\napp.root.addChild(camera)\n\nconst light = new pc.Entity('light')\nlight.addComponent('light')\nlight.setEulerAngles(45, 30, 0)\napp.root.addChild(light)\n\nconst box = new pc.Entity('box')\nbox.addComponent('render', { type: 'box' })\napp.root.addChild(box)\n\napp.on('update', (dt: number) => { box.rotate(10 * dt, 20 * dt, 0) })\napp.start()\n`],
150
151
  ['tsconfig.json', JSON.stringify({ compilerOptions: { target: 'ES2020', module: 'ESNext', moduleResolution: 'bundler', strict: true, esModuleInterop: true }, include: ['src'] }, null, 2)],
151
152
  ['.gitignore', 'node_modules/\ndist/\n'],
@@ -974,8 +975,8 @@ void fragment() {
974
975
  },
975
976
  sphere(p) {
976
977
  const radius = p.radius ?? 0.5;
977
- const rings = p.rings ?? 16;
978
- const segments = p.segments ?? 32;
978
+ const rings = Math.min(p.rings ?? 16, 256);
979
+ const segments = Math.min(p.segments ?? 32, 512);
979
980
  const verts = [];
980
981
  const norms = [];
981
982
  const uvs = [];
@@ -1466,7 +1467,7 @@ void fragment() {
1466
1467
  const atlasW = nextPow2(atlasSize.width);
1467
1468
  const atlasH = nextPow2(atlasSize.height);
1468
1469
  // Composite atlas using ImageMagick
1469
- ensureDir(outputImage);
1470
+ ensureDir(dirname(outputImage));
1470
1471
  const compositeArgs = [
1471
1472
  '-size', `${atlasW}x${atlasH}`, 'xc:transparent',
1472
1473
  ];
@@ -1571,7 +1572,7 @@ void fragment() {
1571
1572
  };
1572
1573
  metadata = JSON.stringify(jsonData, null, 2);
1573
1574
  }
1574
- ensureDir(outputData);
1575
+ ensureDir(dirname(outputData));
1575
1576
  writeFileSync(outputData, metadata);
1576
1577
  return `Sprite atlas packed successfully:
1577
1578
  Atlas: ${outputImage} (${atlasW}x${atlasH})
@@ -1596,7 +1597,13 @@ void fragment() {
1596
1597
  async execute(args) {
1597
1598
  const type = String(args.type).toLowerCase();
1598
1599
  const engine = String(args.engine || 'rapier').toLowerCase();
1599
- const params = args.params ? JSON.parse(String(args.params)) : {};
1600
+ let params = {};
1601
+ try {
1602
+ params = args.params ? JSON.parse(String(args.params)) : {};
1603
+ }
1604
+ catch {
1605
+ return 'Error: params must be valid JSON';
1606
+ }
1600
1607
  const outputPath = String(args.output_path);
1601
1608
  const validTypes = ['rigidbody', 'softbody', 'ragdoll', 'vehicle', 'cloth', 'joints'];
1602
1609
  const validEngines = ['godot', 'unity', 'unreal', 'bevy', 'cannon', 'rapier', 'matter'];
@@ -2859,7 +2866,7 @@ const JOINT_CONFIG = ${JSON.stringify({
2859
2866
  fileExt = 'cpp';
2860
2867
  else if (fileExt === 'ts' && engine === 'bevy')
2861
2868
  fileExt = 'rs';
2862
- ensureDir(outputPath);
2869
+ ensureDir(dirname(outputPath));
2863
2870
  writeFileSync(outputPath, code);
2864
2871
  return `Physics setup generated:
2865
2872
  Type: ${type}
@@ -2883,7 +2890,13 @@ const JOINT_CONFIG = ${JSON.stringify({
2883
2890
  const effect = String(args.effect).toLowerCase();
2884
2891
  const engine = String(args.engine || 'three').toLowerCase();
2885
2892
  const outputPath = String(args.output_path);
2886
- const overrides = args.params ? JSON.parse(String(args.params)) : {};
2893
+ let overrides = {};
2894
+ try {
2895
+ overrides = args.params ? JSON.parse(String(args.params)) : {};
2896
+ }
2897
+ catch {
2898
+ return 'Error: params must be valid JSON';
2899
+ }
2887
2900
  const validEffects = ['fire', 'smoke', 'rain', 'snow', 'sparks', 'magic', 'explosion', 'dust', 'bubbles', 'leaves', 'confetti'];
2888
2901
  const validEngines = ['godot', 'unity', 'unreal', 'three', 'phaser', 'pixi'];
2889
2902
  if (!validEffects.includes(effect))
@@ -3561,7 +3574,7 @@ ${effect === 'fire' || effect === 'smoke' ? ` // Grow over lifetime
3561
3574
  }
3562
3575
  if (!code)
3563
3576
  return `Error: No implementation for effect="${effect}" with engine="${engine}"`;
3564
- ensureDir(outputPath);
3577
+ ensureDir(dirname(outputPath));
3565
3578
  writeFileSync(outputPath, code);
3566
3579
  return `Particle system generated:
3567
3580
  Effect: ${effect}
@@ -3588,12 +3601,18 @@ ${effect === 'fire' || effect === 'smoke' ? ` // Grow over lifetime
3588
3601
  tier: 'free',
3589
3602
  async execute(args) {
3590
3603
  const type = String(args.type).toLowerCase();
3591
- const width = typeof args.width === 'number' ? args.width : 40;
3592
- const height = typeof args.height === 'number' ? args.height : 30;
3604
+ const width = Math.min(typeof args.width === 'number' ? args.width : 40, 1000);
3605
+ const height = Math.min(typeof args.height === 'number' ? args.height : 30, 1000);
3593
3606
  const seedVal = typeof args.seed === 'number' ? args.seed : Date.now();
3594
3607
  const outputPath = String(args.output_path);
3595
3608
  const format = String(args.format || 'json');
3596
- const params = args.params ? JSON.parse(String(args.params)) : {};
3609
+ let params = {};
3610
+ try {
3611
+ params = args.params ? JSON.parse(String(args.params)) : {};
3612
+ }
3613
+ catch {
3614
+ return 'Error: params must be valid JSON';
3615
+ }
3597
3616
  const validTypes = ['dungeon', 'platformer', 'overworld', 'maze', 'arena'];
3598
3617
  if (!validTypes.includes(type))
3599
3618
  return `Error: Invalid type "${type}". Use: ${validTypes.join(', ')}`;
@@ -4114,7 +4133,7 @@ ${effect === 'fire' || effect === 'smoke' ? ` // Grow over lifetime
4114
4133
  };
4115
4134
  output = JSON.stringify(jsonData, null, 2);
4116
4135
  }
4117
- ensureDir(outputPath);
4136
+ ensureDir(dirname(outputPath));
4118
4137
  writeFileSync(outputPath, output);
4119
4138
  const floorCount = map.flat().filter(t => t === FLOOR || t === SPAWN || t === EXIT || t === DOOR).length;
4120
4139
  return `Level generated:
@@ -4155,7 +4174,12 @@ ${effect === 'fire' || effect === 'smoke' ? ` // Grow over lifetime
4155
4174
  // Parse or generate map data
4156
4175
  let mapData;
4157
4176
  if (args.map_data) {
4158
- mapData = JSON.parse(String(args.map_data));
4177
+ try {
4178
+ mapData = JSON.parse(String(args.map_data));
4179
+ }
4180
+ catch {
4181
+ return 'Error: map_data must be valid JSON';
4182
+ }
4159
4183
  }
4160
4184
  else {
4161
4185
  // Auto-generate a sample terrain map
@@ -4490,7 +4514,7 @@ tile_${i}/terrain_peering/left = ${cardW ? 0 : -1}`;
4490
4514
  };
4491
4515
  output = JSON.stringify(jsonOutput, null, 2);
4492
4516
  }
4493
- ensureDir(outputPath);
4517
+ ensureDir(dirname(outputPath));
4494
4518
  writeFileSync(outputPath, output);
4495
4519
  const terrainTileCount = tiledMap.flat().filter(t => t >= 0).length;
4496
4520
  return `Tilemap generated:
@@ -4517,7 +4541,13 @@ tile_${i}/terrain_peering/left = ${cardW ? 0 : -1}`;
4517
4541
  const engine = String(args.engine || 'recast').toLowerCase();
4518
4542
  const agentType = String(args.agent_type || 'humanoid').toLowerCase();
4519
4543
  const outputPath = String(args.output_path);
4520
- const overrides = args.params ? JSON.parse(String(args.params)) : {};
4544
+ let overrides = {};
4545
+ try {
4546
+ overrides = args.params ? JSON.parse(String(args.params)) : {};
4547
+ }
4548
+ catch {
4549
+ return 'Error: params must be valid JSON';
4550
+ }
4521
4551
  const validEngines = ['godot', 'unity', 'unreal', 'recast', 'three'];
4522
4552
  const validAgents = ['humanoid', 'vehicle', 'flying', 'small_creature'];
4523
4553
  if (!validEngines.includes(engine))
@@ -5449,7 +5479,7 @@ export class NavigationSystem {
5449
5479
  }
5450
5480
  if (!code)
5451
5481
  return `Error: No implementation for engine="${engine}"`;
5452
- ensureDir(outputPath);
5482
+ ensureDir(dirname(outputPath));
5453
5483
  writeFileSync(outputPath, code);
5454
5484
  return `Navigation mesh config generated:
5455
5485
  Engine: ${engine}
@@ -5620,7 +5650,13 @@ export class NavigationSystem {
5620
5650
  const system = String(args.system).toLowerCase();
5621
5651
  const engine = String(args.engine || 'web').toLowerCase();
5622
5652
  const outputPath = String(args.output_path);
5623
- const params = args.params ? JSON.parse(String(args.params)) : {};
5653
+ let params = {};
5654
+ try {
5655
+ params = args.params ? JSON.parse(String(args.params)) : {};
5656
+ }
5657
+ catch {
5658
+ return 'Error: params must be valid JSON';
5659
+ }
5624
5660
  const validSystems = ['spatial', 'music_layers', 'sound_bank', 'howler', 'web_audio'];
5625
5661
  if (!validSystems.includes(system)) {
5626
5662
  return `Error: Unknown audio system "${system}". Valid: ${validSystems.join(', ')}`;
@@ -7073,7 +7109,13 @@ export class AudioEngine {
7073
7109
  const transport = String(args.transport || 'websocket').toLowerCase();
7074
7110
  const framework = String(args.framework || 'raw').toLowerCase();
7075
7111
  const outputDir = String(args.output_dir);
7076
- const features = args.features ? JSON.parse(String(args.features)) : ['lobby', 'state_sync'];
7112
+ let features = ['lobby', 'state_sync'];
7113
+ try {
7114
+ features = args.features ? JSON.parse(String(args.features)) : ['lobby', 'state_sync'];
7115
+ }
7116
+ catch {
7117
+ return 'Error: features must be valid JSON';
7118
+ }
7077
7119
  const validArch = ['client_server', 'peer_to_peer', 'relay'];
7078
7120
  if (!validArch.includes(architecture)) {
7079
7121
  return `Error: Unknown architecture "${architecture}". Valid: ${validArch.join(', ')}`;
@@ -8981,7 +9023,13 @@ export default defineConfig({
8981
9023
  const testType = String(args.test_type).toLowerCase();
8982
9024
  const engine = String(args.engine || 'web').toLowerCase();
8983
9025
  const outputPath = String(args.output_path);
8984
- const params = args.params ? JSON.parse(String(args.params)) : {};
9026
+ let params = {};
9027
+ try {
9028
+ params = args.params ? JSON.parse(String(args.params)) : {};
9029
+ }
9030
+ catch {
9031
+ return 'Error: params must be valid JSON';
9032
+ }
8985
9033
  const validTypes = ['fps_profiler', 'memory_tracker', 'input_recorder', 'screenshot_test', 'performance_budget'];
8986
9034
  if (!validTypes.includes(testType)) {
8987
9035
  return `Error: Unknown test type "${testType}". Valid: ${validTypes.join(', ')}`;
@@ -10281,9 +10329,21 @@ export class PerformanceBudget {
10281
10329
  tier: 'free',
10282
10330
  async execute(args) {
10283
10331
  const framework = String(args.framework).toLowerCase();
10284
- const entities = JSON.parse(String(args.entities));
10332
+ let entities = [];
10333
+ try {
10334
+ entities = JSON.parse(String(args.entities));
10335
+ }
10336
+ catch {
10337
+ return 'Error: entities must be valid JSON';
10338
+ }
10285
10339
  const outputDir = String(args.output_dir);
10286
- const systems = args.systems ? JSON.parse(String(args.systems)) : [];
10340
+ let systems = [];
10341
+ try {
10342
+ systems = args.systems ? JSON.parse(String(args.systems)) : [];
10343
+ }
10344
+ catch {
10345
+ return 'Error: systems must be valid JSON';
10346
+ }
10287
10347
  const validFrameworks = ['bevy', 'unity_dots', 'bitecs', 'miniplex', 'ecsy'];
10288
10348
  if (!validFrameworks.includes(framework)) {
10289
10349
  return `Error: Unknown ECS framework "${framework}". Valid: ${validFrameworks.join(', ')}`;