Merge branch 'next' into fix/2137-derive-progress-header-driven

This commit is contained in:
Behruz Nassre Esfahani
2026-07-11 06:59:25 -07:00
committed by GitHub
28 changed files with 1705 additions and 90 deletions

View File

@@ -1107,6 +1107,11 @@ function convertClaudeToAugmentMarkdown(content) {
return converted;
}
// #2097 (ADR-1239): command-body converters selected by descriptor
// (runtime.hostBehaviors.commandBodyConverter) instead of a runtime-name
// branch. Degrade-closed: unknown/absent name → no conversion.
const COMMAND_BODY_CONVERTERS = { convertClaudeToAugmentMarkdown };
function getAugmentSkillAdapterHeader(skillName) {
return `<augment_skill_adapter>
## A. Skill Invocation
@@ -2442,19 +2447,24 @@ function _applyRuntimeRewrites(content, runtime, pathPrefix, isGlobal = false, a
break;
}
case 'augment':
case 'augment': {
content = content.replace(/~\/\.claude\//g, pathPrefix);
content = content.replace(/\$HOME\/\.claude\//g, pathPrefix);
content = content.replace(/\.\/\.claude\//g, `./${dirName}/`);
content = content.replace(/~\/\.claude(?![\w-])/g, normalizedPathPrefix);
content = content.replace(/\$HOME\/\.claude(?![\w-])/g, normalizedPathPrefix);
content = content.replace(/\.\/\.claude(?![\w-])/g, `./${dirName}`);
content = content.replace(/~\/\.augment\//g, pathPrefix);
content = content.replace(/\$HOME\/\.augment\//g, pathPrefix);
content = content.replace(/~\/\.augment(?![\w-])/g, normalizedPathPrefix);
content = content.replace(/\$HOME\/\.augment(?![\w-])/g, normalizedPathPrefix);
// #2097: dot-dir self-references (~/.augment/…) → resolved prefix,
// dirName-derived (no runtime literal). getDirName('augment') resolves
// to '.augment', so this is byte-identical to the prior hardcoded regexes.
const _dd = escapeRegExp(dirName);
content = content.replace(new RegExp('~/' + _dd + '/', 'g'), pathPrefix);
content = content.replace(new RegExp('\\$HOME/' + _dd + '/', 'g'), pathPrefix);
content = content.replace(new RegExp('~/' + _dd + '(?![\\w-])', 'g'), normalizedPathPrefix);
content = content.replace(new RegExp('\\$HOME/' + _dd + '(?![\\w-])', 'g'), normalizedPathPrefix);
content = processAttribution(content, attribution);
break;
}
case 'trae':
content = content.replace(/~\/\.claude\//g, pathPrefix);
@@ -2631,8 +2641,11 @@ function applyRuntimeContentRewritesForCommandsInPlace(stagedDir, runtime, pathP
if (!entry.isFile() || !entry.name.endsWith('.md')) continue;
let content = fs.readFileSync(path.join(stagedDir, entry.name), 'utf8');
content = _applyRuntimeRewrites(content, runtime, pathPrefix, isGlobal, attribution);
if (runtime === 'augment') {
content = convertClaudeToAugmentMarkdown(content);
// #2097 (ADR-1239): descriptor-driven — commandBodyConverter name comes
// from runtime.hostBehaviors instead of a hardcoded runtime-name branch.
const _cmdConv = _hostBehaviors(runtime).commandBodyConverter;
if (_cmdConv && COMMAND_BODY_CONVERTERS[_cmdConv]) {
content = COMMAND_BODY_CONVERTERS[_cmdConv](content);
}
fs.writeFileSync(path.join(tempDir, entry.name), content);
}
@@ -2743,9 +2756,11 @@ function normalizeAgentBodyForRuntime(content: string, runtime: string, cmdNames
* ~/\.claude\b → normalizedPathPrefix
* $HOME/\.claude\b → normalizedPathPrefix
*
* Skipped for copilot and antigravity (which do NOT do path rewrites in the
* inline loop). NO stamp (_stampNonClaudeRuntimeDefaults) — agents are NOT
* stamped in the inline loop.
* Skipped for copilot (hardcoded — #2099 will fold it) and for any runtime
* that declares `hostBehaviors.noPathRewrite` (descriptor-driven, ADR-1239 /
* #2096 — folds the prior hardcoded `runtime === 'antigravity'` literal;
* Antigravity does NOT do path rewrites in the inline loop). NO stamp
* (_stampNonClaudeRuntimeDefaults) — agents are NOT stamped in the inline loop.
*
* ADR-1235 §1: pre-converter cross-cutting for descriptor-driven agent pipeline.
* Exported as `applyAgentPathRewrites` for testing and for injection into
@@ -2754,10 +2769,10 @@ function normalizeAgentBodyForRuntime(content: string, runtime: string, cmdNames
* @param content raw agent file content
* @param runtime canonical runtime ID
* @param pathPrefix trailing-slash path prefix (e.g. '$HOME/.cursor/')
* @returns content with path-prefix rewrites applied (or unchanged for copilot/antigravity)
* @returns content with path-prefix rewrites applied (or unchanged for copilot / noPathRewrite runtimes)
*/
function applyAgentPathRewrites(content: string, runtime: string, pathPrefix: string): string {
if (runtime === 'copilot' || runtime === 'antigravity') return content;
if (runtime === 'copilot' || _hostBehaviors(runtime).noPathRewrite === true) return content;
const normalizedPathPrefix = pathPrefix.replace(/\/$/, '');
content = content.replace(/~\/\.claude\//g, pathPrefix);
content = content.replace(/\$HOME\/\.claude\//g, pathPrefix);

View File

@@ -22,9 +22,12 @@
* false for codex / copilot / kilo / cursor / windsurf / trae / cline / kimi (legacy exclusion list).
* true for all other runtimes.
* - `finishPermissionWriter` names the finishInstall-phase dedicated config writer:
* 'opencode' → writes BOTH shared settings AND its own permissions file.
* 'kilo' → writes only its own permissions file.
* null → no dedicated permission writer.
* 'opencode' → writes BOTH shared settings AND its own permissions file.
* 'kilo' → writes only its own permissions file.
* 'antigravity' → writes BOTH shared settings.json permissions.allow AND a
* standalone mcp_config.json MCP companion profile (#2096
* Phase B Upgrades 1+2).
* null → no dedicated permission writer.
*/
// eslint-disable-next-line @typescript-eslint/no-require-imports
@@ -45,7 +48,7 @@ type ConfigInstallSurface =
| 'cursor-hooks-json'
| 'profile-marker-only';
type FinishPermissionWriter = 'opencode' | 'kilo' | null;
type FinishPermissionWriter = 'opencode' | 'kilo' | 'antigravity' | null;
type HooksSurface =
| 'settings-json'

View File

@@ -120,13 +120,26 @@ export function resolveRuntimeNameFromCandidates(...candidates: unknown[]): stri
* Aliases are normalized via `canonicalizeRuntimeName` first, so inputs like
* `codex-cli` resolve to `codex` → `AGENTS.md`. Replaces the prior codex-only
* override in profile-output.cjs (#3163) which left AGENTS-native runtimes
* (opencode/kilo/kimi) incorrectly emitting `.claude/CLAUDE.md`. Pure: no I/O.
* (opencode/kilo/kimi) incorrectly emitting `.claude/CLAUDE.md`. Pure: no I/O
* (the lazy `require` below reads a static generated module, not the disk).
*
* Descriptor-driven (ADR-1239 / #2096): antigravity's `GEMINI.md` is folded
* from a hardcoded `canonical === 'antigravity'` literal into a read of
* `runtime.hostBehaviors.projectInstructionFile`. claude/copilot stay
* hardcoded (out of scope here) mirroring `getDirName` below, which already
* lazy-`require`s `capability-registry.cjs` inside the function body to
* avoid a circular dependency at module load.
*/
export function getProjectInstructionFile(runtime: unknown): string {
const canonical = canonicalizeRuntimeName(runtime);
if (canonical === 'claude') return '.claude/CLAUDE.md';
if (canonical === 'copilot') return '.github/copilot-instructions.md';
if (canonical === 'antigravity') return 'GEMINI.md';
// eslint-disable-next-line @typescript-eslint/no-require-imports
const { runtimes } = require('./capability-registry.cjs') as {
runtimes: Record<string, { runtime?: { hostBehaviors?: { projectInstructionFile?: string } } } | undefined>;
};
const declared = canonical ? runtimes[canonical]?.runtime?.hostBehaviors?.projectInstructionFile : undefined;
if (typeof declared === 'string' && declared.length > 0) return declared;
// codex, opencode, kilo, kimi, AND unknown/future runtimes all default to
// root AGENTS.md (the safe cross-agent instruction file).
return 'AGENTS.md';

View File

@@ -98,9 +98,17 @@ export function formatManagedHookScriptToken(scriptPath: string, opts: { platfor
return JSON.stringify(scriptPath.replace(/\\/g, '/'));
}
export function projectLocalHookPrefix({ runtime = 'claude', dirName }: { runtime?: string; dirName?: string | null }): string | undefined | null {
export function projectLocalHookPrefix({ runtime: _runtime = 'claude', dirName, hookPathStyle }: { runtime?: string; dirName?: string | null; hookPathStyle?: string | null }): string | undefined | null {
if (!dirName) return dirName;
return (runtime === 'antigravity')
// Descriptor-driven (ADR-1239 / #2096): folded from a hardcoded
// `runtime === 'antigravity'` literal into the runtime's declared
// `hostBehaviors.hookPathStyle`. Runtimes that always run project hooks
// with the project dir as cwd (Antigravity today) declare 'raw' and get
// the bare dirName; every other runtime keeps the $CLAUDE_PROJECT_DIR-
// anchored prefix. `runtime` itself is now unused here but stays in the
// signature for call-site/back-compat parity (kept `_`-prefixed to
// satisfy no-unused-vars).
return (hookPathStyle === 'raw')
? dirName
: `"$CLAUDE_PROJECT_DIR"/${dirName}`;
}