Skip to content

overhaul campaign-init setup flow with a starter template picker#12

Merged
alexphelps merged 3 commits into
mainfrom
starter-templates-setup
Apr 30, 2026
Merged

overhaul campaign-init setup flow with a starter template picker#12
alexphelps merged 3 commits into
mainfrom
starter-templates-setup

Conversation

@alexphelps
Copy link
Copy Markdown
Member

Overhaul the campaign-init function to pull a list of starter templates and streamline setting up a new template from a starter template.

Comment thread lib/actions/init.js
fs.mkdirSync(parent, { recursive: true });
const tmpDir = fs.mkdtempSync(path.join(parent, '.cpk-extract-'));
try {
execSync('tar -xz', { input: tarball, cwd: tmpDir, stdio: ['pipe', 'ignore', 'pipe'] });
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: tar command flags behave differently on GNU tar vs BSD tar (macOS). The -z flag works on Linux but some BSD tars expect -xzf with stdin. Consider using a more portable approach or at minimum testing on macOS.

Additionally, if the tarball is malformed or empty, execSync will throw with an unclear error message. Consider adding explicit error handling around this call.

Comment thread lib/actions/init.js
})),
});
if (isCancel(slug)) { outro('Cancelled.'); return; }
const picked = templates.find(t => t.slug === slug);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CRITICAL: If templates.find() returns undefined (slug not found in manifest), picked will be undefined. Line 196-197 then accesses picked.name which will throw TypeError: Cannot read property 'name' of undefined.

This can happen if the templates.json manifest changes between fetch and user selection.

Comment thread lib/actions/init.js
// Apply an API key to a config.js source string. Returns the new string,
// or null if no `apiKey:` field was found.
function applyApiKey(configSource, apiKey) {
const updated = configSource.replace(/apiKey:\s*['"].*?['"]/, `apiKey: '${apiKey.trim()}'`);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: The regex /apiKey:\s*['"].*?['"]/ with non-greedy .*? only matches the shortest possible string between quotes. If apiKey values themselves could contain embedded quotes (unlikely for API keys but possible in testing), the replacement could be incorrect. The regex also assumes single-line values. Consider using a more robust approach if API keys might contain special characters.

Comment thread lib/actions/init.js

function fetchBuffer(url, redirects = 5) {
return new Promise((resolve, reject) => {
https.get(url, (res) => {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: No timeout is set on the HTTPS request. If the remote server is unreachable or hangs, fetchBuffer will hang indefinitely with no way to cancel. Consider adding an AbortSignal with a timeout:

https.get(url, { signal: AbortSignal.timeout(30000) }, (res) => { ... }

Comment thread lib/actions/init.js
const repoRoot = fs.readdirSync(tmpDir).find(d =>
fs.statSync(path.join(tmpDir, d)).isDirectory()
);
if (!repoRoot) throw new Error('tarball had no top-level directory');
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: If the tarball's top-level contains multiple directories (e.g., 'fixture-repo-main' and some other folder), fs.readdirSync(...).find() takes the first one alphabetically, which may not be the intended repo root. This could cause extraction to fail silently or extract the wrong directory.

Comment thread lib/actions/init.js

// Produce the next state of `_data/campaigns.json` after merging an upstream
// entry under `localSlug` and overriding the name with what the user provided.
function mergeCampaignEntry(localCampaigns, localSlug, upstreamEntry, name) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SUGGESTION: mergeCampaignEntry copies ALL properties from upstreamEntry. If the upstream campaigns.json contains internal-only fields (e.g., hidden: true, deprecated: true, or local paths), they would be merged into the local registry. Consider explicitly listing which fields should be copied instead of spreading everything.

@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 30, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@kilo-code-bot
Copy link
Copy Markdown

kilo-code-bot Bot commented Apr 30, 2026

Code Review Summary

Status: 6 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 1
WARNING 5
SUGGESTION 0
Issue Details (click to expand)

CRITICAL

File Line Issue
lib/actions/init.js 236 templates.find() can return undefined, causing picked.name to throw

WARNING

| File | Line | Issue |
|------|------|
| lib/actions/init.js | 64 | tar command portability issues between GNU and BSD tar |
| lib/actions/init.js | 176 | API key regex may not handle special characters in values |
| lib/actions/init.js | 34 | No timeout on HTTPS request - can hang indefinitely |
| lib/actions/init.js | 68 | Multiple top-level dirs in tarball causes unpredictable behavior |
| lib/actions/init.js | 154 | mergeCampaignEntry copies all upstream properties, including potentially unwanted fields |

Changes Since Last Review

3-line UX improvement: Added descriptive hints to prompt messages for campaign name, slug, and API key. No functional changes. No new issues introduced.

All 6 previous issues remain outstanding.

Files Reviewed (2 files)
  • lib/actions/init.js - 6 issues (unchanged)
  • test/init.test.js - No issues

Note: The changed lines (240, 253, 331) are UX improvements adding helper text to prompts. No new issues found.

Fix these issues in Kilo Cloud


Reviewed by minimax-m2.7 · 107,641 tokens

@alexphelps alexphelps merged commit 18353b3 into main Apr 30, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant