@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.
Files changed (213) hide show
  1. package/.agents/plugins/marketplace.json +22 -0
  2. package/.claude/commands/build.md +44 -0
  3. package/.claude/commands/code-simplify.md +22 -0
  4. package/.claude/commands/constraints.md +32 -0
  5. package/.claude/commands/plan.md +18 -0
  6. package/.claude/commands/review.md +16 -0
  7. package/.claude/commands/ship.md +72 -0
  8. package/.claude/commands/spec.md +17 -0
  9. package/.claude/commands/test.md +19 -0
  10. package/.claude/commands/webperf.md +32 -0
  11. package/.claude-plugin/marketplace.json +26 -0
  12. package/.claude-plugin/plugin.json +17 -0
  13. package/.codex-plugin/plugin.json +26 -0
  14. package/.gemini/commands/build.toml +43 -0
  15. package/.gemini/commands/code-simplify.toml +22 -0
  16. package/.gemini/commands/constraints.toml +32 -0
  17. package/.gemini/commands/planning.toml +18 -0
  18. package/.gemini/commands/review.toml +16 -0
  19. package/.gemini/commands/ship.toml +72 -0
  20. package/.gemini/commands/spec.toml +17 -0
  21. package/.gemini/commands/test.toml +19 -0
  22. package/.gemini/commands/webperf.toml +32 -0
  23. package/LICENSE +21 -0
  24. package/NOTICE.md +9 -0
  25. package/README.md +177 -2
  26. package/agents/code-reviewer.md +102 -0
  27. package/agents/security-auditor.md +112 -0
  28. package/agents/test-engineer.md +95 -0
  29. package/agents/web-performance-auditor.md +184 -0
  30. package/bin/i3-composer-agent.cjs +119 -0
  31. package/commands/build.toml +43 -0
  32. package/commands/code-simplify.toml +22 -0
  33. package/commands/constraints.toml +32 -0
  34. package/commands/planning.toml +18 -0
  35. package/commands/review.toml +16 -0
  36. package/commands/ship.toml +72 -0
  37. package/commands/spec.toml +17 -0
  38. package/commands/test.toml +19 -0
  39. package/commands/webperf.toml +32 -0
  40. package/docs/adoption-guide.md +129 -0
  41. package/docs/advanced-per-agent-configuration.md +70 -0
  42. package/docs/agents.md +123 -0
  43. package/docs/antigravity-setup.md +128 -0
  44. package/docs/codebuddy-setup.md +41 -0
  45. package/docs/codex-setup.md +34 -0
  46. package/docs/commandcode-setup.md +69 -0
  47. package/docs/comparison.md +131 -0
  48. package/docs/copilot-cli-setup.md +64 -0
  49. package/docs/copilot-setup.md +162 -0
  50. package/docs/cursor-setup.md +225 -0
  51. package/docs/developer-onboarding.md +116 -0
  52. package/docs/gemini-cli-setup.md +133 -0
  53. package/docs/getting-started.md +208 -0
  54. package/docs/opencode-setup.md +259 -0
  55. package/docs/other-hosts.md +7 -0
  56. package/docs/skill-anatomy.md +203 -0
  57. package/docs/windsurf-setup.md +48 -0
  58. package/evals/README.md +101 -0
  59. package/evals/cases/api-and-interface-design.json +45 -0
  60. package/evals/cases/browser-testing-with-devtools.json +44 -0
  61. package/evals/cases/ci-cd-and-automation.json +45 -0
  62. package/evals/cases/code-review-and-quality.json +49 -0
  63. package/evals/cases/code-simplification.json +45 -0
  64. package/evals/cases/constraint-driven-development.json +79 -0
  65. package/evals/cases/context-engineering.json +44 -0
  66. package/evals/cases/debugging-and-error-recovery.json +58 -0
  67. package/evals/cases/deprecation-and-migration.json +52 -0
  68. package/evals/cases/documentation-and-adrs.json +44 -0
  69. package/evals/cases/doubt-driven-development.json +43 -0
  70. package/evals/cases/frontend-ui-engineering.json +52 -0
  71. package/evals/cases/git-workflow-and-versioning.json +47 -0
  72. package/evals/cases/idea-refine.json +43 -0
  73. package/evals/cases/incremental-implementation.json +57 -0
  74. package/evals/cases/interview-me.json +42 -0
  75. package/evals/cases/observability-and-instrumentation.json +44 -0
  76. package/evals/cases/performance-optimization.json +53 -0
  77. package/evals/cases/planning-and-task-breakdown.json +45 -0
  78. package/evals/cases/security-and-hardening.json +53 -0
  79. package/evals/cases/shipping-and-launch.json +56 -0
  80. package/evals/cases/source-driven-development.json +44 -0
  81. package/evals/cases/spec-driven-development.json +72 -0
  82. package/evals/cases/test-driven-development.json +73 -0
  83. package/evals/cases/using-agent-skills.json +44 -0
  84. package/evals/fixtures/api-and-interface-design/service-brief.md +19 -0
  85. package/evals/fixtures/browser-testing-with-devtools/README.md +5 -0
  86. package/evals/fixtures/browser-testing-with-devtools/index.html +24 -0
  87. package/evals/fixtures/browser-testing-with-devtools/server.js +15 -0
  88. package/evals/fixtures/ci-cd-and-automation/package.json +8 -0
  89. package/evals/fixtures/ci-cd-and-automation/src/slug.js +3 -0
  90. package/evals/fixtures/ci-cd-and-automation/test/slug.test.js +9 -0
  91. package/evals/fixtures/code-review-and-quality/user-search.diff +16 -0
  92. package/evals/fixtures/code-simplification/config-parser.js +46 -0
  93. package/evals/fixtures/code-simplification/config-parser.test.js +15 -0
  94. package/evals/fixtures/context-engineering/context-audit.md +15 -0
  95. package/evals/fixtures/debugging-and-error-recovery/pagination.js +8 -0
  96. package/evals/fixtures/debugging-and-error-recovery/pagination.test.js +9 -0
  97. package/evals/fixtures/debugging-and-error-recovery/time-pressure.md +6 -0
  98. package/evals/fixtures/deprecation-and-migration/api-inventory.md +9 -0
  99. package/evals/fixtures/documentation-and-adrs/decision-context.md +16 -0
  100. package/evals/fixtures/doubt-driven-development/migration-plan.md +19 -0
  101. package/evals/fixtures/frontend-ui-engineering/Button.tsx +7 -0
  102. package/evals/fixtures/frontend-ui-engineering/design-system.md +11 -0
  103. package/evals/fixtures/git-workflow-and-versioning/.eval/working-tree.patch +21 -0
  104. package/evals/fixtures/git-workflow-and-versioning/app.js +7 -0
  105. package/evals/fixtures/git-workflow-and-versioning/app.test.js +9 -0
  106. package/evals/fixtures/incremental-implementation/reports.js +7 -0
  107. package/evals/fixtures/incremental-implementation/reports.test.js +12 -0
  108. package/evals/fixtures/incremental-implementation/tasks/plan.md +8 -0
  109. package/evals/fixtures/incremental-implementation-pressure/draft-export.js +17 -0
  110. package/evals/fixtures/incremental-implementation-pressure/scenario.md +9 -0
  111. package/evals/fixtures/observability-and-instrumentation/operations.md +11 -0
  112. package/evals/fixtures/observability-and-instrumentation/payment-retry.js +14 -0
  113. package/evals/fixtures/performance-optimization/benchmark.js +15 -0
  114. package/evals/fixtures/performance-optimization/products.js +14 -0
  115. package/evals/fixtures/planning-and-task-breakdown/notifications-spec.md +18 -0
  116. package/evals/fixtures/security-and-hardening/webhook.js +11 -0
  117. package/evals/fixtures/security-and-hardening/webhook.test.js +13 -0
  118. package/evals/fixtures/shipping-and-launch/authority-pressure.md +6 -0
  119. package/evals/fixtures/shipping-and-launch/launch-status.md +11 -0
  120. package/evals/fixtures/source-driven-development/framework-task.md +10 -0
  121. package/evals/fixtures/spec-driven-development/billing-brief.md +16 -0
  122. package/evals/fixtures/spec-driven-development-decomposition/portal-brief.md +22 -0
  123. package/evals/fixtures/test-driven-development/BUG.md +10 -0
  124. package/evals/fixtures/test-driven-development/README.md +28 -0
  125. package/evals/fixtures/test-driven-development/package.json +9 -0
  126. package/evals/fixtures/test-driven-development/src/split.js +8 -0
  127. package/evals/fixtures/test-driven-development/test/split.test.js +13 -0
  128. package/evals/fixtures/test-driven-development-ecosystem/README.md +9 -0
  129. package/evals/fixtures/test-driven-development-ecosystem/ledger.py +15 -0
  130. package/evals/fixtures/test-driven-development-ecosystem/test_ledger.py +19 -0
  131. package/evals/fixtures/using-agent-skills/incident.md +6 -0
  132. package/evals/plugin/code-review-fires/graders/off-by-one.md +7 -0
  133. package/evals/plugin/code-review-fires/graders/severity-labels.md +4 -0
  134. package/evals/plugin/code-review-fires/graders/skill-fired.md +5 -0
  135. package/evals/plugin/code-review-fires/prompt.md +31 -0
  136. package/evals/plugin/code-review-stays-quiet/graders/not-fired.md +8 -0
  137. package/evals/plugin/code-review-stays-quiet/graders/tdd-fired.md +6 -0
  138. package/evals/plugin/code-review-stays-quiet/prompt.md +8 -0
  139. package/evals/plugin/code-review-stays-quiet-on-commit-message/graders/not-fired.md +8 -0
  140. package/evals/plugin/code-review-stays-quiet-on-commit-message/prompt.md +25 -0
  141. package/evals/skill-impact.md +6 -0
  142. package/hooks/SDD-CACHE.md +167 -0
  143. package/hooks/SIMPLIFY-IGNORE.md +91 -0
  144. package/hooks/sdd-cache-post.sh +135 -0
  145. package/hooks/sdd-cache-pre.sh +106 -0
  146. package/hooks/sdd-cache-test.sh +246 -0
  147. package/hooks/session-start-test.sh +47 -0
  148. package/hooks/session-start.sh +33 -0
  149. package/hooks/simplify-ignore-test.sh +476 -0
  150. package/hooks/simplify-ignore.sh +352 -0
  151. package/package.json +31 -4
  152. package/plugin.json +5 -0
  153. package/rebrand/MAINTENANCE.md +51 -0
  154. package/rebrand/apply.cjs +121 -0
  155. package/rebrand/brand.json +9 -0
  156. package/rebrand/templates/README.md +178 -0
  157. package/rebrand/templates/codebuddy-setup.md +41 -0
  158. package/rebrand/templates/codex-setup.md +34 -0
  159. package/references/accessibility-checklist.md +160 -0
  160. package/references/definition-of-done.md +67 -0
  161. package/references/observability-checklist.md +92 -0
  162. package/references/orchestration-patterns.md +370 -0
  163. package/references/performance-checklist.md +236 -0
  164. package/references/security-checklist.md +248 -0
  165. package/references/testing-patterns.md +235 -0
  166. package/scripts/floor-guard-reference-test.js +291 -0
  167. package/scripts/lib/skill-lint-test.js +650 -0
  168. package/scripts/lib/skill-lint.js +584 -0
  169. package/scripts/run-evals-test.js +623 -0
  170. package/scripts/run-evals.js +638 -0
  171. package/scripts/validate-artifact-paths-test.js +179 -0
  172. package/scripts/validate-artifact-paths.js +128 -0
  173. package/scripts/validate-brand.cjs +36 -0
  174. package/scripts/validate-commands-test.js +216 -0
  175. package/scripts/validate-commands.js +222 -0
  176. package/scripts/validate-reference-links-test.js +495 -0
  177. package/scripts/validate-reference-links.js +187 -0
  178. package/scripts/validate-skills.js +69 -0
  179. package/scripts/validate-versions-test.js +32 -0
  180. package/scripts/validate-versions.js +35 -0
  181. package/skills/api-and-interface-design/SKILL.md +367 -0
  182. package/skills/browser-testing-with-devtools/SKILL.md +317 -0
  183. package/skills/ci-cd-and-automation/SKILL.md +390 -0
  184. package/skills/code-review-and-quality/SKILL.md +398 -0
  185. package/skills/code-simplification/SKILL.md +331 -0
  186. package/skills/constraint-driven-development/SKILL.md +311 -0
  187. package/skills/constraint-driven-development/references/floor-guard.md +182 -0
  188. package/skills/context-engineering/SKILL.md +353 -0
  189. package/skills/debugging-and-error-recovery/SKILL.md +300 -0
  190. package/skills/deprecation-and-migration/SKILL.md +247 -0
  191. package/skills/documentation-and-adrs/SKILL.md +288 -0
  192. package/skills/doubt-driven-development/SKILL.md +243 -0
  193. package/skills/frontend-ui-engineering/SKILL.md +340 -0
  194. package/skills/git-workflow-and-versioning/SKILL.md +355 -0
  195. package/skills/idea-refine/SKILL.md +178 -0
  196. package/skills/idea-refine/examples.md +238 -0
  197. package/skills/idea-refine/frameworks.md +99 -0
  198. package/skills/idea-refine/refinement-criteria.md +113 -0
  199. package/skills/idea-refine/scripts/idea-refine.sh +15 -0
  200. package/skills/incremental-implementation/SKILL.md +249 -0
  201. package/skills/interview-me/SKILL.md +235 -0
  202. package/skills/observability-and-instrumentation/SKILL.md +238 -0
  203. package/skills/performance-optimization/SKILL.md +267 -0
  204. package/skills/performance-optimization/references/optimization-patterns.md +250 -0
  205. package/skills/planning-and-task-breakdown/SKILL.md +257 -0
  206. package/skills/security-and-hardening/SKILL.md +216 -0
  207. package/skills/security-and-hardening/references/hardening-patterns.md +324 -0
  208. package/skills/shipping-and-launch/SKILL.md +330 -0
  209. package/skills/source-driven-development/SKILL.md +216 -0
  210. package/skills/spec-driven-development/SKILL.md +259 -0
  211. package/skills/test-driven-development/SKILL.md +398 -0
  212. package/skills/using-agent-skills/SKILL.md +192 -0
  213. 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.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
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,5 @@
1
+ {
2
+ "name": "i3-composer-agent",
3
+ "version": "0.6.12",
4
+ "description": "Production-grade engineering skills for AI coding agents covering the development lifecycle from spec to ship."
5
+ }
@@ -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
+ }