kiro-kit 0.2.4 → 0.3.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.
Files changed (34) hide show
  1. package/README.md +35 -0
  2. package/dist/index.js +764 -112
  3. package/dist/index.js.map +1 -1
  4. package/dist/presets/backend/hooks/api-schema-validate.js +75 -0
  5. package/dist/presets/backend/hooks/endpoint-test-coverage.js +77 -0
  6. package/dist/presets/backend/hooks/migration-safety-check.js +68 -0
  7. package/dist/presets/backend/manifest.json +23 -0
  8. package/dist/presets/backend/powers.json +40 -0
  9. package/dist/presets/data-ai/hooks/data-drift-check.js +77 -0
  10. package/dist/presets/data-ai/hooks/experiment-log.js +87 -0
  11. package/dist/presets/data-ai/hooks/model-card-update.js +99 -0
  12. package/dist/presets/data-ai/manifest.json +23 -0
  13. package/dist/presets/data-ai/powers.json +34 -0
  14. package/dist/presets/devops/hooks/container-scan.js +73 -0
  15. package/dist/presets/devops/hooks/cost-estimation.js +69 -0
  16. package/dist/presets/devops/hooks/terraform-plan-review.js +67 -0
  17. package/dist/presets/devops/manifest.json +23 -0
  18. package/dist/presets/devops/powers.json +40 -0
  19. package/dist/presets/frontend/hooks/accessibility-check.js +76 -0
  20. package/dist/presets/frontend/hooks/bundle-size-guard.js +71 -0
  21. package/dist/presets/frontend/hooks/component-test-reminder.js +71 -0
  22. package/dist/presets/frontend/manifest.json +23 -0
  23. package/dist/presets/frontend/powers.json +34 -0
  24. package/dist/presets/fullstack/hooks/api-client-gen.js +69 -0
  25. package/dist/presets/fullstack/hooks/deployment-readiness.js +73 -0
  26. package/dist/presets/fullstack/hooks/type-sync-check.js +69 -0
  27. package/dist/presets/fullstack/manifest.json +23 -0
  28. package/dist/presets/fullstack/powers.json +46 -0
  29. package/dist/presets/mobile/hooks/asset-optimization.js +58 -0
  30. package/dist/presets/mobile/hooks/platform-parity-check.js +73 -0
  31. package/dist/presets/mobile/hooks/release-checklist.js +83 -0
  32. package/dist/presets/mobile/manifest.json +23 -0
  33. package/dist/presets/mobile/powers.json +34 -0
  34. package/package.json +1 -1
@@ -0,0 +1,69 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Verifies shared types in src/types/ are imported by both client and server code.
4
+ * Checks for orphan type definitions not used anywhere.
5
+ */
6
+
7
+ const fs = require('fs');
8
+ const path = require('path');
9
+
10
+ const TYPES_DIR = path.resolve(process.cwd(), 'src/types');
11
+ const SRC_DIR = path.resolve(process.cwd(), 'src');
12
+
13
+ if (!fs.existsSync(TYPES_DIR)) {
14
+ process.exit(0);
15
+ }
16
+
17
+ function getTypeFiles(dir) {
18
+ const results = [];
19
+ try {
20
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
21
+ for (const entry of entries) {
22
+ if (entry.isFile() && /\.(ts|tsx)$/.test(entry.name) && entry.name !== 'index.ts') {
23
+ results.push(entry.name);
24
+ }
25
+ }
26
+ } catch (e) { /* skip */ }
27
+ return results;
28
+ }
29
+
30
+ function searchImports(dir, typeFile, exclude) {
31
+ let found = false;
32
+ if (!fs.existsSync(dir)) return false;
33
+ try {
34
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
35
+ for (const entry of entries) {
36
+ if (found) break;
37
+ const full = path.join(dir, entry.name);
38
+ if (entry.isDirectory() && entry.name !== 'node_modules' && full !== exclude) {
39
+ found = searchImports(full, typeFile, exclude);
40
+ } else if (entry.isFile() && /\.(ts|tsx|js|jsx)$/.test(entry.name)) {
41
+ const content = fs.readFileSync(full, 'utf8');
42
+ const baseName = path.basename(typeFile, path.extname(typeFile));
43
+ if (content.includes(`/types/${baseName}`) || content.includes(`/types'`) || content.includes(`/types"`)) {
44
+ found = true;
45
+ }
46
+ }
47
+ }
48
+ } catch (e) { /* skip */ }
49
+ return found;
50
+ }
51
+
52
+ const typeFiles = getTypeFiles(TYPES_DIR);
53
+ const orphans = [];
54
+
55
+ for (const tf of typeFiles) {
56
+ const baseName = path.basename(tf, path.extname(tf));
57
+ const isUsed = searchImports(SRC_DIR, tf, TYPES_DIR);
58
+ if (!isUsed) {
59
+ orphans.push(tf);
60
+ }
61
+ }
62
+
63
+ if (orphans.length > 0) {
64
+ process.stdout.write(`[type-sync-check] ${orphans.length} type file(s) not imported anywhere:\n`);
65
+ orphans.forEach((o) => process.stdout.write(` - src/types/${o}\n`));
66
+ process.exit(1);
67
+ }
68
+
69
+ process.exit(0);
@@ -563,6 +563,29 @@
563
563
  "type": "hook",
564
564
  "executable": true
565
565
  },
566
+ {
567
+ "source": "hooks/type-sync-check.js",
568
+ "target": ".kiro/hooks/type-sync-check.js",
569
+ "type": "hook",
570
+ "executable": true
571
+ },
572
+ {
573
+ "source": "hooks/api-client-gen.js",
574
+ "target": ".kiro/hooks/api-client-gen.js",
575
+ "type": "hook",
576
+ "executable": true
577
+ },
578
+ {
579
+ "source": "hooks/deployment-readiness.js",
580
+ "target": ".kiro/hooks/deployment-readiness.js",
581
+ "type": "hook",
582
+ "executable": true
583
+ },
584
+ {
585
+ "source": "powers.json",
586
+ "target": ".kiro/powers.json",
587
+ "type": "powers"
588
+ },
566
589
  {
567
590
  "source": "metadata.json",
568
591
  "target": ".kiro/metadata.json",
@@ -0,0 +1,46 @@
1
+ {
2
+ "powers": [
3
+ {
4
+ "name": "Supabase",
5
+ "url": "https://kiro.dev/powers/supabase",
6
+ "description": "Backend-as-a-service with Postgres, auth, and real-time subscriptions",
7
+ "tier": "essential"
8
+ },
9
+ {
10
+ "name": "Figma",
11
+ "url": "https://kiro.dev/powers/figma",
12
+ "description": "Design-to-code integration with Figma files",
13
+ "tier": "recommended"
14
+ },
15
+ {
16
+ "name": "Netlify",
17
+ "url": "https://kiro.dev/powers/netlify",
18
+ "description": "Deploy React, Next.js, and modern web apps to global CDN",
19
+ "tier": "recommended"
20
+ },
21
+ {
22
+ "name": "Stripe",
23
+ "url": "https://kiro.dev/powers/stripe",
24
+ "description": "Payment processing, subscriptions, and billing integration",
25
+ "tier": "recommended"
26
+ },
27
+ {
28
+ "name": "Context7",
29
+ "url": "https://kiro.dev/powers/context7",
30
+ "description": "Up-to-date documentation lookup for libraries and frameworks",
31
+ "tier": "recommended"
32
+ },
33
+ {
34
+ "name": "Firebase",
35
+ "url": "https://kiro.dev/powers/firebase",
36
+ "description": "Full-stack application development with Google Cloud services",
37
+ "tier": "optional"
38
+ },
39
+ {
40
+ "name": "LaunchDarkly",
41
+ "url": "https://kiro.dev/powers/launch-darkly",
42
+ "description": "Feature flag management and progressive delivery",
43
+ "tier": "optional"
44
+ }
45
+ ]
46
+ }
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Scans assets/ directory for images over 500KB and suggests optimization.
4
+ */
5
+
6
+ const fs = require('fs');
7
+ const path = require('path');
8
+
9
+ const ASSET_DIRS = ['assets', 'src/assets', 'lib/assets', 'public/assets'];
10
+ const IMAGE_EXTENSIONS = ['.png', '.jpg', '.jpeg', '.gif', '.bmp', '.webp', '.tiff'];
11
+ const THRESHOLD_KB = 500;
12
+
13
+ const cwd = process.cwd();
14
+
15
+ function findLargeImages(dir) {
16
+ const results = [];
17
+ if (!fs.existsSync(dir)) return results;
18
+ try {
19
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
20
+ for (const entry of entries) {
21
+ const full = path.join(dir, entry.name);
22
+ if (entry.isDirectory()) {
23
+ results.push(...findLargeImages(full));
24
+ } else if (entry.isFile()) {
25
+ const ext = path.extname(entry.name).toLowerCase();
26
+ if (IMAGE_EXTENSIONS.includes(ext)) {
27
+ const stat = fs.statSync(full);
28
+ const sizeKB = Math.round(stat.size / 1024);
29
+ if (sizeKB > THRESHOLD_KB) {
30
+ results.push({ file: path.relative(cwd, full), sizeKB });
31
+ }
32
+ }
33
+ }
34
+ }
35
+ } catch (e) { /* skip */ }
36
+ return results;
37
+ }
38
+
39
+ let largeFiles = [];
40
+ for (const dir of ASSET_DIRS) {
41
+ largeFiles.push(...findLargeImages(path.resolve(cwd, dir)));
42
+ }
43
+
44
+ if (largeFiles.length === 0) {
45
+ process.exit(0);
46
+ }
47
+
48
+ largeFiles.sort((a, b) => b.sizeKB - a.sizeKB);
49
+
50
+ process.stdout.write(`[asset-optimization] ${largeFiles.length} image(s) over ${THRESHOLD_KB}KB:\n`);
51
+ largeFiles.slice(0, 10).forEach((f) => {
52
+ process.stdout.write(` - ${f.file} (${f.sizeKB}KB)\n`);
53
+ });
54
+ if (largeFiles.length > 10) {
55
+ process.stdout.write(` ... and ${largeFiles.length - 10} more\n`);
56
+ }
57
+ process.stdout.write(' Consider compressing or converting to WebP format.\n');
58
+ process.exit(1);
@@ -0,0 +1,73 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Checks that platform-specific files (*.ios.*, *.android.*) have matching
4
+ * counterparts for both platforms.
5
+ */
6
+
7
+ const fs = require('fs');
8
+ const path = require('path');
9
+
10
+ const SRC_DIRS = ['src', 'lib', 'app'];
11
+ const PLATFORM_REGEX = /\.(ios|android)\./;
12
+
13
+ const cwd = process.cwd();
14
+
15
+ function findPlatformFiles(dir) {
16
+ const results = [];
17
+ if (!fs.existsSync(dir)) return results;
18
+ try {
19
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
20
+ for (const entry of entries) {
21
+ const full = path.join(dir, entry.name);
22
+ if (entry.isDirectory() && entry.name !== 'node_modules' && entry.name !== '.dart_tool') {
23
+ results.push(...findPlatformFiles(full));
24
+ } else if (entry.isFile() && PLATFORM_REGEX.test(entry.name)) {
25
+ results.push(full);
26
+ }
27
+ }
28
+ } catch (e) { /* skip */ }
29
+ return results;
30
+ }
31
+
32
+ let platformFiles = [];
33
+ for (const dir of SRC_DIRS) {
34
+ platformFiles.push(...findPlatformFiles(path.resolve(cwd, dir)));
35
+ }
36
+
37
+ if (platformFiles.length === 0) {
38
+ process.exit(0);
39
+ }
40
+
41
+ const missing = [];
42
+ for (const file of platformFiles) {
43
+ const dir = path.dirname(file);
44
+ const name = path.basename(file);
45
+
46
+ let counterpart;
47
+ if (name.includes('.ios.')) {
48
+ counterpart = name.replace('.ios.', '.android.');
49
+ } else {
50
+ counterpart = name.replace('.android.', '.ios.');
51
+ }
52
+
53
+ const counterpartPath = path.join(dir, counterpart);
54
+ if (!fs.existsSync(counterpartPath)) {
55
+ missing.push({
56
+ file: path.relative(cwd, file),
57
+ expected: path.relative(cwd, counterpartPath),
58
+ });
59
+ }
60
+ }
61
+
62
+ if (missing.length > 0) {
63
+ process.stdout.write(`[platform-parity-check] ${missing.length} file(s) missing platform counterpart:\n`);
64
+ missing.slice(0, 10).forEach((m) => {
65
+ process.stdout.write(` - ${m.file} (missing: ${m.expected})\n`);
66
+ });
67
+ if (missing.length > 10) {
68
+ process.stdout.write(` ... and ${missing.length - 10} more\n`);
69
+ }
70
+ process.exit(1);
71
+ }
72
+
73
+ process.exit(0);
@@ -0,0 +1,83 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Verifies version bump in pubspec.yaml/package.json, changelog updated,
4
+ * and no debug flags before release.
5
+ */
6
+
7
+ const fs = require('fs');
8
+ const path = require('path');
9
+
10
+ const cwd = process.cwd();
11
+ const issues = [];
12
+
13
+ // Check version file exists and has been updated
14
+ const versionFiles = ['pubspec.yaml', 'package.json', 'app.json'];
15
+ let versionFile = null;
16
+ for (const vf of versionFiles) {
17
+ if (fs.existsSync(path.resolve(cwd, vf))) {
18
+ versionFile = vf;
19
+ break;
20
+ }
21
+ }
22
+
23
+ if (!versionFile) {
24
+ process.exit(0);
25
+ }
26
+
27
+ // Check changelog exists
28
+ const changelogFiles = ['CHANGELOG.md', 'changelog.md', 'CHANGES.md'];
29
+ const hasChangelog = changelogFiles.some((f) => fs.existsSync(path.resolve(cwd, f)));
30
+ if (!hasChangelog) {
31
+ issues.push('No CHANGELOG.md found. Document changes before release.');
32
+ }
33
+
34
+ // Check for debug flags in source code
35
+ const DEBUG_PATTERNS = [
36
+ /debugShowCheckedModeBanner:\s*true/,
37
+ /kDebugMode/,
38
+ /console\.log\(/,
39
+ /__DEV__/,
40
+ /debugPrint\(/,
41
+ ];
42
+
43
+ function scanForDebug(dir, depth) {
44
+ const results = [];
45
+ if (depth > 4 || !fs.existsSync(dir)) return results;
46
+ try {
47
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
48
+ for (const entry of entries) {
49
+ const full = path.join(dir, entry.name);
50
+ if (entry.isDirectory() && !['node_modules', '.dart_tool', 'build'].includes(entry.name)) {
51
+ results.push(...scanForDebug(full, depth + 1));
52
+ } else if (entry.isFile() && /\.(dart|ts|tsx|js|jsx)$/.test(entry.name)) {
53
+ const content = fs.readFileSync(full, 'utf8');
54
+ for (const pattern of DEBUG_PATTERNS) {
55
+ if (pattern.test(content)) {
56
+ results.push(path.relative(cwd, full));
57
+ break;
58
+ }
59
+ }
60
+ }
61
+ }
62
+ } catch (e) { /* skip */ }
63
+ return results;
64
+ }
65
+
66
+ const SRC_DIRS = ['lib', 'src', 'app'];
67
+ let debugFiles = [];
68
+ for (const dir of SRC_DIRS) {
69
+ debugFiles.push(...scanForDebug(path.resolve(cwd, dir), 0));
70
+ }
71
+
72
+ if (debugFiles.length > 0) {
73
+ issues.push(`${debugFiles.length} file(s) contain debug flags/statements`);
74
+ }
75
+
76
+ if (issues.length > 0) {
77
+ process.stdout.write('[release-checklist] Release blockers:\n');
78
+ issues.forEach((i) => process.stdout.write(` - ${i}\n`));
79
+ process.exit(1);
80
+ }
81
+
82
+ process.stdout.write('[release-checklist] All release checks passed.\n');
83
+ process.exit(0);
@@ -568,6 +568,29 @@
568
568
  "type": "hook",
569
569
  "executable": true
570
570
  },
571
+ {
572
+ "source": "hooks/platform-parity-check.js",
573
+ "target": ".kiro/hooks/platform-parity-check.js",
574
+ "type": "hook",
575
+ "executable": true
576
+ },
577
+ {
578
+ "source": "hooks/asset-optimization.js",
579
+ "target": ".kiro/hooks/asset-optimization.js",
580
+ "type": "hook",
581
+ "executable": true
582
+ },
583
+ {
584
+ "source": "hooks/release-checklist.js",
585
+ "target": ".kiro/hooks/release-checklist.js",
586
+ "type": "hook",
587
+ "executable": true
588
+ },
589
+ {
590
+ "source": "powers.json",
591
+ "target": ".kiro/powers.json",
592
+ "type": "powers"
593
+ },
571
594
  {
572
595
  "source": "metadata.json",
573
596
  "target": ".kiro/metadata.json",
@@ -0,0 +1,34 @@
1
+ {
2
+ "powers": [
3
+ {
4
+ "name": "Firebase",
5
+ "url": "https://kiro.dev/powers/firebase",
6
+ "description": "Full-stack mobile development with auth, database, and push notifications",
7
+ "tier": "essential"
8
+ },
9
+ {
10
+ "name": "Figma",
11
+ "url": "https://kiro.dev/powers/figma",
12
+ "description": "Design-to-code integration with Figma files",
13
+ "tier": "recommended"
14
+ },
15
+ {
16
+ "name": "Context7",
17
+ "url": "https://kiro.dev/powers/context7",
18
+ "description": "Up-to-date documentation lookup for libraries and frameworks",
19
+ "tier": "recommended"
20
+ },
21
+ {
22
+ "name": "ElevenLabs",
23
+ "url": "https://kiro.dev/powers/eleven-labs",
24
+ "description": "Text-to-speech and voice AI integration",
25
+ "tier": "optional"
26
+ },
27
+ {
28
+ "name": "Bria",
29
+ "url": "https://kiro.dev/powers/bria",
30
+ "description": "AI image generation and editing for app assets",
31
+ "tier": "optional"
32
+ }
33
+ ]
34
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kiro-kit",
3
- "version": "0.2.4",
3
+ "version": "0.3.0",
4
4
  "description": "CLI tool for bootstrapping engineer-grade Kiro IDE workspaces with curated presets.",
5
5
  "type": "module",
6
6
  "bin": {