Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"$schema": "https://anthropic.com/claude-code/marketplace.schema.json",
"$schema": "https://json.schemastore.org/claude-code-marketplace.json",
"name": "agentic-utilities",
"description": "Curated Claude Code plugins from agentic-utilities — a harness-agnostic collection of skills, plugins, and extensions across pi, Claude Code, and Codex. This marketplace exposes the Claude Code plugins.",
"owner": {
Expand Down Expand Up @@ -54,7 +54,7 @@
},
{
"name": "ask-codex",
"description": "OpenAI Codex CLI integration for Claude Code. Wraps `codex exec` and `codex resume` with model selection (gpt-5.4 / gpt-5.3-codex / gpt-5.4-nano), reasoning effort control (high/medium/low), sandbox modes (read-only / workspace-write / danger-full-access), session resumption, and stderr suppression for thinking tokens.",
"description": "OpenAI Codex CLI integration for Claude Code. Wraps `codex exec` and `codex resume` with model selection (gpt-5.4 / gpt-5.3-codex / gpt-5.4-nano), reasoning effort control (high/medium/low), sandbox modes (read-only / workspace-write / danger-full-access), session resumption, and stderr suppression for thinking tokens. Requires the `codex` binary on PATH.",
"version": "0.1.0",
"author": {
"name": "Ossie Irondi"
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
node_modules/
.pnpm-store/
.DS_Store
__pycache__/
*.py[cod]
.env
.env.*
!.env.example
Expand Down
2 changes: 1 addition & 1 deletion claude-code/plugins/ask-codex/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "ask-codex",
"version": "0.1.0",
"description": "OpenAI Codex CLI integration for Claude Code. Wraps `codex exec` and `codex resume` with model selection (gpt-5.4 / gpt-5.3-codex / gpt-5.4-nano), reasoning effort control (high/medium/low), sandbox modes (read-only / workspace-write / danger-full-access), session resumption, and stderr suppression for thinking tokens.",
"description": "OpenAI Codex CLI integration for Claude Code. Wraps `codex exec` and `codex resume` with model selection (gpt-5.4 / gpt-5.3-codex / gpt-5.4-nano), reasoning effort control (high/medium/low), sandbox modes (read-only / workspace-write / danger-full-access), session resumption, and stderr suppression for thinking tokens. Requires the `codex` binary on PATH.",
"author": {
"name": "Ossie Irondi"
},
Expand Down
20 changes: 6 additions & 14 deletions claude-code/plugins/awesome-readme/skills/awesome-readme/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,24 +57,16 @@ If neither (1) nor (2) is set up and the user picks "Yes, generate via gpt-image

### How to invoke

When a workflow needs an image, invoke the **gpt-image-2** skill directly:
When a workflow needs an image, invoke the installed **gpt-image-2** skill directly (do not try to locate or run its script yourself; the skill loader resolves that). Pass:

```bash
bash scripts/gen.sh \
--prompt "<descriptive prompt for the README element>" \
--out docs/<descriptive-name>.png
```
- `--prompt "<descriptive prompt for the README element>"`
- `--out docs/<descriptive-name>.png`

For reference-image conditioning (remix an existing logo, restyle a screenshot, etc.):
For reference-image conditioning (remix an existing logo, restyle a screenshot, etc.), also pass:

```bash
bash scripts/gen.sh \
--prompt "<remix instruction>" \
--ref /absolute/path/to/reference.png \
--out docs/<descriptive-name>.png
```
- `--ref /absolute/path/to/reference.png`

The script lives inside the gpt-image-2 skill's directory; the standard skill loader resolves it. Pass the user's prompt through raw — only polish wording when the user explicitly asks for it. After the image lands, display/attach it in the response; never stop at "saved to docs/x.png".
Pass the user's prompt through raw. Only polish wording when the user explicitly asks for it. After the image lands, display/attach it in the response; never stop at "saved to docs/x.png".

### Prompt patterns for README elements

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,34 +99,15 @@ Follow this 10-section order — story before installation:

If the user said yes in Step 2, invoke the **gpt-image-2** skill — once per visual. Pass the user's intent through raw; only polish wording when the user explicitly asked for "fancy" or "make it look great".

**Pattern:**

```bash
bash scripts/gen.sh \
--prompt "<README element prompt — see SKILL.md 'Prompt patterns' table>" \
--out docs/<descriptive-name>.png
```
**Pattern:** invoke the installed gpt-image-2 skill (do not try to locate or run its script yourself) with `--prompt "<README element prompt: see SKILL.md 'Prompt patterns' table>"` and `--out docs/<descriptive-name>.png`.

**Example invocations for a typical Story-mode README:**

```bash
# Hero banner with embedded tagline
bash scripts/gen.sh \
--prompt "<project> README hero banner. <subject in one phrase>. Embedded tagline reads: '<the tagline>'." \
--out docs/hero.png

# Architecture diagram
bash scripts/gen.sh \
--prompt "Architecture diagram for <project>. <ComponentA> connects to <ComponentB> via <ComponentC>. Excalidraw / hand-drawn style. Clear labels on each node." \
--out docs/architecture.png

# Workflow illustration
bash scripts/gen.sh \
--prompt "Workflow illustration: step 1 <X>, step 2 <Y>, step 3 <Z>. Numbered left-to-right flow with annotated arrows." \
--out docs/workflow.png
```
- Hero banner with embedded tagline: `--prompt "<project> README hero banner. <subject in one phrase>. Embedded tagline reads: '<the tagline>'." --out docs/hero.png`
- Architecture diagram: `--prompt "Architecture diagram for <project>. <ComponentA> connects to <ComponentB> via <ComponentC>. Excalidraw / hand-drawn style. Clear labels on each node." --out docs/architecture.png`
- Workflow illustration: `--prompt "Workflow illustration: step 1 <X>, step 2 <Y>, step 3 <Z>. Numbered left-to-right flow with annotated arrows." --out docs/workflow.png`

For reference-conditioned remixes (e.g., "restyle this existing logo as ukiyo-e"), add `--ref /absolute/path/to/reference.png`.
For reference-conditioned remixes (e.g., "restyle this existing logo as ukiyo-e"), also pass `--ref /absolute/path/to/reference.png`.

After each call:
1. Confirm the output file exists at the `--out` path.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,24 +130,13 @@ For each section:

If the user said yes in Step 3, invoke the **gpt-image-2** skill — once per visual. See SKILL.md "Image Generation" and Create.md Step 5 for the full pattern.

```bash
# Architecture diagram
bash scripts/gen.sh \
--prompt "Architecture diagram for <project>. <ComponentA> connects to <ComponentB> via <ComponentC>. Excalidraw / hand-drawn style. Clear labels on each node." \
--out docs/architecture.png

# Workflow illustration
bash scripts/gen.sh \
--prompt "Workflow illustration: step 1 <X>, step 2 <Y>, step 3 <Z>. Numbered left-to-right flow with annotated arrows." \
--out docs/workflow.png

# Comparison visual (if applicable)
bash scripts/gen.sh \
--prompt "Side-by-side comparison: '<A>' vs '<B>'. Two columns, contrasting treatment, clear winner indicated." \
--out docs/comparison.png
```
Invoke the installed gpt-image-2 skill (do not try to locate or run its script yourself):

- Architecture diagram: `--prompt "Architecture diagram for <project>. <ComponentA> connects to <ComponentB> via <ComponentC>. Excalidraw / hand-drawn style. Clear labels on each node." --out docs/architecture.png`
- Workflow illustration: `--prompt "Workflow illustration: step 1 <X>, step 2 <Y>, step 3 <Z>. Numbered left-to-right flow with annotated arrows." --out docs/workflow.png`
- Comparison visual (if applicable): `--prompt "Side-by-side comparison: '<A>' vs '<B>'. Two columns, contrasting treatment, clear winner indicated." --out docs/comparison.png`

Pass the user's prompt through raw — only polish wording when they explicitly asked for it. Reference each output in the README with descriptive alt text. If `gen.sh` fails, name the failing layer in one sentence and ask the user how to proceed; do not silently fall back to a weaker model.
Pass the user's prompt through raw. Only polish wording when they explicitly asked for it. Reference each output in the README with descriptive alt text. If image generation fails, name the failing layer in one sentence and ask the user how to proceed; do not silently fall back to a weaker model.

## Step 8: Validate and Deliver

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ For each artifact, score `✅ Present / ⚠️ Partial / ❌ Missing` with concr
2. **Rules directory** — per-domain coding standards in `rules/`, `.cursor/rules/`, `docs/rules/`, `docs/solutions/`, etc. Imperative rules with reasoning. For repos with exported APIs, this includes an API documentation policy or ADR.
3. **Lint config with rich error messages** — ESLint / Biome / SwiftLint / ruff / clippy with custom rules whose messages explain why and how to fix.
4. **Pre-commit hooks** — Husky / lefthook / pre-commit / native git hooks running formatters, type checks, or targeted tests before push/commit.
5. **Test suite agents can drive** — one-liner to run tests (`npm test`, `./scripts/test.sh`, `cargo test`, etc.). Fast enough and deterministic enough for agents.
5. **Test suite agents can drive**: one-liner to run tests (`npm test`, `make test`, `cargo test`, etc.). Fast enough and deterministic enough for agents.
6. **PR review automation** — CodeRabbit, AI reviewer workflows, persona reviewers, or at minimum CI that gates PRs.
7. **Repo-scoped skills/prompts** — `.agents/skills/`, `.pi/skills/`, `.claude/skills/`, `.codex/`, `.pi/prompts/`, or package-scoped resources. Prefer 5-10 deep resources over many shallow ones.
8. **Garbage-collection cadence** — documented recurring loop that converts agent/PR feedback into permanent rules, lints, docs, or skills.
Expand Down
3 changes: 2 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
]
},
"scripts": {
"check": "npm run lint && npm run typecheck && npm test && npm run validate:plugins && npm run validate:skills && node scripts/list-resources.mjs",
"check": "npm run lint && npm run typecheck && npm test && npm run validate:plugins && node scripts/validate-package-contents.mjs && npm run validate:skills && node scripts/list-resources.mjs",
"list": "node scripts/list-resources.mjs",
"validate:plugins": "node scripts/validate-plugin-ports.mjs && node scripts/validate-codex-plugins.mjs",
"install:bash-guard:global": "node scripts/install-bash-guard-global.mjs",
Expand All @@ -53,7 +53,7 @@
"lint": "biome lint .",
"lint:fix": "biome check --write .",
"prepare": "husky",
"test": "node extensions/autopilot/v2-smoke-test.mjs && node extensions/question/question-smoke-test.mjs && node extensions/conditional-hooks/smoke-test.mjs && python3 skills/diataxis-docs-site/tests/test_create_site.py && node scripts/validate-package-contents.mjs",
"test": "node extensions/autopilot/v2-smoke-test.mjs && node extensions/question/question-smoke-test.mjs && node extensions/conditional-hooks/smoke-test.mjs && node scripts/lib/frontmatter-test.mjs && node scripts/lib/bundle-refs-test.mjs && python3 skills/diataxis-docs-site/tests/test_create_site.py",
"typecheck": "tsc --noEmit",
"validate:skills": "node scripts/validate-agent-skills.mjs"
},
Expand All @@ -74,7 +74,8 @@
"husky": "9.1.7",
"lint-staged": "16.4.0",
"typebox": "latest",
"typescript": "latest"
"typescript": "latest",
"yaml": "^2.8.2"
},
"engines": {
"node": ">=20"
Expand Down
163 changes: 163 additions & 0 deletions scripts/lib/bundle-refs-test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
import assert from "node:assert/strict";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { checkReferenceOnDisk } from "../validate-plugin-ports.mjs";
import { extractBundleReferences, resolveBundleReference } from "./bundle-refs.mjs";

const SUBDIRS = ["workflows", "references", "tools", "scripts", "cli", "assets", "hooks"];
const EXTENSIONS = [
"md",
"ts",
"tsx",
"sh",
"json",
"js",
"mjs",
"cjs",
"py",
"png",
"jpg",
"jpeg",
"gif",
"svg",
"webp",
];
function extract(text) {
return extractBundleReferences(text, { subdirs: SUBDIRS, extensions: EXTENSIONS });
}

// --- extractBundleReferences: token boundaries and asset coverage --------

{
// A production-realistic image reference must actually be extracted — the
// prior REF_EXT list excluded image extensions entirely, so this never
// reached resolveBundleReference at all regardless of what it returned.
const refs = extract("See `assets/missing-logo.png` for the logo.");
assert.equal(refs.length, 1);
assert.deepEqual(refs[0], { prefixed: false, pathPart: "assets/missing-logo.png", ref: "assets/missing-logo.png" });
}

{
// A reference embedded mid-path, preceded by a word/path character, must
// not "resync" and match as if it started a fresh token.
const refs = extract("xtools/outside.ts should never match as a bare reference");
assert.equal(refs.length, 0, "mid-identifier text must not match");
}

{
// The exact adversarial case from the review: a ${CLAUDE_PLUGIN_ROOT}/../
// reference must keep its traversal prefix attached to the captured
// pathPart, not get reinterpreted as the bare tail `tools/outside.ts`.
// biome-ignore lint/suspicious/noTemplateCurlyInString: literal "${CLAUDE_PLUGIN_ROOT}" placeholder text, not a JS template
const refs = extract("Run ${CLAUDE_PLUGIN_ROOT}/../tools/outside.ts now.");
assert.equal(refs.length, 1, "must extract exactly one reference, not a bare-tail duplicate");
assert.deepEqual(refs[0], {
prefixed: true,
pathPart: "../tools/outside.ts",
// biome-ignore lint/suspicious/noTemplateCurlyInString: literal "${CLAUDE_PLUGIN_ROOT}" placeholder text, not a JS template
ref: "${CLAUDE_PLUGIN_ROOT}/../tools/outside.ts",
});
}

// --- resolveBundleReference: pure lexical containment (no filesystem) ----

{
const result = resolveBundleReference("/tmp/base", "scripts/gen.sh");
assert.equal(result.ok, true);
assert.equal(result.resolved, path.join("/tmp/base", "scripts", "gen.sh"));
}

{
// A lone "." (current-dir) segment is a safe no-op and must be accepted,
// not rejected as traversal.
const result = resolveBundleReference("/tmp/base", "scripts/./gen.sh");
assert.equal(result.ok, true, "scripts/./gen.sh must not be treated as traversal");
}

for (const pathPart of ["scripts/../../secret/outside.md", "../../secret/outside.md", "../tools/outside.ts"]) {
const result = resolveBundleReference("/tmp/base", pathPart);
assert.equal(result.ok, false, `${pathPart}: expected not ok`);
assert.equal(result.reason, "traversal", `${pathPart}: expected reason "traversal"`);
}

// --- checkReferenceOnDisk: filesystem boundary (existence, regular-file,
// symlink containment) lives at the validator, not in the pure lib ---------

const tmp = fs.mkdtempSync(path.join(os.tmpdir(), "bundle-refs-"));
const base = path.join(tmp, "skills", "fixture-plugin");
fs.mkdirSync(path.join(base, "scripts"), { recursive: true });
fs.mkdirSync(path.join(base, "tools"), { recursive: true });
fs.writeFileSync(path.join(base, "scripts", "gen.sh"), "#!/bin/sh\necho ok\n");
// A directory whose name matches the reference vocabulary + extension
// pattern (e.g. a stray "tool.ts" directory) must not pass as a file.
fs.mkdirSync(path.join(base, "tools", "tool.ts"), { recursive: true });
// A real file planted at the *bare* traversal-tail location, to prove the
// adversarial same-named-file case: even though tools/outside.ts genuinely
// exists inside the bundle, a reference that actually reads
// ${CLAUDE_PLUGIN_ROOT}/../tools/outside.ts must still be rejected as
// traversal — it must never be matched against this coincidental file.
fs.writeFileSync(path.join(base, "tools", "outside.ts"), "// decoy, must never be reached via traversal\n");
fs.mkdirSync(path.join(tmp, "secret"), { recursive: true });
fs.writeFileSync(path.join(tmp, "secret", "real-target.md"), "should never be reachable\n");
fs.symlinkSync(path.join(tmp, "secret", "real-target.md"), path.join(base, "scripts", "escape-link.md"));
fs.symlinkSync(path.join(base, "scripts", "gen.sh"), path.join(base, "scripts", "safe-link.sh"));

{
// missing: lexically contained, no file on disk.
const resolved = path.join(base, "assets", "missing-logo.png");
assert.equal(checkReferenceOnDisk(base, resolved).reason, "missing");
}

{
// not-a-file: a directory sitting at the exact reference path.
const resolved = path.join(base, "tools", "tool.ts");
assert.equal(checkReferenceOnDisk(base, resolved).reason, "not-a-file");
}

{
// symlink-escape: the reference's own path is inside the bundle, but it
// points at a real target outside it.
const resolved = path.join(base, "scripts", "escape-link.md");
assert.equal(checkReferenceOnDisk(base, resolved).reason, "symlink-escape");
}

{
// A symlink whose target stays inside the bundle is a legitimate file.
const resolved = path.join(base, "scripts", "safe-link.sh");
assert.equal(checkReferenceOnDisk(base, resolved).reason, "ok");
}

{
// A genuine in-bundle file.
const resolved = path.join(base, "scripts", "gen.sh");
assert.equal(checkReferenceOnDisk(base, resolved).reason, "ok");
}

// --- End-to-end: extractor -> resolver -> on-disk check, chained exactly
// the way validate-plugin-ports.mjs's checkSkillReferences runs them -------

function validateReference(skillMdText, pluginBase) {
const [entry] = extract(skillMdText);
assert.ok(entry, "expected exactly one extracted reference");
const lexical = resolveBundleReference(pluginBase, entry.pathPart);
if (!lexical.ok) return lexical.reason;
return checkReferenceOnDisk(pluginBase, lexical.resolved).reason;
}

assert.equal(
validateReference("See `assets/missing-logo.png` for the logo.", base),
"missing",
"production pipeline must flag a missing PNG asset reference",
);

assert.equal(
// biome-ignore lint/suspicious/noTemplateCurlyInString: literal "${CLAUDE_PLUGIN_ROOT}" placeholder text, not a JS template
validateReference("Run ${CLAUDE_PLUGIN_ROOT}/../tools/outside.ts now.", base),
"traversal",
"production pipeline must reject the traversal reference even though tools/outside.ts genuinely exists in the bundle",
);

fs.rmSync(tmp, { recursive: true, force: true });

console.log("bundle reference resolution fixtures passed");
Loading
Loading