thedotmack/claude-mem · critical · Error

Hand-edited Windows shell string detected in ${filePath} (${

Error message

Hand-edited Windows shell string detected in ${filePath} (${dottedPath}). It no longer matches src/build/hook-shell-template.ts. Regenerate via `node scripts/build-hooks.js --write-shell-templates` after an intentional generator change.

What it means

The Windows-specific half of the Rule A guard from [3]. For manifest entries where expected is an object (not a bare string), the verifier also compares entry.commandWindows against expected.commandWindows. A mismatch on the Windows launcher string throws this. Triggered identically to [3] but only when the generator emits a distinct Windows command.

Source

Thrown at scripts/build-hooks.js:207

      for (const [dottedPath, expected] of Object.entries(spec.commands)) {
        const entry = hookEntryByPath(parsed, dottedPath);
        const expectedCommand = typeof expected === 'string' ? expected : expected.command;
        const actual = entry?.command ?? null;
        if (actual !== expectedCommand) {
          if (!writeMode || !entry) {
            throw new Error(
              `Hand-edited shell string detected in ${filePath} (${dottedPath}). It no longer matches src/build/hook-shell-template.ts. ` +
              `Regenerate via \`node scripts/build-hooks.js --write-shell-templates\` after an intentional generator change.`
            );
          }
          entry.command = expectedCommand;
          dirty = true;
        }
        if (typeof expected !== 'string') {
          const actualWindows = entry?.commandWindows ?? null;
          if (actualWindows !== expected.commandWindows) {
            if (!writeMode || !entry) {
              throw new Error(
                `Hand-edited Windows shell string detected in ${filePath} (${dottedPath}). It no longer matches src/build/hook-shell-template.ts. ` +
                `Regenerate via \`node scripts/build-hooks.js --write-shell-templates\` after an intentional generator change.`
              );
            }
            entry.commandWindows = expected.commandWindows;
            dirty = true;
          }
        }
      }
    }
    if (dirty) {
      fs.writeFileSync(filePath, JSON.stringify(parsed, null, 2) + '\n');
      console.log(`  ✏️  Regenerated shell templates in ${filePath}`);
    }
  }

  // Rule C safety net (bun-runner.js fixBrokenScriptPath) must stay documented.
  const bunRunner = fs.readFileSync('plugin/scripts/bun-runner.js', 'utf-8');

View on GitHub (pinned to d768ba3643)

Solutions

  1. Run node scripts/build-hooks.js --write-shell-templates to rewrite commandWindows from buildCodexWindowsCommand.
  2. If the entry is missing, restore the hook entry in the JSON first (the regenerator needs a target object), then re-run.
  3. Otherwise revert the hand edit: git checkout -- <filePath>.
  4. Confirm the verifier prints '✓ Rule A shell templates match the canonical generator'.

Example fix

# before: Windows launcher hand-edited
"commandWindows": "powershell -File old.ps1"

node scripts/build-hooks.js --write-shell-templates

# after: commandWindows matches buildCodexWindowsCommand output
Defensive patterns

Strategy: validation

Validate before calling

// CI step: node scripts/build-hooks.js  (verifier; non-zero exit on Windows-launcher drift)
// Confirms every entry.commandWindows matches buildCodexWindowsCommand output.

Type guard

function hasWindowsCommand(entry): entry is { commandWindows: string } {
  return entry != null && typeof entry.commandWindows === 'string';
}

Try / catch

// Build-time only. Resolve by regenerating (--write-shell-templates) or reverting
// the Windows launcher hand edit. Never catch/suppress.

Prevention

When it happens

Trigger: A hooks JSON has entry.commandWindows that differs from buildCodexWindowsCommand output. Fires during node scripts/build-hooks.js verification when writeMode is off, or when on but the entry itself is absent so the regenerator cannot populate commandWindows.

Common situations: Editing the Windows branch of a hook by hand. Changing buildCodexWindowsCommand in src/build/hook-shell-template.ts without regenerating. Removing a hook entry while the manifest still expects a commandWindows field.

Related errors


AI-assisted analysis of thedotmack/claude-mem@d768ba3643 (2026-08-12). Data as JSON: /api/errors/d316d288cffe3469. Report an issue: GitHub.