* refactor(#712): replace Codex slash-command denylist lookbehind with positive-boundary match The hyphen-style /gsd-<cmd> -> $gsd-<cmd> conversion in convertSlashCommandsToCodexSkillMentions used a negative-lookbehind DENYLIST enumerating characters that must NOT precede a real mention. #637 -> #704 showed this is an unbounded treadmill: each new unanticipated preceding char (/, ., word chars, then }, )) leaked the same path-corruption bug class, and a backtick-wrapped path (`/gsd-core/workflows/update.md`) still leaked through. Replace it with a POSITIVE two-boundary definition of a mention: 1. Left: opens at start-of-string, whitespace, or an inline-prose delimiter (backtick/quote/paren/bracket). 2. Right: the command token is not followed by a path separator `/` (a path continues, a command does not). The (?![a-z0-9/-]) lookahead also blocks regex backtracking to a shorter command. This closes the whole class by construction (no preceding-char denylist to maintain) and fixes the backtick-wrapped-path corruption the #704 test documented as a pre-existing gap, while preserving conversion of legitimate backtick-wrapped mentions (e.g. CONTEXT.md's `/gsd-execute-phase` lists). The colon-style /gsd: replace is intentionally left unguarded (it never appears as a filesystem path segment) and is annotated as such. Tests assert the regex directly (function now exported) across a convert/ don't-convert matrix plus one end-to-end pipeline assertion for the headline backtick-path case. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * chore(#712): add changeset fragment for PR #747 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -2797,17 +2797,22 @@ function convertClaudeAgentToClineAgent(content) {
|
||||
// ── End Cline converters ─────────────────────────────────────────────────────
|
||||
|
||||
function convertSlashCommandsToCodexSkillMentions(content) {
|
||||
// Convert colon-style skill invocations to Codex $ prefix
|
||||
// Colon-style /gsd: never appears as a filesystem path segment, so no boundary guard is needed (unlike the hyphen-style below).
|
||||
let converted = content.replace(/\/gsd:([a-z0-9-]+)/gi, (_, commandName) => {
|
||||
return `$gsd-${String(commandName).toLowerCase()}`;
|
||||
});
|
||||
// Convert hyphen-style command references (workflow output) to Codex $ prefix.
|
||||
// Negative lookbehind excludes shell path contexts where `/gsd-` is a path
|
||||
// segment, not a slash-command mention:
|
||||
// - word chars / dot / slash: `bin/gsd-tools.cjs`, `.claude/gsd-core/`
|
||||
// - `}`: shell variable expressions `${VAR}/gsd-core/` (#704)
|
||||
// - `)`: command-substitution paths `$(cmd)/gsd-local-patches` (#704)
|
||||
converted = converted.replace(/(?<![a-zA-Z0-9./})])\/gsd-([a-z0-9-]+)/gi, (_, commandName) => {
|
||||
// A real /gsd-<cmd> MENTION is defined positively by two boundaries, so any
|
||||
// in-path occurrence is excluded by construction (no denylist of preceding
|
||||
// chars to maintain — see #712, supersedes the #637/#704 lookbehind treadmill):
|
||||
// 1. Left boundary: opens at start-of-string, whitespace, or an inline-prose
|
||||
// delimiter (backtick/quote/paren/bracket) — e.g. `/gsd-execute-phase`.
|
||||
// 2. Right boundary: the command token is NOT followed by a path separator
|
||||
// `/` (a path continues: `/gsd-core/bin/...`; a command does not). The
|
||||
// `(?![a-z0-9/-])` also blocks regex backtracking to a shorter command.
|
||||
// This converts backtick-wrapped MENTIONS (`/gsd-foo`) while leaving backtick-
|
||||
// wrapped PATHS (`/gsd-core/workflows/update.md`) untouched (#712).
|
||||
converted = converted.replace(/(?<=^|[\s`"'([])\/gsd-([a-z0-9-]+)(?![a-z0-9/-])/gi, (_, commandName) => {
|
||||
return `$gsd-${String(commandName).toLowerCase()}`;
|
||||
});
|
||||
return converted;
|
||||
@@ -10948,6 +10953,7 @@ module.exports = {
|
||||
install,
|
||||
installAllRuntimes,
|
||||
uninstall,
|
||||
convertSlashCommandsToCodexSkillMentions,
|
||||
convertClaudeCommandToCodexSkill,
|
||||
convertClaudeToOpencodeFrontmatter,
|
||||
convertClaudeToKiloFrontmatter,
|
||||
|
||||
Reference in New Issue
Block a user