feat(absorb-tstack): /modernize skill, per-skill Codex default prompts, gstack-post --attribute, the unattended grant and a CONTRIBUTING porting section

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
garrytanandcapy-ai[bot] committed 2026-10-26 21:16:00 +00:00
1 parent 576839cb8c
commit 15ca433067
38 files changed
+1032 -27

No files matched your search

+22 -4
View File
@@ -432,11 +432,28 @@ function condenseOpenAIShortDescription(description: string): string {
return `${safe}...`;
}
function generateOpenAIYaml(displayName: string, shortDescription: string): string {
/**
* The sentence Codex's skill picker inserts when a user chooses the skill.
* A template sets it with a `codex_default_prompt:` frontmatter key (one line,
* optionally quoted; `$<display name>` is Codex's own skill reference). Without
* the key the prompt is the generic fallback, so every skill keeps a valid entry.
*/
export function extractCodexDefaultPrompt(tmplContent: string): string | undefined {
const fmEnd = tmplContent.startsWith('---\n') ? tmplContent.indexOf('\n---', 4) : -1;
if (fmEnd === -1) return undefined;
const match = tmplContent.slice(4, fmEnd).match(/^codex_default_prompt:[ \t]*(.+?)[ \t]*$/m);
if (!match) return undefined;
const raw = match[1];
const quoted = raw.match(/^"(.*)"$/) || raw.match(/^'(.*)'$/);
const value = quoted ? quoted[1] : raw;
return value.length > 0 ? value : undefined;
}
export function generateOpenAIYaml(displayName: string, shortDescription: string, defaultPrompt?: string): string {
return `interface:
display_name: ${JSON.stringify(displayName)}
short_description: ${JSON.stringify(shortDescription)}
default_prompt: ${JSON.stringify(`Use ${displayName} for this task.`)}
default_prompt: ${JSON.stringify(defaultPrompt ?? `Use ${displayName} for this task.`)}
policy:
allow_implicit_invocation: true
`;
@@ -748,10 +765,11 @@ function processExternalHost(
// section cross-references get the same per-host treatment as SKILL.md).
result = applyHostRewrites(result, hostConfig);
// Config-driven: generate metadata (e.g., openai.yaml for Codex)
// Config-driven: generate metadata (e.g., openai.yaml for Codex). The
// default_prompt comes from the template's codex_default_prompt: key when set.
const metadata = hostConfig.generation.generateMetadata && !symlinkLoop ? {
outputPath: path.join(outputDir, 'agents', 'openai.yaml'),
content: generateOpenAIYaml(name, condenseOpenAIShortDescription(extractedDescription)),
content: generateOpenAIYaml(name, condenseOpenAIShortDescription(extractedDescription), extractCodexDefaultPrompt(tmplContent)),
} : undefined;
return { content: result, outputPath, symlinkLoop, metadata };
+1 -1
View File
@@ -97,7 +97,7 @@ export interface HostConfig {
// --- Generation ---
generation: {
/** Whether to create a metadata file alongside skills (always openai.yaml; gen-skill-docs hardcodes the format). */
/** Whether to create a metadata file alongside skills (always openai.yaml; gen-skill-docs hardcodes the format and reads the template's `codex_default_prompt:` key for its default_prompt). */
generateMetadata: boolean;
/** Skill directories to exclude from generation for this host. */
skipSkills?: string[];