castle-web-cli 0.4.40 → 0.4.42

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.
@@ -105,12 +105,12 @@ export function buildTaskPrompt(opts) {
105
105
  // Claude-only: collapsing the wrap-up (progress 90 + restart + notes) into
106
106
  // one shell call reliably saves 1-2 serial ~7s turns there. Cursor's
107
107
  // composer sometimes reacts to the same rule with MORE calls, so it stays
108
- // on the plain instructions. Read-before-overwrite likewise targets
109
- // claude's Write-tool precondition (a blind Write to an existing file is
110
- // rejected, forcing a wasted failed-call + Read + retry cycle).
108
+ // on the plain instructions.
109
+ // (We deliberately do NOT tell agents to overwrite files via `cat > … <<EOF`
110
+ // -- blind whole-file rewrites made parallel agents clobber each other's
111
+ // edits. Read-then-edit is slower but safe; that is the right tradeoff.)
111
112
  const wrapUp = opts.backend === 'claude'
112
- ? `\n- NEVER point your Write tool at a file that already exists (scenes/main.scene especially): it rejects files it has not Read, and the failed call + forced Read wastes two turns. Replace existing files with ONE shell command instead (\`cat > scenes/main.scene <<'EOF' ... EOF\`); reserve the Write tool for brand-new files.
113
- - Wrap up in ONE tool call, not several: once your last file edit is done, combine the 90-progress write, the final \`npm run restart\`, and writing the notes file into a single shell command (\`;\`-separated so the notes land even if the restart hiccups). Then stop -- no extra turns after it.`
113
+ ? `\n- Wrap up in ONE tool call, not several: once your last file edit is done, combine the 90-progress write, the final \`npm run restart\`, and writing the notes file into a single shell command (\`;\`-separated so the notes land even if the restart hiccups). Then stop -- no extra turns after it.`
114
114
  : '';
115
115
  return `You are a background build agent for the Castle deck "${opts.deckLabel}" (current directory). A separate conversation agent dispatched you with one task. Read the deck's CLAUDE.md / AGENTS.md first and follow its workflow (including reloading the served deck after changes, e.g. \`npm run restart\`).
116
116
 
@@ -123,6 +123,7 @@ Operating rules:
123
123
  - The USER is the verifier -- the whole tasks system exists so the user playtests every change themselves. Your first priority is to finish as soon as possible with the change genuinely in place and reachable in the running deck, so the user can test it right away. Do NOT run verification (screenshots especially) unless you are really sure it will catch something a re-read of your own change cannot -- and even then at most one cheap check, never a retry loop. Time spent verifying is time the user is left waiting.
124
124
  - The moment implementation is complete and you switch to verifying, write 90 to the progress file -- verification time must not read as stalled progress.
125
125
  - Do this one task completely, then stop. Do not expand scope.
126
+ - Other task agents may be editing this same deck IN PARALLEL. When you change an existing file, READ it first and make a targeted edit to just the part you need -- never overwrite a whole file you have not read. A blind full-file rewrite clobbers other agents' in-flight changes. Being a bit slower and careful here is the right tradeoff.
126
127
  - Update your progress VERY frequently: write a bare integer 0-100 to ${opts.progressPath} (e.g. \`echo 30 > ${opts.progressPath}\`) every time you advance -- at least every 10 points, or every 20 for properly small tasks. Start near 10, write 90 just before wrapping up. Never let it sit stale while you work.
127
128
  - Before finishing, write ${opts.notesPath}: a SHORT test guide for the user -- 2-4 brief sentences. Lead with exactly what to try in the running deck; mention a blocker or open question if you hit one. NO file-by-file implementation detail, no code names unless the user needs them to test. The user reads this verbatim when checking your work off.${wrapUp}
128
129
  - If you are truly blocked, write the blocker to the notes file and stop rather than guessing wildly.
package/dist/init.js CHANGED
@@ -223,12 +223,15 @@ function hasPnpm() {
223
223
  // store is baked in, so this is near-instant (hardlinks from the store, no
224
224
  // download). Fall back to npm when pnpm isn't on PATH (e.g. a laptop that never
225
225
  // installed it). --prefer-offline uses the store/cache first; --ignore-scripts
226
- // skips dep build scripts (pnpm 10 gates them and exits non-zero otherwise, and
227
- // the deck's deps are all prebuilt pure JS that don't need them).
228
- function installDeps(projectDir) {
226
+ // skips dep build scripts (pnpm 10+ gates them and exits non-zero otherwise,
227
+ // and the deck's deps are all prebuilt pure JS that don't need them). `frozen`
228
+ // installs straight from the shipped lockfile (skips resolution -> no network,
229
+ // fast + deterministic); used in published mode where the kit lockfile matches.
230
+ function installDeps(projectDir, frozen) {
229
231
  if (hasPnpm()) {
230
232
  console.log('Installing deps (pnpm)...');
231
- execSync('pnpm install --prefer-offline --ignore-scripts', {
233
+ const frozenFlag = frozen ? '--frozen-lockfile ' : '';
234
+ execSync(`pnpm install ${frozenFlag}--prefer-offline --ignore-scripts`, {
232
235
  cwd: projectDir,
233
236
  stdio: 'inherit',
234
237
  });
@@ -259,10 +262,20 @@ export async function init(dir, opts = {}) {
259
262
  // Always install deps so the deck is ready to serve/edit immediately.
260
263
  // `--no-serve` only skips the serve step below (callers like the cloud
261
264
  // launcher run their own serve, but still want deps in place).
265
+ //
266
+ // Published kit decks ship a matching pnpm-lock.yaml -> frozen install (no
267
+ // resolution, no network; hardlinks from the template's warm store). Workspace
268
+ // decks rewrite the sdk to file:../../sdk, which the shipped (published)
269
+ // lockfile won't match -> drop it and let pnpm resolve. Bare decks have no
270
+ // lockfile -> non-frozen.
271
+ const lockPath = path.join(projectDir, 'pnpm-lock.yaml');
272
+ if (resolveScaffoldRefs().workspaceMode)
273
+ fs.rmSync(lockPath, { force: true });
274
+ const frozen = fs.existsSync(lockPath);
262
275
  console.log('');
263
276
  let installed = false;
264
277
  try {
265
- installDeps(projectDir);
278
+ installDeps(projectDir, frozen);
266
279
  installed = true;
267
280
  }
268
281
  catch {