@givolt/i3-composer-agent 0.0.0-stage → 0.6.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/plugins/marketplace.json +22 -0
- package/.claude/commands/build.md +44 -0
- package/.claude/commands/code-simplify.md +22 -0
- package/.claude/commands/constraints.md +32 -0
- package/.claude/commands/plan.md +18 -0
- package/.claude/commands/review.md +16 -0
- package/.claude/commands/ship.md +72 -0
- package/.claude/commands/spec.md +17 -0
- package/.claude/commands/test.md +19 -0
- package/.claude/commands/webperf.md +32 -0
- package/.claude-plugin/marketplace.json +26 -0
- package/.claude-plugin/plugin.json +17 -0
- package/.codex-plugin/plugin.json +26 -0
- package/.gemini/commands/build.toml +43 -0
- package/.gemini/commands/code-simplify.toml +22 -0
- package/.gemini/commands/constraints.toml +32 -0
- package/.gemini/commands/planning.toml +18 -0
- package/.gemini/commands/review.toml +16 -0
- package/.gemini/commands/ship.toml +72 -0
- package/.gemini/commands/spec.toml +17 -0
- package/.gemini/commands/test.toml +19 -0
- package/.gemini/commands/webperf.toml +32 -0
- package/LICENSE +21 -0
- package/NOTICE.md +9 -0
- package/README.md +177 -2
- package/agents/code-reviewer.md +102 -0
- package/agents/security-auditor.md +112 -0
- package/agents/test-engineer.md +95 -0
- package/agents/web-performance-auditor.md +184 -0
- package/bin/i3-composer-agent.cjs +119 -0
- package/commands/build.toml +43 -0
- package/commands/code-simplify.toml +22 -0
- package/commands/constraints.toml +32 -0
- package/commands/planning.toml +18 -0
- package/commands/review.toml +16 -0
- package/commands/ship.toml +72 -0
- package/commands/spec.toml +17 -0
- package/commands/test.toml +19 -0
- package/commands/webperf.toml +32 -0
- package/docs/adoption-guide.md +129 -0
- package/docs/advanced-per-agent-configuration.md +70 -0
- package/docs/agents.md +123 -0
- package/docs/antigravity-setup.md +128 -0
- package/docs/codebuddy-setup.md +41 -0
- package/docs/codex-setup.md +34 -0
- package/docs/commandcode-setup.md +69 -0
- package/docs/comparison.md +131 -0
- package/docs/copilot-cli-setup.md +64 -0
- package/docs/copilot-setup.md +162 -0
- package/docs/cursor-setup.md +225 -0
- package/docs/developer-onboarding.md +116 -0
- package/docs/gemini-cli-setup.md +133 -0
- package/docs/getting-started.md +208 -0
- package/docs/opencode-setup.md +259 -0
- package/docs/other-hosts.md +7 -0
- package/docs/skill-anatomy.md +203 -0
- package/docs/windsurf-setup.md +48 -0
- package/evals/README.md +101 -0
- package/evals/cases/api-and-interface-design.json +45 -0
- package/evals/cases/browser-testing-with-devtools.json +44 -0
- package/evals/cases/ci-cd-and-automation.json +45 -0
- package/evals/cases/code-review-and-quality.json +49 -0
- package/evals/cases/code-simplification.json +45 -0
- package/evals/cases/constraint-driven-development.json +79 -0
- package/evals/cases/context-engineering.json +44 -0
- package/evals/cases/debugging-and-error-recovery.json +58 -0
- package/evals/cases/deprecation-and-migration.json +52 -0
- package/evals/cases/documentation-and-adrs.json +44 -0
- package/evals/cases/doubt-driven-development.json +43 -0
- package/evals/cases/frontend-ui-engineering.json +52 -0
- package/evals/cases/git-workflow-and-versioning.json +47 -0
- package/evals/cases/idea-refine.json +43 -0
- package/evals/cases/incremental-implementation.json +57 -0
- package/evals/cases/interview-me.json +42 -0
- package/evals/cases/observability-and-instrumentation.json +44 -0
- package/evals/cases/performance-optimization.json +53 -0
- package/evals/cases/planning-and-task-breakdown.json +45 -0
- package/evals/cases/security-and-hardening.json +53 -0
- package/evals/cases/shipping-and-launch.json +56 -0
- package/evals/cases/source-driven-development.json +44 -0
- package/evals/cases/spec-driven-development.json +72 -0
- package/evals/cases/test-driven-development.json +73 -0
- package/evals/cases/using-agent-skills.json +44 -0
- package/evals/fixtures/api-and-interface-design/service-brief.md +19 -0
- package/evals/fixtures/browser-testing-with-devtools/README.md +5 -0
- package/evals/fixtures/browser-testing-with-devtools/index.html +24 -0
- package/evals/fixtures/browser-testing-with-devtools/server.js +15 -0
- package/evals/fixtures/ci-cd-and-automation/package.json +8 -0
- package/evals/fixtures/ci-cd-and-automation/src/slug.js +3 -0
- package/evals/fixtures/ci-cd-and-automation/test/slug.test.js +9 -0
- package/evals/fixtures/code-review-and-quality/user-search.diff +16 -0
- package/evals/fixtures/code-simplification/config-parser.js +46 -0
- package/evals/fixtures/code-simplification/config-parser.test.js +15 -0
- package/evals/fixtures/context-engineering/context-audit.md +15 -0
- package/evals/fixtures/debugging-and-error-recovery/pagination.js +8 -0
- package/evals/fixtures/debugging-and-error-recovery/pagination.test.js +9 -0
- package/evals/fixtures/debugging-and-error-recovery/time-pressure.md +6 -0
- package/evals/fixtures/deprecation-and-migration/api-inventory.md +9 -0
- package/evals/fixtures/documentation-and-adrs/decision-context.md +16 -0
- package/evals/fixtures/doubt-driven-development/migration-plan.md +19 -0
- package/evals/fixtures/frontend-ui-engineering/Button.tsx +7 -0
- package/evals/fixtures/frontend-ui-engineering/design-system.md +11 -0
- package/evals/fixtures/git-workflow-and-versioning/.eval/working-tree.patch +21 -0
- package/evals/fixtures/git-workflow-and-versioning/app.js +7 -0
- package/evals/fixtures/git-workflow-and-versioning/app.test.js +9 -0
- package/evals/fixtures/incremental-implementation/reports.js +7 -0
- package/evals/fixtures/incremental-implementation/reports.test.js +12 -0
- package/evals/fixtures/incremental-implementation/tasks/plan.md +8 -0
- package/evals/fixtures/incremental-implementation-pressure/draft-export.js +17 -0
- package/evals/fixtures/incremental-implementation-pressure/scenario.md +9 -0
- package/evals/fixtures/observability-and-instrumentation/operations.md +11 -0
- package/evals/fixtures/observability-and-instrumentation/payment-retry.js +14 -0
- package/evals/fixtures/performance-optimization/benchmark.js +15 -0
- package/evals/fixtures/performance-optimization/products.js +14 -0
- package/evals/fixtures/planning-and-task-breakdown/notifications-spec.md +18 -0
- package/evals/fixtures/security-and-hardening/webhook.js +11 -0
- package/evals/fixtures/security-and-hardening/webhook.test.js +13 -0
- package/evals/fixtures/shipping-and-launch/authority-pressure.md +6 -0
- package/evals/fixtures/shipping-and-launch/launch-status.md +11 -0
- package/evals/fixtures/source-driven-development/framework-task.md +10 -0
- package/evals/fixtures/spec-driven-development/billing-brief.md +16 -0
- package/evals/fixtures/spec-driven-development-decomposition/portal-brief.md +22 -0
- package/evals/fixtures/test-driven-development/BUG.md +10 -0
- package/evals/fixtures/test-driven-development/README.md +28 -0
- package/evals/fixtures/test-driven-development/package.json +9 -0
- package/evals/fixtures/test-driven-development/src/split.js +8 -0
- package/evals/fixtures/test-driven-development/test/split.test.js +13 -0
- package/evals/fixtures/test-driven-development-ecosystem/README.md +9 -0
- package/evals/fixtures/test-driven-development-ecosystem/ledger.py +15 -0
- package/evals/fixtures/test-driven-development-ecosystem/test_ledger.py +19 -0
- package/evals/fixtures/using-agent-skills/incident.md +6 -0
- package/evals/plugin/code-review-fires/graders/off-by-one.md +7 -0
- package/evals/plugin/code-review-fires/graders/severity-labels.md +4 -0
- package/evals/plugin/code-review-fires/graders/skill-fired.md +5 -0
- package/evals/plugin/code-review-fires/prompt.md +31 -0
- package/evals/plugin/code-review-stays-quiet/graders/not-fired.md +8 -0
- package/evals/plugin/code-review-stays-quiet/graders/tdd-fired.md +6 -0
- package/evals/plugin/code-review-stays-quiet/prompt.md +8 -0
- package/evals/plugin/code-review-stays-quiet-on-commit-message/graders/not-fired.md +8 -0
- package/evals/plugin/code-review-stays-quiet-on-commit-message/prompt.md +25 -0
- package/evals/skill-impact.md +6 -0
- package/hooks/SDD-CACHE.md +167 -0
- package/hooks/SIMPLIFY-IGNORE.md +91 -0
- package/hooks/sdd-cache-post.sh +135 -0
- package/hooks/sdd-cache-pre.sh +106 -0
- package/hooks/sdd-cache-test.sh +246 -0
- package/hooks/session-start-test.sh +47 -0
- package/hooks/session-start.sh +33 -0
- package/hooks/simplify-ignore-test.sh +476 -0
- package/hooks/simplify-ignore.sh +352 -0
- package/package.json +31 -4
- package/plugin.json +5 -0
- package/rebrand/MAINTENANCE.md +51 -0
- package/rebrand/apply.cjs +121 -0
- package/rebrand/brand.json +9 -0
- package/rebrand/templates/README.md +178 -0
- package/rebrand/templates/codebuddy-setup.md +41 -0
- package/rebrand/templates/codex-setup.md +34 -0
- package/references/accessibility-checklist.md +160 -0
- package/references/definition-of-done.md +67 -0
- package/references/observability-checklist.md +92 -0
- package/references/orchestration-patterns.md +370 -0
- package/references/performance-checklist.md +236 -0
- package/references/security-checklist.md +248 -0
- package/references/testing-patterns.md +235 -0
- package/scripts/floor-guard-reference-test.js +291 -0
- package/scripts/lib/skill-lint-test.js +650 -0
- package/scripts/lib/skill-lint.js +584 -0
- package/scripts/run-evals-test.js +623 -0
- package/scripts/run-evals.js +638 -0
- package/scripts/validate-artifact-paths-test.js +179 -0
- package/scripts/validate-artifact-paths.js +128 -0
- package/scripts/validate-brand.cjs +36 -0
- package/scripts/validate-commands-test.js +216 -0
- package/scripts/validate-commands.js +222 -0
- package/scripts/validate-reference-links-test.js +495 -0
- package/scripts/validate-reference-links.js +187 -0
- package/scripts/validate-skills.js +69 -0
- package/scripts/validate-versions-test.js +32 -0
- package/scripts/validate-versions.js +35 -0
- package/skills/api-and-interface-design/SKILL.md +367 -0
- package/skills/browser-testing-with-devtools/SKILL.md +317 -0
- package/skills/ci-cd-and-automation/SKILL.md +390 -0
- package/skills/code-review-and-quality/SKILL.md +398 -0
- package/skills/code-simplification/SKILL.md +331 -0
- package/skills/constraint-driven-development/SKILL.md +311 -0
- package/skills/constraint-driven-development/references/floor-guard.md +182 -0
- package/skills/context-engineering/SKILL.md +353 -0
- package/skills/debugging-and-error-recovery/SKILL.md +300 -0
- package/skills/deprecation-and-migration/SKILL.md +247 -0
- package/skills/documentation-and-adrs/SKILL.md +288 -0
- package/skills/doubt-driven-development/SKILL.md +243 -0
- package/skills/frontend-ui-engineering/SKILL.md +340 -0
- package/skills/git-workflow-and-versioning/SKILL.md +355 -0
- package/skills/idea-refine/SKILL.md +178 -0
- package/skills/idea-refine/examples.md +238 -0
- package/skills/idea-refine/frameworks.md +99 -0
- package/skills/idea-refine/refinement-criteria.md +113 -0
- package/skills/idea-refine/scripts/idea-refine.sh +15 -0
- package/skills/incremental-implementation/SKILL.md +249 -0
- package/skills/interview-me/SKILL.md +235 -0
- package/skills/observability-and-instrumentation/SKILL.md +238 -0
- package/skills/performance-optimization/SKILL.md +267 -0
- package/skills/performance-optimization/references/optimization-patterns.md +250 -0
- package/skills/planning-and-task-breakdown/SKILL.md +257 -0
- package/skills/security-and-hardening/SKILL.md +216 -0
- package/skills/security-and-hardening/references/hardening-patterns.md +324 -0
- package/skills/shipping-and-launch/SKILL.md +330 -0
- package/skills/source-driven-development/SKILL.md +216 -0
- package/skills/spec-driven-development/SKILL.md +259 -0
- package/skills/test-driven-development/SKILL.md +398 -0
- package/skills/using-agent-skills/SKILL.md +192 -0
- package/tests/bundle.test.cjs +79 -0
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# simplify-ignore.sh — Hook for Read (PreToolUse), Edit|Write (PostToolUse), Stop
|
|
3
|
+
#
|
|
4
|
+
# PreToolUse Read → backs up file, replaces blocks with BLOCK_<hash> in-place
|
|
5
|
+
# PostToolUse Edit → expands placeholders, re-filters so file stays hidden
|
|
6
|
+
# PostToolUse Write → expands placeholders, re-filters so file stays hidden
|
|
7
|
+
# Stop → expands the placeholders still in the file on disk, so a
|
|
8
|
+
# change made by any route survives; the backup is used
|
|
9
|
+
# only when no placeholder is left to expand
|
|
10
|
+
#
|
|
11
|
+
# The file on disk ALWAYS has placeholders while the session is active.
|
|
12
|
+
# The real content is that file with its placeholders expanded; the backup
|
|
13
|
+
# holds the last state the hook itself saw.
|
|
14
|
+
#
|
|
15
|
+
# Dependencies: jq, shasum or sha1sum (auto-detected)
|
|
16
|
+
|
|
17
|
+
set -euo pipefail
|
|
18
|
+
|
|
19
|
+
# Bash 5.2+ turns on patsub_replacement by default, which makes `&` and
|
|
20
|
+
# backslash special on the replacement side of ${var//pattern/replacement}:
|
|
21
|
+
# `&` expands to the matched text and `\\` collapses. expand_file substitutes
|
|
22
|
+
# raw block content there, and code routinely contains `&&` and backslashes,
|
|
23
|
+
# so the option must be off or protected blocks come back corrupted on Linux.
|
|
24
|
+
# Older bashes do not know the option; ignore the error there.
|
|
25
|
+
shopt -u patsub_replacement 2>/dev/null || true
|
|
26
|
+
|
|
27
|
+
if ! command -v jq >/dev/null 2>&1; then
|
|
28
|
+
printf '%s\n' "error: missing jq" >&2; exit 1
|
|
29
|
+
fi
|
|
30
|
+
|
|
31
|
+
CACHE="${CLAUDE_PROJECT_DIR:-.}/.claude/.simplify-ignore-cache"
|
|
32
|
+
if [ -t 0 ]; then INPUT="{}"; else INPUT=$(cat); fi
|
|
33
|
+
|
|
34
|
+
# Parse hook input — trap errors explicitly so set -e doesn't cause
|
|
35
|
+
# a silent exit on malformed JSON, and surface a useful diagnostic.
|
|
36
|
+
parse_error=""
|
|
37
|
+
TOOL_NAME=$(printf '%s' "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null) || {
|
|
38
|
+
parse_error="failed to parse .tool_name from hook input"
|
|
39
|
+
TOOL_NAME=""
|
|
40
|
+
}
|
|
41
|
+
FILE_PATH=$(printf '%s' "$INPUT" | jq -r '.tool_input.file_path // empty' 2>/dev/null) || {
|
|
42
|
+
parse_error="failed to parse .tool_input.file_path from hook input"
|
|
43
|
+
FILE_PATH=""
|
|
44
|
+
}
|
|
45
|
+
if [ -n "$parse_error" ]; then
|
|
46
|
+
printf 'Warning: %s (input: %.120s)\n' "$parse_error" "$INPUT" >&2
|
|
47
|
+
fi
|
|
48
|
+
|
|
49
|
+
hash_cmd() {
|
|
50
|
+
if command -v shasum >/dev/null 2>&1; then shasum
|
|
51
|
+
elif command -v sha1sum >/dev/null 2>&1; then sha1sum
|
|
52
|
+
else printf '%s\n' "error: missing shasum or sha1sum" >&2; exit 1; fi
|
|
53
|
+
}
|
|
54
|
+
file_id() { printf '%s' "$1" | hash_cmd | cut -c1-16; }
|
|
55
|
+
block_hash() { printf '%s' "$1" | hash_cmd | cut -c1-8; }
|
|
56
|
+
# Escape glob metacharacters so ${var/pattern/repl} treats pattern as literal.
|
|
57
|
+
# Needed for Bash 3.2 (macOS) where quotes don't suppress globbing in PE patterns.
|
|
58
|
+
escape_glob() {
|
|
59
|
+
local s="$1"
|
|
60
|
+
s="${s//\\/\\\\}"
|
|
61
|
+
s="${s//\*/\\*}"
|
|
62
|
+
s="${s//\?/\\?}"
|
|
63
|
+
s="${s//\[/\\[}"
|
|
64
|
+
printf '%s' "$s"
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
# ── filter_file: replace simplify-ignore blocks with BLOCK_<hash> placeholders ─
|
|
68
|
+
# Reads $1 (source), writes filtered version to $2 (dest), saves blocks to cache.
|
|
69
|
+
# Returns 0 if blocks were found, 1 if none.
|
|
70
|
+
filter_file() {
|
|
71
|
+
local src="$1" dest="$2" fid="$3"
|
|
72
|
+
: > "$dest"
|
|
73
|
+
rm -f "$CACHE/${fid}".block.* "$CACHE/${fid}".reason.* "$CACHE/${fid}".prefix.* "$CACHE/${fid}".suffix.*
|
|
74
|
+
|
|
75
|
+
local count=0 in_block=0 buf="" reason="" prefix="" suffix=""
|
|
76
|
+
|
|
77
|
+
while IFS= read -r line || [ -n "$line" ]; do
|
|
78
|
+
# Check for start marker (no fork — uses bash case)
|
|
79
|
+
if [ $in_block -eq 0 ]; then
|
|
80
|
+
case "$line" in *simplify-ignore-start*)
|
|
81
|
+
in_block=1
|
|
82
|
+
buf="$line"
|
|
83
|
+
# Extract comment prefix/suffix to preserve language-appropriate syntax
|
|
84
|
+
prefix="${line%%simplify-ignore-start*}"
|
|
85
|
+
suffix=""
|
|
86
|
+
case "$line" in *'*/'*) suffix=" */" ;; *'-->'*) suffix=" -->" ;; esac
|
|
87
|
+
reason=$(printf '%s' "$line" | sed -n 's/.*simplify-ignore-start:[[:space:]]*//p' \
|
|
88
|
+
| sed 's/[[:space:]]*\*\/.*$//' | sed 's/[[:space:]]*-->.*$//' | sed 's/[[:space:]]*$//')
|
|
89
|
+
# Handle single-line block (start + end on same line)
|
|
90
|
+
case "$line" in *simplify-ignore-end*)
|
|
91
|
+
in_block=0
|
|
92
|
+
# Write single-line block immediately and skip to next line
|
|
93
|
+
# to avoid the end-marker check below firing again
|
|
94
|
+
local h; h=$(block_hash "$buf")
|
|
95
|
+
count=$((count + 1))
|
|
96
|
+
printf '%s' "$buf" > "$CACHE/${fid}.block.${h}"
|
|
97
|
+
[ -n "$reason" ] && printf '%s' "$reason" > "$CACHE/${fid}.reason.${h}"
|
|
98
|
+
printf '%s' "$prefix" > "$CACHE/${fid}.prefix.${h}"
|
|
99
|
+
printf '%s' "$suffix" > "$CACHE/${fid}.suffix.${h}"
|
|
100
|
+
if [ -n "$reason" ]; then
|
|
101
|
+
printf '%s\n' "${prefix}BLOCK_${h}: ${reason}${suffix}" >> "$dest"
|
|
102
|
+
else
|
|
103
|
+
printf '%s\n' "${prefix}BLOCK_${h}${suffix}" >> "$dest"
|
|
104
|
+
fi
|
|
105
|
+
buf=""; reason=""; prefix=""; suffix=""
|
|
106
|
+
continue
|
|
107
|
+
;; *)
|
|
108
|
+
continue
|
|
109
|
+
;;
|
|
110
|
+
esac
|
|
111
|
+
;; esac
|
|
112
|
+
fi
|
|
113
|
+
# Accumulate block content
|
|
114
|
+
if [ $in_block -eq 1 ]; then
|
|
115
|
+
buf="${buf}
|
|
116
|
+
${line}"
|
|
117
|
+
fi
|
|
118
|
+
# Check for end marker
|
|
119
|
+
case "$line" in *simplify-ignore-end*)
|
|
120
|
+
if [ $in_block -eq 1 ]; then
|
|
121
|
+
local h; h=$(block_hash "$buf")
|
|
122
|
+
count=$((count + 1))
|
|
123
|
+
printf '%s' "$buf" > "$CACHE/${fid}.block.${h}"
|
|
124
|
+
[ -n "$reason" ] && printf '%s' "$reason" > "$CACHE/${fid}.reason.${h}"
|
|
125
|
+
printf '%s' "$prefix" > "$CACHE/${fid}.prefix.${h}"
|
|
126
|
+
printf '%s' "$suffix" > "$CACHE/${fid}.suffix.${h}"
|
|
127
|
+
if [ -n "$reason" ]; then
|
|
128
|
+
printf '%s\n' "${prefix}BLOCK_${h}: ${reason}${suffix}" >> "$dest"
|
|
129
|
+
else
|
|
130
|
+
printf '%s\n' "${prefix}BLOCK_${h}${suffix}" >> "$dest"
|
|
131
|
+
fi
|
|
132
|
+
in_block=0; buf=""; reason=""; prefix=""; suffix=""
|
|
133
|
+
continue
|
|
134
|
+
fi
|
|
135
|
+
;;
|
|
136
|
+
esac
|
|
137
|
+
[ $in_block -eq 0 ] && printf '%s\n' "$line" >> "$dest"
|
|
138
|
+
done < "$src"
|
|
139
|
+
|
|
140
|
+
# Unclosed block → flush as-is
|
|
141
|
+
if [ $in_block -eq 1 ] && [ -n "$buf" ]; then
|
|
142
|
+
printf 'Warning: unclosed simplify-ignore-start in %s (block not hidden)\n' "$src" >&2
|
|
143
|
+
printf '%s\n' "$buf" >> "$dest"
|
|
144
|
+
fi
|
|
145
|
+
|
|
146
|
+
# Preserve trailing newline status of source
|
|
147
|
+
if [ -s "$dest" ] && [ -s "$src" ] && [ -n "$(tail -c 1 "$src")" ]; then
|
|
148
|
+
perl -pe 'chomp if eof' "$dest" > "${dest}.nnl" && \
|
|
149
|
+
cat "${dest}.nnl" > "$dest" && rm -f "${dest}.nnl"
|
|
150
|
+
fi
|
|
151
|
+
|
|
152
|
+
[ $count -gt 0 ] && return 0 || return 1
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
# ── expand_file: replace BLOCK_<hash> placeholders with the real block code ───
|
|
156
|
+
# Reads $1 (source), writes the expanded version to $2 (dest), using the blocks
|
|
157
|
+
# cached under $3 (file id). Warns on placeholders that were altered or deleted.
|
|
158
|
+
expand_file() {
|
|
159
|
+
local src="$1" dest="$2" fid="$3"
|
|
160
|
+
local line bf h bp bs br placeholder block_content esc_placeholder esc_fuzzy bh first_line
|
|
161
|
+
rm -f "$dest"
|
|
162
|
+
while IFS= read -r line || [ -n "$line" ]; do
|
|
163
|
+
case "$line" in *BLOCK_*)
|
|
164
|
+
# Expand all placeholders on this line (supports multiple per line)
|
|
165
|
+
for bf in "$CACHE/${fid}".block.*; do
|
|
166
|
+
[ -f "$bf" ] || continue
|
|
167
|
+
h="${bf##*.}"
|
|
168
|
+
case "$line" in *"BLOCK_${h}"*)
|
|
169
|
+
# Reconstruct the exact placeholder pattern
|
|
170
|
+
bp=""; bs=""; br=""
|
|
171
|
+
[ -f "$CACHE/${fid}.prefix.${h}" ] && bp=$(cat "$CACHE/${fid}.prefix.${h}")
|
|
172
|
+
[ -f "$CACHE/${fid}.suffix.${h}" ] && bs=$(cat "$CACHE/${fid}.suffix.${h}")
|
|
173
|
+
[ -f "$CACHE/${fid}.reason.${h}" ] && br=$(cat "$CACHE/${fid}.reason.${h}")
|
|
174
|
+
if [ -n "$br" ]; then
|
|
175
|
+
placeholder="${bp}BLOCK_${h}: ${br}${bs}"
|
|
176
|
+
else
|
|
177
|
+
placeholder="${bp}BLOCK_${h}${bs}"
|
|
178
|
+
fi
|
|
179
|
+
block_content=$(cat "$bf"; printf x); block_content="${block_content%x}"
|
|
180
|
+
# Escape glob metacharacters (* ? [ \) in the pattern
|
|
181
|
+
esc_placeholder=$(escape_glob "$placeholder")
|
|
182
|
+
# Bash native substitution (// = global replace): replace placeholder, keep surrounding code
|
|
183
|
+
line="${line//$esc_placeholder/$block_content}"
|
|
184
|
+
# Fallback: if model altered the reason text, try without reason
|
|
185
|
+
# (only trigger if BLOCK_hash is still present AND wasn't in the original block content)
|
|
186
|
+
case "$block_content" in *"BLOCK_${h}"*) ;; *)
|
|
187
|
+
case "$line" in *"BLOCK_${h}"*)
|
|
188
|
+
printf 'Warning: placeholder BLOCK_%s was modified by model, using fuzzy match\n' "$h" >&2
|
|
189
|
+
esc_fuzzy=$(escape_glob "${bp}BLOCK_${h}${bs}")
|
|
190
|
+
line="${line//$esc_fuzzy/$block_content}"
|
|
191
|
+
# Last resort: match just the hash token
|
|
192
|
+
case "$line" in *"BLOCK_${h}"*)
|
|
193
|
+
line="${line//BLOCK_${h}/$block_content}"
|
|
194
|
+
;; esac
|
|
195
|
+
;; esac
|
|
196
|
+
;; esac
|
|
197
|
+
;; esac
|
|
198
|
+
done
|
|
199
|
+
;; esac
|
|
200
|
+
printf '%s\n' "$line" >> "$dest"
|
|
201
|
+
done < "$src"
|
|
202
|
+
# Preserve trailing newline status
|
|
203
|
+
if [ -s "$dest" ] && [ -s "$src" ] && [ -n "$(tail -c 1 "$src")" ]; then
|
|
204
|
+
perl -pe 'chomp if eof' "$dest" > "${dest}.nnl" && \
|
|
205
|
+
cat "${dest}.nnl" > "$dest" && rm -f "${dest}.nnl"
|
|
206
|
+
fi
|
|
207
|
+
# Warn if model deleted a protected block entirely
|
|
208
|
+
for bf in "$CACHE/${fid}".block.*; do
|
|
209
|
+
[ -f "$bf" ] || continue
|
|
210
|
+
bh="${bf##*.}"
|
|
211
|
+
# After expansion, blocks appear as original code (simplify-ignore-start).
|
|
212
|
+
# If neither the expanded code nor the placeholder is in EXPANDED, it was deleted.
|
|
213
|
+
if ! grep -qF "BLOCK_${bh}" "$dest" 2>/dev/null; then
|
|
214
|
+
# Get first line of block to check if it was expanded back
|
|
215
|
+
first_line=$(head -1 "$bf")
|
|
216
|
+
if ! grep -qF "$first_line" "$dest" 2>/dev/null; then
|
|
217
|
+
printf 'Warning: protected block BLOCK_%s was deleted by model\n' "$bh" >&2
|
|
218
|
+
fi
|
|
219
|
+
fi
|
|
220
|
+
done
|
|
221
|
+
return 0
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
# ── has_placeholders: is a cached BLOCK_<hash> for $2 still present in file $1? ─
|
|
225
|
+
has_placeholders() {
|
|
226
|
+
local f="$1" fid="$2" bf h
|
|
227
|
+
for bf in "$CACHE/${fid}".block.*; do
|
|
228
|
+
[ -f "$bf" ] || continue
|
|
229
|
+
h="${bf##*.}"
|
|
230
|
+
grep -qF "BLOCK_${h}" "$f" 2>/dev/null && return 0
|
|
231
|
+
done
|
|
232
|
+
return 1
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
# ── Stop: expand each cached file in place, backup only as fallback ──────────
|
|
236
|
+
if [ -z "$TOOL_NAME" ]; then
|
|
237
|
+
[ -d "$CACHE" ] || exit 0
|
|
238
|
+
for bak in "$CACHE"/*.bak; do
|
|
239
|
+
[ -f "$bak" ] || continue
|
|
240
|
+
fid="${bak##*/}"; fid="${fid%.bak}"
|
|
241
|
+
pathfile="$CACHE/${fid}.path"
|
|
242
|
+
[ -f "$pathfile" ] || { rm -f "$bak"; continue; }
|
|
243
|
+
orig=$(cat "$pathfile")
|
|
244
|
+
if [ -f "$orig" ]; then
|
|
245
|
+
# A change can reach the file through a route that fires no Edit or Write
|
|
246
|
+
# event (a Bash command, a formatter, an external editor), and the backup
|
|
247
|
+
# is stale for all of them. Expand what is on disk rather than overwrite it.
|
|
248
|
+
if has_placeholders "$orig" "$fid"; then
|
|
249
|
+
EXPANDED="$CACHE/${fid}.$$.expanded"
|
|
250
|
+
expand_file "$orig" "$EXPANDED" "$fid"
|
|
251
|
+
cat "$EXPANDED" > "$orig"
|
|
252
|
+
rm -f "$EXPANDED"
|
|
253
|
+
else
|
|
254
|
+
# Nothing left to expand — the file was rewritten wholesale, so the
|
|
255
|
+
# backup is the only remaining copy of the protected blocks. Keep the
|
|
256
|
+
# rewrite in the cache before the backup overwrites it, so the work is
|
|
257
|
+
# recoverable rather than lost.
|
|
258
|
+
rewritten="$CACHE/${fid}.recovered"
|
|
259
|
+
cat "$orig" > "$rewritten"
|
|
260
|
+
cat "$bak" > "$orig"
|
|
261
|
+
printf 'Warning: no BLOCK_ placeholder left in %s, restored from backup. Rewrite kept at %s\n' \
|
|
262
|
+
"$orig" "$rewritten" >&2
|
|
263
|
+
fi
|
|
264
|
+
rm -f "$bak" "$pathfile" "$CACHE/${fid}".block.* "$CACHE/${fid}".reason.* "$CACHE/${fid}".prefix.* "$CACHE/${fid}".suffix.*
|
|
265
|
+
rmdir "$CACHE/${fid}.lock" 2>/dev/null
|
|
266
|
+
else
|
|
267
|
+
# File was moved/deleted — save backup as .recovered, don't destroy it
|
|
268
|
+
mkdir -p "$(dirname "${orig}.recovered")"
|
|
269
|
+
mv "$bak" "${orig}.recovered"
|
|
270
|
+
rm -f "$pathfile" "$CACHE/${fid}".block.* "$CACHE/${fid}".reason.* "$CACHE/${fid}".prefix.* "$CACHE/${fid}".suffix.*
|
|
271
|
+
rmdir "$CACHE/${fid}.lock" 2>/dev/null
|
|
272
|
+
printf 'Warning: %s was moved/deleted. Recovered original to %s.recovered\n' "$orig" "$orig" >&2
|
|
273
|
+
fi
|
|
274
|
+
done
|
|
275
|
+
# Clean orphan locks (created but crash before backup)
|
|
276
|
+
for lockdir in "$CACHE"/*.lock; do
|
|
277
|
+
[ -d "$lockdir" ] || continue
|
|
278
|
+
rmdir "$lockdir" 2>/dev/null
|
|
279
|
+
done
|
|
280
|
+
exit 0
|
|
281
|
+
fi
|
|
282
|
+
|
|
283
|
+
[ -z "$FILE_PATH" ] && exit 0
|
|
284
|
+
|
|
285
|
+
# ── PreToolUse Read: filter in-place ──────────────────────────────────────────
|
|
286
|
+
if [ "$TOOL_NAME" = "Read" ]; then
|
|
287
|
+
[ -f "$FILE_PATH" ] || exit 0
|
|
288
|
+
case "$(basename "$FILE_PATH")" in simplify-ignore*|SIMPLIFY-IGNORE*) exit 0 ;; esac
|
|
289
|
+
|
|
290
|
+
mkdir -p "$CACHE"
|
|
291
|
+
ID=$(file_id "$FILE_PATH")
|
|
292
|
+
|
|
293
|
+
# If backup exists, file is already filtered — skip
|
|
294
|
+
[ -f "$CACHE/${ID}.bak" ] && exit 0
|
|
295
|
+
|
|
296
|
+
grep -q 'simplify-ignore-start' -- "$FILE_PATH" || exit 0
|
|
297
|
+
|
|
298
|
+
# Atomic lock: mkdir fails if another session races us
|
|
299
|
+
if ! mkdir "$CACHE/${ID}.lock" 2>/dev/null; then
|
|
300
|
+
# Lock exists — reclaim only if stale (>60s old, no backup = crash leftover)
|
|
301
|
+
if [ ! -f "$CACHE/${ID}.bak" ] && \
|
|
302
|
+
[ -n "$(find "$CACHE/${ID}.lock" -maxdepth 0 -mmin +1 2>/dev/null)" ]; then
|
|
303
|
+
rmdir "$CACHE/${ID}.lock" 2>/dev/null || true
|
|
304
|
+
mkdir "$CACHE/${ID}.lock" 2>/dev/null || exit 0
|
|
305
|
+
else
|
|
306
|
+
exit 0
|
|
307
|
+
fi
|
|
308
|
+
fi
|
|
309
|
+
|
|
310
|
+
# Back up the original (preserve trailing newline status)
|
|
311
|
+
cp -p "$FILE_PATH" "$CACHE/${ID}.bak" 2>/dev/null || cp "$FILE_PATH" "$CACHE/${ID}.bak"
|
|
312
|
+
printf '%s' "$FILE_PATH" > "$CACHE/${ID}.path"
|
|
313
|
+
|
|
314
|
+
# Filter in-place (cat > preserves inode and permissions)
|
|
315
|
+
FILTERED="$CACHE/${ID}.$$.tmp"
|
|
316
|
+
rm -f "$FILTERED"
|
|
317
|
+
if filter_file "$FILE_PATH" "$FILTERED" "$ID"; then
|
|
318
|
+
cat "$FILTERED" > "$FILE_PATH"
|
|
319
|
+
rm -f "$FILTERED"
|
|
320
|
+
else
|
|
321
|
+
rm -f "$FILTERED" "$CACHE/${ID}.bak" "$CACHE/${ID}.path"
|
|
322
|
+
rmdir "$CACHE/${ID}.lock" 2>/dev/null
|
|
323
|
+
fi
|
|
324
|
+
exit 0
|
|
325
|
+
fi
|
|
326
|
+
|
|
327
|
+
# ── PostToolUse Edit|Write: expand, then re-filter ────────────────────────────
|
|
328
|
+
if [ "$TOOL_NAME" = "Edit" ] || [ "$TOOL_NAME" = "Write" ]; then
|
|
329
|
+
ID=$(file_id "$FILE_PATH")
|
|
330
|
+
[ -f "$CACHE/${ID}.bak" ] || exit 0
|
|
331
|
+
ls "$CACHE/${ID}".block.* >/dev/null 2>&1 || exit 0
|
|
332
|
+
|
|
333
|
+
# Expand placeholders, preserving any inline code the model added around them
|
|
334
|
+
EXPANDED="$CACHE/${ID}.$$.expanded"
|
|
335
|
+
expand_file "$FILE_PATH" "$EXPANDED" "$ID"
|
|
336
|
+
# Preserve inode and permissions
|
|
337
|
+
cat "$EXPANDED" > "$FILE_PATH"
|
|
338
|
+
rm -f "$EXPANDED"
|
|
339
|
+
|
|
340
|
+
# Save expanded version as new backup (this is the "real" file with model's changes)
|
|
341
|
+
cp "$FILE_PATH" "$CACHE/${ID}.bak"
|
|
342
|
+
|
|
343
|
+
# Re-filter in-place so the file on disk stays with placeholders
|
|
344
|
+
FILTERED="$CACHE/${ID}.$$.tmp"
|
|
345
|
+
rm -f "$FILTERED"
|
|
346
|
+
if filter_file "$FILE_PATH" "$FILTERED" "$ID"; then
|
|
347
|
+
cat "$FILTERED" > "$FILE_PATH"
|
|
348
|
+
rm -f "$FILTERED"
|
|
349
|
+
fi
|
|
350
|
+
|
|
351
|
+
exit 0
|
|
352
|
+
fi
|
package/package.json
CHANGED
|
@@ -1,6 +1,33 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@givolt/i3-composer-agent",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.6.12",
|
|
4
|
+
"description": "i3 Composer Agent: production-grade engineering skills and lifecycle commands for AI coding agents.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "Givolt",
|
|
7
|
+
"contributors": [{ "name": "Addy Osmani" }],
|
|
8
|
+
"bin": { "i3-composer-agent": "bin/i3-composer-agent.cjs" },
|
|
9
|
+
"engines": { "node": ">=20" },
|
|
10
|
+
"publishConfig": { "access": "public", "registry": "https://registry.npmjs.org/" },
|
|
11
|
+
"files": [
|
|
12
|
+
"bin/", "skills/", "references/", "agents/", "commands/",
|
|
13
|
+
".claude/commands/", ".gemini/commands/", ".claude-plugin/",
|
|
14
|
+
".codex-plugin/", ".agents/plugins/", "hooks/", "docs/",
|
|
15
|
+
"scripts/", "evals/", "rebrand/", "tests/", "plugin.json", "NOTICE.md"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"rebrand": "node rebrand/apply.cjs --apply",
|
|
19
|
+
"rebrand:check": "node rebrand/apply.cjs --check",
|
|
20
|
+
"validate": "node scripts/validate-brand.cjs && node scripts/validate-skills.js && node scripts/validate-versions.js && node scripts/validate-commands.js && node scripts/validate-reference-links.js && node scripts/validate-artifact-paths.js",
|
|
21
|
+
"test": "node --test scripts/*-test.js scripts/lib/*-test.js tests/*.test.cjs",
|
|
22
|
+
"prepack": "npm run validate"
|
|
23
|
+
},
|
|
24
|
+
"keywords": ["i3-composer", "agent-skills", "codebuddy", "codex", "claude-code"],
|
|
25
|
+
"i3ComposerAgent": {
|
|
26
|
+
"pluginFiles": [
|
|
27
|
+
"bin", "skills", "references", "agents", "commands", ".claude/commands",
|
|
28
|
+
".gemini/commands", ".claude-plugin", ".codex-plugin", ".agents/plugins",
|
|
29
|
+
"hooks", "docs", "scripts", "evals", "rebrand", "tests", "plugin.json",
|
|
30
|
+
"package.json", "README.md", "LICENSE", "NOTICE.md"
|
|
31
|
+
]
|
|
32
|
+
}
|
|
33
|
+
}
|
package/plugin.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Maintaining i3 Composer Agent
|
|
2
|
+
|
|
3
|
+
The product and plugin ID is `i3-composer-agent`; the npm package is
|
|
4
|
+
`@givolt/i3-composer-agent`. The separate GSD-based project is maintained in its
|
|
5
|
+
own repository and is outside this conversion.
|
|
6
|
+
|
|
7
|
+
`brand.json` records the identity and upstream baseline. `apply.cjs` replays the
|
|
8
|
+
brand substitutions and marketplace normalization; `templates/` holds the
|
|
9
|
+
branded installation pages. Preserve LICENSE, NOTICE, upstream URLs, historical
|
|
10
|
+
eval reports, the upstream comparison, and the skill ID `using-agent-skills`.
|
|
11
|
+
References to the independent Agent Skills specification retain that name.
|
|
12
|
+
|
|
13
|
+
## Source and release workflow
|
|
14
|
+
|
|
15
|
+
Keep the upstream source on `i3/source`, with its original names. Perform source
|
|
16
|
+
updates there. Start release candidates from the current branded branch, bringing
|
|
17
|
+
in the upstream changes while retaining the npm CLI and `rebrand/` files, then
|
|
18
|
+
replay the brand transformation. A fresh checkout of `i3/source` alone does not
|
|
19
|
+
contain the distribution tools.
|
|
20
|
+
Keep the original upstream remote until a dedicated fork repository is created;
|
|
21
|
+
do not push branded changes to `addyosmani/agent-skills`.
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
node rebrand/apply.cjs --apply
|
|
25
|
+
node rebrand/apply.cjs --check
|
|
26
|
+
npm run validate
|
|
27
|
+
npm test
|
|
28
|
+
node scripts/run-evals.js --min-rank1 95
|
|
29
|
+
bash hooks/session-start-test.sh
|
|
30
|
+
bash hooks/sdd-cache-test.sh
|
|
31
|
+
bash hooks/simplify-ignore-test.sh
|
|
32
|
+
npm pack --pack-destination /path/to/release-directory
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
The transform is idempotent. The check exits with a failure when another replay
|
|
36
|
+
would change files. Keep package.json and all plugin manifest versions in sync.
|
|
37
|
+
Inspect the tarball and test its CLI in an isolated directory before publishing.
|
|
38
|
+
|
|
39
|
+
The CLI prepares a self-contained plugin directory and prints native host
|
|
40
|
+
registration commands. It does not write business-project AGENTS.md, change
|
|
41
|
+
existing plugin settings, or register lifecycle slash commands in Codex.
|
|
42
|
+
|
|
43
|
+
Publishing is a separate step after the package is reviewed:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
npm publish /path/to/givolt-i3-composer-agent-0.6.12.tgz --access public
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Verify the registry version, integrity, and a fresh registry install after
|
|
50
|
+
publication. A local tarball test does not prove registry publication or actual
|
|
51
|
+
model execution of a command.
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const fs = require('node:fs');
|
|
5
|
+
const path = require('node:path');
|
|
6
|
+
const brand = require('./brand.json');
|
|
7
|
+
const root = path.resolve(__dirname, '..');
|
|
8
|
+
const mode = process.argv[2];
|
|
9
|
+
if (!['--apply', '--check'].includes(mode)) {
|
|
10
|
+
console.error('Usage: node rebrand/apply.cjs --apply | --check');
|
|
11
|
+
process.exit(1);
|
|
12
|
+
}
|
|
13
|
+
const changes = new Map();
|
|
14
|
+
function update(relative, content) {
|
|
15
|
+
const file = path.join(root, relative);
|
|
16
|
+
if (!fs.existsSync(file) || fs.readFileSync(file, 'utf8') !== content) changes.set(relative, content);
|
|
17
|
+
}
|
|
18
|
+
function transform(content, relative) {
|
|
19
|
+
// Agent Skills is also the name of an independent specification.
|
|
20
|
+
const standard = '__I3_AGENT_SKILLS_STANDARD__';
|
|
21
|
+
let result = content
|
|
22
|
+
.replace('agents working on the [`addyosmani/agent-skills`](https://github.com/addyosmani/agent-skills) repository itself',
|
|
23
|
+
'agents working on the i3 Composer Agent repository itself, derived from [`addyosmani/agent-skills`](https://github.com/addyosmani/agent-skills)')
|
|
24
|
+
.replace(/Agent Skills(?=\s+(?:specification|spec\b|format\b|standard\b))/g, standard)
|
|
25
|
+
.replaceAll('addy-agent-skills', brand.name)
|
|
26
|
+
.replaceAll('agent-skills@addy-agent-skills', `${brand.name}@${brand.name}`)
|
|
27
|
+
.replaceAll('agent-skills@agent-skills', `${brand.name}@${brand.name}`)
|
|
28
|
+
.replaceAll('agent-skills:', `${brand.name}:`)
|
|
29
|
+
.replaceAll('/path/to/agent-skills', `/path/to/${brand.name}`)
|
|
30
|
+
.replaceAll('./agent-skills', `./${brand.name}`)
|
|
31
|
+
.replace(/(?<![\w/.-])agent-skills(?![\w-])/g, brand.name)
|
|
32
|
+
.replaceAll('Agent Skills', brand.displayName)
|
|
33
|
+
.replaceAll(standard, 'Agent Skills');
|
|
34
|
+
if (relative.startsWith('docs/')) {
|
|
35
|
+
result = result.split('\n').map(line => {
|
|
36
|
+
if (/^\s*git clone https:\/\/github\.com\/addyosmani\/agent-skills(?:\.git)?\s*$/.test(line)) {
|
|
37
|
+
return `${line.match(/^\s*/)[0]}npx ${brand.npmName} --extract --dir ./${brand.name}`;
|
|
38
|
+
}
|
|
39
|
+
if (/^\s*(?:npx |codex |copilot |cmd |agy |gemini |\/plugin )/.test(line)) {
|
|
40
|
+
return line.replaceAll('https://github.com/addyosmani/agent-skills.git', `/path/to/${brand.name}`)
|
|
41
|
+
.replaceAll('https://github.com/addyosmani/agent-skills', `/path/to/${brand.name}`)
|
|
42
|
+
.replaceAll('addyosmani/agent-skills', `/path/to/${brand.name}`);
|
|
43
|
+
}
|
|
44
|
+
return line;
|
|
45
|
+
}).join('\n');
|
|
46
|
+
result = result
|
|
47
|
+
.replace(/^cmd skills add \/path\/to\/i3-composer-agent@main[^\n]*$/gm,
|
|
48
|
+
'# Branch selectors apply to Git sources; prepared npm bundles have no Git history.')
|
|
49
|
+
.replaceAll('Clone the repository', 'Prepare the plugin bundle')
|
|
50
|
+
.replaceAll('Clone this repository', 'Prepare the plugin bundle')
|
|
51
|
+
.replaceAll('Install from the remote repository', 'Install from a prepared local bundle')
|
|
52
|
+
.replaceAll('npx skills add addyosmani/agent-skills', `npx skills add /path/to/${brand.name}`)
|
|
53
|
+
.replaceAll('plugin marketplace add addyosmani/agent-skills', `plugin marketplace add /path/to/${brand.name}`)
|
|
54
|
+
.replaceAll('~/.gemini/config/plugins/agent-skills/', `~/.gemini/config/plugins/${brand.name}/`)
|
|
55
|
+
.replaceAll('.cursor/rules/agent-skills.mdc', `.cursor/rules/${brand.name}.mdc`)
|
|
56
|
+
.replace(/\[[^\]]+\]\(https:\/\/github\.com\/addyosmani\/agent-skills\/issues\/(\d+)\)/g,
|
|
57
|
+
(_, issue) => `[upstream agent-skills #${issue}](https://github.com/addyosmani/agent-skills/issues/${issue})`);
|
|
58
|
+
}
|
|
59
|
+
return result;
|
|
60
|
+
}
|
|
61
|
+
const skipDirectories = new Set(['.git', 'node_modules', 'rebrand', 'dist', 'tests', 'bin']);
|
|
62
|
+
const skipFiles = new Set(['LICENSE', 'NOTICE.md', 'package.json', 'README.md', 'evals/README.md', 'evals/skill-impact.md', 'docs/comparison.md', 'scripts/validate-brand.cjs', 'scripts/lib/skill-lint.js', 'scripts/lib/skill-lint-test.js']);
|
|
63
|
+
function walk(directory, prefix = '') {
|
|
64
|
+
for (const entry of fs.readdirSync(directory, { withFileTypes: true })) {
|
|
65
|
+
const relative = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
66
|
+
if (entry.isDirectory()) {
|
|
67
|
+
if (!skipDirectories.has(entry.name) && !relative.startsWith('evals/results')) walk(path.join(directory, entry.name), relative);
|
|
68
|
+
} else if (entry.isFile() && !skipFiles.has(relative) && /\.(?:md|js|cjs|sh|toml|yml)$/.test(entry.name)) {
|
|
69
|
+
const original = fs.readFileSync(path.join(root, relative), 'utf8');
|
|
70
|
+
update(relative, transform(original, relative));
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
walk(root);
|
|
75
|
+
const comparisonPath = 'docs/comparison.md';
|
|
76
|
+
const comparison = fs.readFileSync(path.join(root, comparisonPath), 'utf8');
|
|
77
|
+
if (!comparison.includes('> **Upstream research:**')) {
|
|
78
|
+
const note = `> **Upstream research:** This comparison is retained from Addy Osmani's \`agent-skills\` at commit \`${brand.upstreamCommit}\`. Its experiments describe the upstream project; they are not independent evaluations of ${brand.displayName}.\n\n`;
|
|
79
|
+
update(comparisonPath, comparison.replace('# How agent-skills compares\n\n', '# How agent-skills compares\n\n' + note));
|
|
80
|
+
}
|
|
81
|
+
for (const relative of ['plugin.json', '.claude-plugin/plugin.json', '.codex-plugin/plugin.json']) {
|
|
82
|
+
const manifest = JSON.parse(fs.readFileSync(path.join(root, relative), 'utf8'));
|
|
83
|
+
manifest.name = brand.name;
|
|
84
|
+
manifest.description = brand.description;
|
|
85
|
+
if (manifest.author) manifest.author = { name: brand.maintainer };
|
|
86
|
+
delete manifest.homepage;
|
|
87
|
+
delete manifest.repository;
|
|
88
|
+
if (manifest.interface) {
|
|
89
|
+
manifest.interface.displayName = brand.displayName;
|
|
90
|
+
manifest.interface.developerName = brand.maintainer;
|
|
91
|
+
manifest.interface.shortDescription = 'Engineering workflow skills';
|
|
92
|
+
manifest.interface.longDescription = `${brand.displayName} packages 25 engineering skills from Addy Osmani's Agent Skills, covering requirements, planning, implementation, testing, review, and shipping.`;
|
|
93
|
+
manifest.interface.defaultPrompt = manifest.interface.defaultPrompt.map(prompt => prompt.replaceAll('Agent Skills', brand.displayName));
|
|
94
|
+
}
|
|
95
|
+
update(relative, JSON.stringify(manifest, null, 2) + '\n');
|
|
96
|
+
}
|
|
97
|
+
for (const relative of ['.claude-plugin/marketplace.json', '.agents/plugins/marketplace.json']) {
|
|
98
|
+
const manifest = JSON.parse(fs.readFileSync(path.join(root, relative), 'utf8'));
|
|
99
|
+
manifest.name = brand.name;
|
|
100
|
+
if (manifest.description) manifest.description = brand.description;
|
|
101
|
+
if (manifest.owner) manifest.owner = { name: brand.maintainer };
|
|
102
|
+
if (manifest.interface) manifest.interface.displayName = brand.displayName;
|
|
103
|
+
for (const plugin of manifest.plugins) {
|
|
104
|
+
plugin.name = brand.name;
|
|
105
|
+
plugin.description = brand.description;
|
|
106
|
+
plugin.source = relative.startsWith('.agents/') ? { source: 'local', path: './' } : './';
|
|
107
|
+
delete plugin.homepage;
|
|
108
|
+
}
|
|
109
|
+
update(relative, JSON.stringify(manifest, null, 2) + '\n');
|
|
110
|
+
}
|
|
111
|
+
for (const [relative, template] of [
|
|
112
|
+
['README.md', 'README.md'], ['docs/codex-setup.md', 'codex-setup.md'], ['docs/codebuddy-setup.md', 'codebuddy-setup.md'],
|
|
113
|
+
]) {
|
|
114
|
+
update(relative, fs.readFileSync(path.join(__dirname, 'templates', template), 'utf8'));
|
|
115
|
+
}
|
|
116
|
+
if (mode === '--apply') for (const [relative, content] of changes) {
|
|
117
|
+
fs.mkdirSync(path.dirname(path.join(root, relative)), { recursive: true });
|
|
118
|
+
fs.writeFileSync(path.join(root, relative), content);
|
|
119
|
+
}
|
|
120
|
+
console.log(JSON.stringify({ mode, changedFiles: [...changes.keys()] }, null, 2));
|
|
121
|
+
if (mode === '--check' && changes.size) process.exitCode = 1;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "i3-composer-agent",
|
|
3
|
+
"displayName": "i3 Composer Agent",
|
|
4
|
+
"npmName": "@givolt/i3-composer-agent",
|
|
5
|
+
"maintainer": "Givolt",
|
|
6
|
+
"upstream": "https://github.com/addyosmani/agent-skills",
|
|
7
|
+
"upstreamCommit": "1401c8b",
|
|
8
|
+
"description": "Production-grade engineering skills for AI coding agents covering the development lifecycle from spec to ship."
|
|
9
|
+
}
|