refactor(#1510): relocate getDirName + processAttribution out of bin/install.js (#1512)

Phase 1 of epic #1507 (ADR-1508): behavior-preserving relocation of the pure
rewrite-engine helpers out of the hand-authored installer so the conversion
module can own them without importing bin/install.js.

- getDirName -> src/runtime-name-policy.cts (pure runtime->dir-name switch).
- processAttribution -> src/runtime-artifact-conversion.cts (pure Co-Authored-By
  content transform).
- bin/install.js imports both back via destructure/binding and re-exports
  getDirName unchanged (Hyrum: install.test.cjs + runtime install tests import
  getDirName from bin/install.js).

Two refinements to ADR-1508's Phase 1 (verified against the source):
- getCommitAttribution STAYS in bin/install.js: it is impure install-time
  config I/O (reads runtime settings.json, uses install-time config-dir state +
  attributionCache), not a content transform. Phase 2 will inject the resolved
  attribution into the engine rather than move this function.
- The convertClaudeToAugmentMarkdown dedup is deferred to Phase 2's cleanup: the
  local copy is entangled with a converter cluster (convertSlashCommandsTo
  AugmentSkillMentions is used only by it; the family is partly dead-local via
  the ...runtimeArtifactConversion export spread), deduping only augment would be
  arbitrary, and it is not required to unblock Phase 2 (the engine will call the
  conversion module's own copy when it moves).

New tests/enh-1510-*.test.cjs: getDirName at its new home (all runtimes +
fallback + install.js re-export identity) and processAttribution
(null/undefined/string/$-escape/CRLF/global). 487 affected-suite tests green.


Claude-Session: https://claude.ai/code/session_0187qgypdy1wkWRpdaf2hRuD

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Tom Boucher
2026-06-20 22:29:15 -04:00
committed by GitHub
parent fd0657ddb5
commit cadc944781
4 changed files with 183 additions and 37 deletions

View File

@@ -2095,7 +2095,36 @@ function convertClaudeCommandToKiloSkill(content, skillName) {
}
/**
* Apply Co-Authored-By attribution policy to file content.
* - null -> remove the Co-Authored-By line and its preceding blank line
* - undefined -> leave content unchanged
* - string -> replace the value ($ escaped to block backreference injection)
*
* Pure content transform, relocated from bin/install.js per ADR-1508
* (epic #1507, #1510 Phase 1). NOTE: getCommitAttribution stays in the
* installer — it is impure install-time config I/O (reads runtime
* settings.json, uses the install-time config-dir + cache), not a content
* transform, so it does not belong behind this content-conversion seam.
*/
function processAttribution(
content: string,
attribution: string | null | undefined,
): string {
if (attribution === null) {
// Remove Co-Authored-By lines and the preceding blank line
return content.replace(/(\r?\n){2}Co-Authored-By:.*$/gim, '');
}
if (attribution === undefined) {
return content;
}
// Replace with custom attribution (escape $ to prevent backreference injection)
const safeAttribution = attribution.replace(/\$/g, '$$$$');
return content.replace(/Co-Authored-By:.*$/gim, `Co-Authored-By: ${safeAttribution}`);
}
export = {
processAttribution,
yamlIdentifier,
yamlQuote,
toSingleLine,

View File

@@ -88,3 +88,32 @@ export function resolveRuntimeNameFromCandidates(...candidates: unknown[]): stri
}
return null;
}
/**
* Map a canonical runtime id to its on-disk local config directory name
* (e.g. `cursor` -> `.cursor`, `windsurf` -> `.devin`). Unknown/empty inputs
* fall back to `.claude`.
*
* Pure runtime-identity projection. Relocated from `bin/install.js` per
* ADR-1508 (epic #1507, #1510 Phase 1) so the Runtime Artifact Conversion
* Module's rewrite engine can consume it without importing the installer.
* `bin/install.js` re-exports this same function for back-compat.
*/
export function getDirName(runtime: string): string {
if (runtime === 'copilot') return '.github';
if (runtime === 'opencode') return '.opencode';
if (runtime === 'gemini') return '.gemini';
if (runtime === 'kilo') return '.kilo';
if (runtime === 'codex') return '.codex';
if (runtime === 'antigravity') return '.agents';
if (runtime === 'cursor') return '.cursor';
if (runtime === 'windsurf') return '.devin';
if (runtime === 'augment') return '.augment';
if (runtime === 'trae') return '.trae';
if (runtime === 'qwen') return '.qwen';
if (runtime === 'hermes') return '.hermes';
if (runtime === 'kimi') return '.kimi-code';
if (runtime === 'codebuddy') return '.codebuddy';
if (runtime === 'cline') return '.cline';
return '.claude';
}