{"record":{"id":"d316d288cffe3469","repo":"thedotmack/claude-mem","slug":"hand-edited-windows-shell-string-detected-in-fil","errorCode":null,"errorMessage":"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.","messagePattern":"Hand-edited Windows shell string detected in (.+?) \\((.+?)\\)\\. 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\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"scripts/build-hooks.js","lineNumber":207,"sourceCode":"      for (const [dottedPath, expected] of Object.entries(spec.commands)) {\n        const entry = hookEntryByPath(parsed, dottedPath);\n        const expectedCommand = typeof expected === 'string' ? expected : expected.command;\n        const actual = entry?.command ?? null;\n        if (actual !== expectedCommand) {\n          if (!writeMode || !entry) {\n            throw new Error(\n              `Hand-edited shell string detected in ${filePath} (${dottedPath}). It no longer matches src/build/hook-shell-template.ts. ` +\n              `Regenerate via \\`node scripts/build-hooks.js --write-shell-templates\\` after an intentional generator change.`\n            );\n          }\n          entry.command = expectedCommand;\n          dirty = true;\n        }\n        if (typeof expected !== 'string') {\n          const actualWindows = entry?.commandWindows ?? null;\n          if (actualWindows !== expected.commandWindows) {\n            if (!writeMode || !entry) {\n              throw new Error(\n                `Hand-edited Windows shell string detected in ${filePath} (${dottedPath}). It no longer matches src/build/hook-shell-template.ts. ` +\n                `Regenerate via \\`node scripts/build-hooks.js --write-shell-templates\\` after an intentional generator change.`\n              );\n            }\n            entry.commandWindows = expected.commandWindows;\n            dirty = true;\n          }\n        }\n      }\n    }\n    if (dirty) {\n      fs.writeFileSync(filePath, JSON.stringify(parsed, null, 2) + '\\n');\n      console.log(`  ✏️  Regenerated shell templates in ${filePath}`);\n    }\n  }\n\n  // Rule C safety net (bun-runner.js fixBrokenScriptPath) must stay documented.\n  const bunRunner = fs.readFileSync('plugin/scripts/bun-runner.js', 'utf-8');","sourceCodeStart":189,"sourceCodeEnd":225,"githubUrl":"https://github.com/thedotmack/claude-mem/blob/d768ba364302d12b76e69e4f021f0bb1d2d50ed6/scripts/build-hooks.js#L189-L225","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Run node scripts/build-hooks.js --write-shell-templates to rewrite commandWindows from buildCodexWindowsCommand.","If the entry is missing, restore the hook entry in the JSON first (the regenerator needs a target object), then re-run.","Otherwise revert the hand edit: git checkout -- <filePath>.","Confirm the verifier prints '✓ Rule A shell templates match the canonical generator'."],"exampleFix":"# before: Windows launcher hand-edited\n\"commandWindows\": \"powershell -File old.ps1\"\n\nnode scripts/build-hooks.js --write-shell-templates\n\n# after: commandWindows matches buildCodexWindowsCommand output","handlingStrategy":"validation","validationCode":"// CI step: node scripts/build-hooks.js  (verifier; non-zero exit on Windows-launcher drift)\n// Confirms every entry.commandWindows matches buildCodexWindowsCommand output.","typeGuard":"function hasWindowsCommand(entry): entry is { commandWindows: string } {\n  return entry != null && typeof entry.commandWindows === 'string';\n}","tryCatchPattern":"// Build-time only. Resolve by regenerating (--write-shell-templates) or reverting\n// the Windows launcher hand edit. Never catch/suppress.","preventionTips":["Treat commandWindows as fully generator-owned; do not hand-edit even for Windows testing.","Keep buildCodexWindowsCommand in the template as the single source of truth.","Run the build on Windows CI too, so Windows-only drift is caught early."],"tags":["build","verification","shell-template","rule-a","windows"],"backgroundTag":null,"analyzedSha":"d768ba364302d12b76e69e4f021f0bb1d2d50ed6","analyzedAt":"2026-08-12T23:52:55.241Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}