mirror of
https://github.com/affaan-m/ECC.git
synced 2026-11-04 15:15:49 +00:00
When strict YAML cannot load a rule (for example unquoted globs), the line-based fallback treated trigger: '' as native and left the rule without an activation trigger. Read the trigger value by hand, drop a trailing comment and surrounding quotes, and only treat a nonblank value as native. Refs #3548 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
102 lines
3.2 KiB
JavaScript
102 lines
3.2 KiB
JavaScript
'use strict';
|
|
|
|
// Antigravity only attaches a workspace rule when its frontmatter declares an
|
|
// activation trigger (always_on, glob, model_decision or manual). ECC's
|
|
// canonical rules are written for Claude Code: common rules have no
|
|
// frontmatter and language rules scope themselves with a `paths:` list, which
|
|
// Antigravity does not read. Without a trigger the installed files sit in
|
|
// .agents/rules/ and are never loaded.
|
|
|
|
const FRONTMATTER_PATTERN = /^---\r?\n([\s\S]*?)\r?\n---\r?\n/;
|
|
const TRIGGER_LINE = /^trigger[ \t]*:(.*)$/m;
|
|
|
|
// Fallback for frontmatter that strict YAML cannot load: read the trigger
|
|
// line by hand and accept it only when it holds a nonblank value.
|
|
function hasNativeTriggerLine(yamlText) {
|
|
const match = yamlText.match(TRIGGER_LINE);
|
|
if (!match) {
|
|
return false;
|
|
}
|
|
let value = match[1].trim();
|
|
if (value.startsWith('#')) {
|
|
return false;
|
|
}
|
|
value = value.replace(/[ \t]+#.*$/, '');
|
|
const quoted = value.match(/^(['"])(.*)\1$/);
|
|
if (quoted) {
|
|
value = quoted[2];
|
|
}
|
|
return value.trim() !== '';
|
|
}
|
|
|
|
function parseFrontmatter(source, label) {
|
|
const match = source.match(FRONTMATTER_PATTERN);
|
|
if (!match) {
|
|
return null;
|
|
}
|
|
|
|
// Keep YAML loading behind the transform boundary, like the agent adapter:
|
|
// planning must stay free of runtime package dependencies.
|
|
let frontmatter;
|
|
try {
|
|
frontmatter = require('js-yaml').load(match[1]);
|
|
} catch (error) {
|
|
// Antigravity-native glob rules may hold unquoted `globs: **/*.ts`, which
|
|
// strict YAML rejects as an alias. Leave such rules untouched.
|
|
if (hasNativeTriggerLine(match[1])) {
|
|
return { native: true };
|
|
}
|
|
throw error;
|
|
}
|
|
if (frontmatter === null || frontmatter === undefined) {
|
|
return { frontmatter: {}, body: source.slice(match[0].length) };
|
|
}
|
|
if (typeof frontmatter !== 'object' || Array.isArray(frontmatter)) {
|
|
throw new Error(`Cannot adapt Antigravity rule ${label}: frontmatter must be an object`);
|
|
}
|
|
// A rule that already declares a usable trigger is Antigravity-native.
|
|
if (typeof frontmatter.trigger === 'string' && frontmatter.trigger.trim()) {
|
|
return { native: true };
|
|
}
|
|
|
|
return { frontmatter, body: source.slice(match[0].length) };
|
|
}
|
|
|
|
function toGlobList(paths) {
|
|
const values = Array.isArray(paths) ? paths : [paths];
|
|
return values
|
|
.map(value => String(value).trim())
|
|
.filter(Boolean);
|
|
}
|
|
|
|
function adaptAntigravityRule(source, label = '<unknown>') {
|
|
const text = String(source || '');
|
|
const parsed = parseFrontmatter(text, label);
|
|
|
|
if (!parsed) {
|
|
return `---\ntrigger: always_on\n---\n${text}`;
|
|
}
|
|
|
|
if (parsed.native) {
|
|
return text;
|
|
}
|
|
|
|
const { frontmatter, body } = parsed;
|
|
|
|
const globs = Object.hasOwn(frontmatter, 'paths') ? toGlobList(frontmatter.paths) : [];
|
|
// Quote globs: a plain YAML scalar cannot start with `*` (alias indicator).
|
|
const lines = globs.length > 0
|
|
? ['trigger: glob', `globs: ${JSON.stringify(globs.join(','))}`]
|
|
: ['trigger: always_on'];
|
|
|
|
if (typeof frontmatter.description === 'string' && frontmatter.description.trim()) {
|
|
lines.push(`description: ${JSON.stringify(frontmatter.description.trim())}`);
|
|
}
|
|
|
|
return `---\n${lines.join('\n')}\n---\n${body}`;
|
|
}
|
|
|
|
module.exports = {
|
|
adaptAntigravityRule,
|
|
};
|