mirror of
https://github.com/garrytan/gstack.git
synced 2026-11-05 08:23:59 +01:00
feat(hosts): /land-and-deploy and /modernize run only when typed on Claude Code and Cursor (C1) (#3808)
* feat(hosts): manual-only /land-and-deploy and /modernize on Claude Code and Cursor (C1, GST-804) Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * fix(routing): host-neutral router wording, update repo CLAUDE.md and the onboarding fixture for the manual-only skills Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * fix(gen): escape conditionalFields keys, anchor values, skip keys the template already sets Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * fix(modernize): trim always-on description to stay under the 8000-token context budget Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> --------- Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
1 parent
92f22ea87e
commit
242e918bcb
17 files changed
+104
-38
No files matched your search
+12
-16
@@ -486,13 +486,21 @@ policy:
|
||||
|
||||
/**
|
||||
* Transform frontmatter for external hosts.
|
||||
* Claude: strips `sensitive:` field (only Factory uses it).
|
||||
* Claude: strips template-only fields, adds disable-model-invocation to manual_only skills.
|
||||
* Codex: keeps name + description only, enforces 1024-char limit.
|
||||
* Factory: keeps name + description + user-invocable, conditionally adds disable-model-invocation.
|
||||
*/
|
||||
function transformFrontmatter(content: string, host: Host): string {
|
||||
const hostConfig = getHostConfig(host);
|
||||
const fm = hostConfig.frontmatter;
|
||||
const templateFrontmatter = content.startsWith('---\n') ? content.slice(4, content.indexOf('\n---', 4)) : '';
|
||||
const escape = (s: unknown) => String(s).replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||||
const conditionalLines = (fm.conditionalFields || [])
|
||||
.filter(rule => Object.entries(rule.if).every(([k, v]) => new RegExp(`^${escape(k)}:[ \\t]*${escape(v)}[ \\t]*$`, 'm').test(templateFrontmatter)))
|
||||
.flatMap(rule => Object.entries(rule.add))
|
||||
.filter(([key]) => !new RegExp(`^${escape(key)}:`, 'm').test(templateFrontmatter))
|
||||
.map(([key, value]) => `${key}: ${value}\n`)
|
||||
.join('');
|
||||
|
||||
if (fm.mode === 'denylist') {
|
||||
// Denylist mode: strip listed fields, keep everything else
|
||||
@@ -503,7 +511,7 @@ function transformFrontmatter(content: string, host: Host): string {
|
||||
content = content.replace(new RegExp(`^${field}:\\s*.*\\n`, 'm'), '');
|
||||
}
|
||||
}
|
||||
return content;
|
||||
return conditionalLines ? content.replace('\n---\n', () => `\n${conditionalLines}---\n`) : content;
|
||||
}
|
||||
|
||||
// Allowlist mode: reconstruct frontmatter with only allowed fields
|
||||
@@ -546,19 +554,7 @@ function transformFrontmatter(content: string, host: Host): string {
|
||||
}
|
||||
}
|
||||
|
||||
// Add conditional fields
|
||||
if (fm.conditionalFields) {
|
||||
for (const rule of fm.conditionalFields) {
|
||||
const match = Object.entries(rule.if).every(([k, v]) =>
|
||||
new RegExp(`^${k}:\\s*${v}`, 'm').test(frontmatter)
|
||||
);
|
||||
if (match) {
|
||||
for (const [key, value] of Object.entries(rule.add)) {
|
||||
newFm += `${key}: ${value}\n`;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
newFm += conditionalLines;
|
||||
|
||||
// Preserve additional keepFields beyond name and description
|
||||
if (fm.keepFields) {
|
||||
@@ -853,7 +849,7 @@ function processTemplate(tmplPath: string, host: Host, options: RenderOptions):
|
||||
// metadata gets the updated description with voice triggers included.
|
||||
const postProcessDescription = extractNameAndDescription(content).description;
|
||||
|
||||
// For Claude: strip sensitive: field (only Factory uses it)
|
||||
// For Claude: strip template-only fields, add conditional fields
|
||||
// For external hosts: route output, transform frontmatter, rewrite paths
|
||||
let symlinkLoop = false;
|
||||
let metadata: { outputPath: string; content: string } | undefined;
|
||||
|
||||
Reference in new issue
Block a user