@givolt/i3-composer-agent 1.0.1 → 2.0.0

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 (204) hide show
  1. package/.agents/plugins/marketplace.json +1 -1
  2. package/.claude/commands/{build.md → i3-build.md} +10 -10
  3. package/.claude/commands/{code-simplify.md → i3-code-simplify.md} +2 -2
  4. package/.claude/commands/{constraints.md → i3-constraints.md} +4 -4
  5. package/.claude/commands/{plan.md → i3-plan.md} +1 -1
  6. package/.claude/commands/{review.md → i3-review.md} +3 -3
  7. package/.claude/commands/{ship.md → i3-ship.md} +4 -4
  8. package/.claude/commands/{spec.md → i3-spec.md} +1 -1
  9. package/.claude/commands/{test.md → i3-test.md} +2 -2
  10. package/.claude/commands/{webperf.md → i3-webperf.md} +1 -1
  11. package/.claude-plugin/marketplace.json +1 -1
  12. package/.claude-plugin/plugin.json +1 -1
  13. package/.codex-plugin/plugin.json +1 -1
  14. package/.gemini/commands/{build.toml → i3-build.toml} +10 -10
  15. package/.gemini/commands/{code-simplify.toml → i3-code-simplify.toml} +2 -2
  16. package/.gemini/commands/{constraints.toml → i3-constraints.toml} +4 -4
  17. package/.gemini/commands/{planning.toml → i3-planning.toml} +1 -1
  18. package/{commands/review.toml → .gemini/commands/i3-review.toml} +3 -3
  19. package/.gemini/commands/{ship.toml → i3-ship.toml} +4 -4
  20. package/.gemini/commands/{spec.toml → i3-spec.toml} +1 -1
  21. package/{commands/test.toml → .gemini/commands/i3-test.toml} +2 -2
  22. package/.gemini/commands/{webperf.toml → i3-webperf.toml} +1 -1
  23. package/CHANGELOG.md +17 -0
  24. package/NOTICE.md +2 -1
  25. package/README.md +47 -41
  26. package/agents/code-reviewer.md +2 -2
  27. package/agents/security-auditor.md +1 -1
  28. package/agents/test-engineer.md +1 -1
  29. package/agents/web-performance-auditor.md +3 -3
  30. package/bin/i3-composer-agent.cjs +2 -2
  31. package/bin/install.cjs +20 -4
  32. package/commands/{build.toml → i3-build.toml} +10 -10
  33. package/commands/{code-simplify.toml → i3-code-simplify.toml} +2 -2
  34. package/commands/{constraints.toml → i3-constraints.toml} +4 -4
  35. package/commands/{planning.toml → i3-planning.toml} +1 -1
  36. package/{.gemini/commands/review.toml → commands/i3-review.toml} +3 -3
  37. package/commands/{ship.toml → i3-ship.toml} +4 -4
  38. package/commands/{spec.toml → i3-spec.toml} +1 -1
  39. package/{.gemini/commands/test.toml → commands/i3-test.toml} +2 -2
  40. package/commands/{webperf.toml → i3-webperf.toml} +1 -1
  41. package/docs/adoption-guide.md +35 -35
  42. package/docs/agents.md +12 -12
  43. package/docs/antigravity-setup.md +14 -14
  44. package/docs/codebuddy-setup.md +16 -15
  45. package/docs/codex-setup.md +6 -6
  46. package/docs/commandcode-setup.md +5 -5
  47. package/docs/copilot-cli-setup.md +5 -5
  48. package/docs/copilot-setup.md +22 -22
  49. package/docs/cursor-setup.md +20 -20
  50. package/docs/developer-onboarding.md +5 -5
  51. package/docs/gemini-cli-setup.md +26 -26
  52. package/docs/getting-started.md +36 -36
  53. package/docs/opencode-setup.md +27 -27
  54. package/docs/skill-anatomy.md +3 -3
  55. package/docs/windsurf-setup.md +7 -7
  56. package/evals/cases/{api-and-interface-design.json → i3-api-and-interface-design.json} +4 -4
  57. package/evals/cases/{browser-testing-with-devtools.json → i3-browser-testing-with-devtools.json} +4 -4
  58. package/evals/cases/{ci-cd-and-automation.json → i3-ci-cd-and-automation.json} +4 -4
  59. package/evals/cases/{code-review-and-quality.json → i3-code-review-and-quality.json} +4 -4
  60. package/evals/cases/{code-simplification.json → i3-code-simplification.json} +4 -4
  61. package/evals/cases/{constraint-driven-development.json → i3-constraint-driven-development.json} +4 -4
  62. package/evals/cases/{context-engineering.json → i3-context-engineering.json} +4 -4
  63. package/evals/cases/{debugging-and-error-recovery.json → i3-debugging-and-error-recovery.json} +5 -5
  64. package/evals/cases/{deprecation-and-migration.json → i3-deprecation-and-migration.json} +4 -4
  65. package/evals/cases/{documentation-and-adrs.json → i3-documentation-and-adrs.json} +4 -4
  66. package/evals/cases/{doubt-driven-development.json → i3-doubt-driven-development.json} +3 -3
  67. package/evals/cases/{frontend-ui-engineering.json → i3-frontend-ui-engineering.json} +4 -4
  68. package/evals/cases/{git-workflow-and-versioning.json → i3-git-workflow-and-versioning.json} +3 -3
  69. package/evals/cases/{idea-refine.json → i3-idea-refine.json} +3 -3
  70. package/evals/cases/{incremental-implementation.json → i3-incremental-implementation.json} +4 -4
  71. package/evals/cases/{interview-me.json → i3-interview-me.json} +3 -3
  72. package/evals/cases/{observability-and-instrumentation.json → i3-observability-and-instrumentation.json} +3 -3
  73. package/evals/cases/{performance-optimization.json → i3-performance-optimization.json} +4 -4
  74. package/evals/cases/{planning-and-task-breakdown.json → i3-planning-and-task-breakdown.json} +4 -4
  75. package/evals/cases/{security-and-hardening.json → i3-security-and-hardening.json} +4 -4
  76. package/evals/cases/{shipping-and-launch.json → i3-shipping-and-launch.json} +4 -4
  77. package/evals/cases/{source-driven-development.json → i3-source-driven-development.json} +4 -4
  78. package/evals/cases/{spec-driven-development.json → i3-spec-driven-development.json} +5 -5
  79. package/evals/cases/{test-driven-development.json → i3-test-driven-development.json} +5 -5
  80. package/evals/cases/{using-agent-skills.json → i3-using-agent-skills.json} +4 -4
  81. package/evals/fixtures/{git-workflow-and-versioning → i3-git-workflow-and-versioning}/.eval/working-tree.patch +3 -3
  82. package/evals/plugin/code-review-fires/graders/skill-fired.md +1 -1
  83. package/evals/plugin/code-review-stays-quiet/graders/not-fired.md +1 -1
  84. package/evals/plugin/code-review-stays-quiet/graders/tdd-fired.md +1 -1
  85. package/evals/plugin/code-review-stays-quiet/prompt.md +2 -2
  86. package/evals/plugin/code-review-stays-quiet-on-commit-message/graders/not-fired.md +1 -1
  87. package/evals/plugin/code-review-stays-quiet-on-commit-message/prompt.md +2 -2
  88. package/hooks/SDD-CACHE.md +3 -3
  89. package/hooks/SIMPLIFY-IGNORE.md +2 -2
  90. package/hooks/session-start-test.sh +1 -1
  91. package/hooks/session-start.sh +3 -3
  92. package/package.json +1 -1
  93. package/plugin.json +1 -1
  94. package/rebrand/INSTALLATION-SPEC.md +2 -1
  95. package/rebrand/MAINTENANCE.md +3 -2
  96. package/rebrand/NOTICE.md +2 -1
  97. package/rebrand/PREFIX-SPEC.md +16 -0
  98. package/rebrand/UNIFICATION-SPEC.md +2 -2
  99. package/rebrand/VALIDATION.md +2 -2
  100. package/rebrand/VERSIONING.md +5 -3
  101. package/rebrand/apply.cjs +33 -10
  102. package/rebrand/brand.json +1 -1
  103. package/rebrand/catalog.cjs +16 -2
  104. package/rebrand/fork-patches.json +15 -0
  105. package/rebrand/identifiers.cjs +41 -0
  106. package/rebrand/overlay/CHANGELOG.md +17 -0
  107. package/rebrand/overlay/bin/i3-composer-agent.cjs +2 -2
  108. package/rebrand/overlay/bin/install.cjs +20 -4
  109. package/rebrand/overlay/scripts/validate-brand.cjs +3 -3
  110. package/rebrand/overlay/tests/installer.test.cjs +60 -12
  111. package/rebrand/templates/README.md +11 -5
  112. package/rebrand/templates/codebuddy-setup.md +16 -15
  113. package/rebrand/templates/codex-setup.md +6 -6
  114. package/rebrand/tests/pipeline.test.cjs +71 -3
  115. package/references/accessibility-checklist.md +1 -1
  116. package/references/definition-of-done.md +7 -7
  117. package/references/observability-checklist.md +3 -3
  118. package/references/orchestration-patterns.md +17 -17
  119. package/references/performance-checklist.md +2 -2
  120. package/references/security-checklist.md +1 -1
  121. package/references/testing-patterns.md +1 -1
  122. package/scripts/floor-guard-reference-test.js +2 -2
  123. package/scripts/lib/skill-lint.js +2 -0
  124. package/scripts/run-evals-test.js +2 -2
  125. package/scripts/validate-artifact-paths-test.js +3 -3
  126. package/scripts/validate-artifact-paths.js +4 -2
  127. package/scripts/validate-brand.cjs +3 -3
  128. package/scripts/validate-commands.js +1 -0
  129. package/scripts/validate-reference-links-test.js +11 -11
  130. package/scripts/validate-reference-links.js +1 -1
  131. package/skills/{api-and-interface-design → i3-api-and-interface-design}/SKILL.md +2 -2
  132. package/skills/{browser-testing-with-devtools → i3-browser-testing-with-devtools}/SKILL.md +1 -1
  133. package/skills/{ci-cd-and-automation → i3-ci-cd-and-automation}/SKILL.md +2 -2
  134. package/skills/{code-review-and-quality → i3-code-review-and-quality}/SKILL.md +5 -5
  135. package/skills/{code-simplification → i3-code-simplification}/SKILL.md +1 -1
  136. package/skills/{constraint-driven-development → i3-constraint-driven-development}/SKILL.md +15 -15
  137. package/skills/{context-engineering → i3-context-engineering}/SKILL.md +1 -1
  138. package/skills/{debugging-and-error-recovery → i3-debugging-and-error-recovery}/SKILL.md +2 -2
  139. package/skills/{deprecation-and-migration → i3-deprecation-and-migration}/SKILL.md +2 -2
  140. package/skills/{documentation-and-adrs → i3-documentation-and-adrs}/SKILL.md +1 -1
  141. package/skills/{doubt-driven-development → i3-doubt-driven-development}/SKILL.md +8 -8
  142. package/skills/{frontend-ui-engineering → i3-frontend-ui-engineering}/SKILL.md +1 -1
  143. package/skills/{git-workflow-and-versioning → i3-git-workflow-and-versioning}/SKILL.md +4 -4
  144. package/skills/{idea-refine → i3-idea-refine}/SKILL.md +2 -2
  145. package/skills/{idea-refine → i3-idea-refine}/scripts/idea-refine.sh +1 -1
  146. package/skills/{incremental-implementation → i3-incremental-implementation}/SKILL.md +3 -3
  147. package/skills/{interview-me → i3-interview-me}/SKILL.md +12 -12
  148. package/skills/{observability-and-instrumentation → i3-observability-and-instrumentation}/SKILL.md +5 -5
  149. package/skills/{performance-optimization → i3-performance-optimization}/SKILL.md +1 -1
  150. package/skills/{performance-optimization → i3-performance-optimization}/references/optimization-patterns.md +1 -1
  151. package/skills/{planning-and-task-breakdown → i3-planning-and-task-breakdown}/SKILL.md +2 -2
  152. package/skills/{security-and-hardening → i3-security-and-hardening}/SKILL.md +3 -3
  153. package/skills/{security-and-hardening → i3-security-and-hardening}/references/hardening-patterns.md +1 -1
  154. package/skills/{shipping-and-launch → i3-shipping-and-launch}/SKILL.md +2 -2
  155. package/skills/{source-driven-development → i3-source-driven-development}/SKILL.md +2 -2
  156. package/skills/{spec-driven-development → i3-spec-driven-development}/SKILL.md +7 -7
  157. package/skills/{test-driven-development → i3-test-driven-development}/SKILL.md +2 -2
  158. package/skills/{using-agent-skills → i3-using-agent-skills}/SKILL.md +67 -67
  159. package/tests/installer.test.cjs +60 -12
  160. /package/evals/fixtures/{api-and-interface-design → i3-api-and-interface-design}/service-brief.md +0 -0
  161. /package/evals/fixtures/{browser-testing-with-devtools → i3-browser-testing-with-devtools}/README.md +0 -0
  162. /package/evals/fixtures/{browser-testing-with-devtools → i3-browser-testing-with-devtools}/index.html +0 -0
  163. /package/evals/fixtures/{browser-testing-with-devtools → i3-browser-testing-with-devtools}/server.js +0 -0
  164. /package/evals/fixtures/{ci-cd-and-automation → i3-ci-cd-and-automation}/package.json +0 -0
  165. /package/evals/fixtures/{ci-cd-and-automation → i3-ci-cd-and-automation}/src/slug.js +0 -0
  166. /package/evals/fixtures/{ci-cd-and-automation → i3-ci-cd-and-automation}/test/slug.test.js +0 -0
  167. /package/evals/fixtures/{code-review-and-quality → i3-code-review-and-quality}/user-search.diff +0 -0
  168. /package/evals/fixtures/{code-simplification → i3-code-simplification}/config-parser.js +0 -0
  169. /package/evals/fixtures/{code-simplification → i3-code-simplification}/config-parser.test.js +0 -0
  170. /package/evals/fixtures/{context-engineering → i3-context-engineering}/context-audit.md +0 -0
  171. /package/evals/fixtures/{debugging-and-error-recovery → i3-debugging-and-error-recovery}/pagination.js +0 -0
  172. /package/evals/fixtures/{debugging-and-error-recovery → i3-debugging-and-error-recovery}/pagination.test.js +0 -0
  173. /package/evals/fixtures/{debugging-and-error-recovery → i3-debugging-and-error-recovery}/time-pressure.md +0 -0
  174. /package/evals/fixtures/{deprecation-and-migration → i3-deprecation-and-migration}/api-inventory.md +0 -0
  175. /package/evals/fixtures/{documentation-and-adrs → i3-documentation-and-adrs}/decision-context.md +0 -0
  176. /package/evals/fixtures/{doubt-driven-development → i3-doubt-driven-development}/migration-plan.md +0 -0
  177. /package/evals/fixtures/{frontend-ui-engineering → i3-frontend-ui-engineering}/Button.tsx +0 -0
  178. /package/evals/fixtures/{frontend-ui-engineering → i3-frontend-ui-engineering}/design-system.md +0 -0
  179. /package/evals/fixtures/{git-workflow-and-versioning → i3-git-workflow-and-versioning}/app.js +0 -0
  180. /package/evals/fixtures/{git-workflow-and-versioning → i3-git-workflow-and-versioning}/app.test.js +0 -0
  181. /package/evals/fixtures/{incremental-implementation → i3-incremental-implementation}/reports.js +0 -0
  182. /package/evals/fixtures/{incremental-implementation → i3-incremental-implementation}/reports.test.js +0 -0
  183. /package/evals/fixtures/{incremental-implementation → i3-incremental-implementation}/tasks/plan.md +0 -0
  184. /package/evals/fixtures/{observability-and-instrumentation → i3-observability-and-instrumentation}/operations.md +0 -0
  185. /package/evals/fixtures/{observability-and-instrumentation → i3-observability-and-instrumentation}/payment-retry.js +0 -0
  186. /package/evals/fixtures/{performance-optimization → i3-performance-optimization}/benchmark.js +0 -0
  187. /package/evals/fixtures/{performance-optimization → i3-performance-optimization}/products.js +0 -0
  188. /package/evals/fixtures/{planning-and-task-breakdown → i3-planning-and-task-breakdown}/notifications-spec.md +0 -0
  189. /package/evals/fixtures/{security-and-hardening → i3-security-and-hardening}/webhook.js +0 -0
  190. /package/evals/fixtures/{security-and-hardening → i3-security-and-hardening}/webhook.test.js +0 -0
  191. /package/evals/fixtures/{shipping-and-launch → i3-shipping-and-launch}/authority-pressure.md +0 -0
  192. /package/evals/fixtures/{shipping-and-launch → i3-shipping-and-launch}/launch-status.md +0 -0
  193. /package/evals/fixtures/{source-driven-development → i3-source-driven-development}/framework-task.md +0 -0
  194. /package/evals/fixtures/{spec-driven-development → i3-spec-driven-development}/billing-brief.md +0 -0
  195. /package/evals/fixtures/{test-driven-development → i3-test-driven-development}/BUG.md +0 -0
  196. /package/evals/fixtures/{test-driven-development → i3-test-driven-development}/README.md +0 -0
  197. /package/evals/fixtures/{test-driven-development → i3-test-driven-development}/package.json +0 -0
  198. /package/evals/fixtures/{test-driven-development → i3-test-driven-development}/src/split.js +0 -0
  199. /package/evals/fixtures/{test-driven-development → i3-test-driven-development}/test/split.test.js +0 -0
  200. /package/evals/fixtures/{using-agent-skills → i3-using-agent-skills}/incident.md +0 -0
  201. /package/skills/{constraint-driven-development → i3-constraint-driven-development}/references/floor-guard.md +0 -0
  202. /package/skills/{idea-refine → i3-idea-refine}/examples.md +0 -0
  203. /package/skills/{idea-refine → i3-idea-refine}/frameworks.md +0 -0
  204. /package/skills/{idea-refine → i3-idea-refine}/refinement-criteria.md +0 -0
@@ -0,0 +1,16 @@
1
+ # i3 command and Skill identifiers
2
+
3
+ The user approved applying the existing i3 naming convention on 2026-10-07.
4
+ This supersedes the earlier preservation of unprefixed distribution identifiers.
5
+
6
+ - `agent/source` keeps upstream files and identifiers unchanged. Changes live in `rebrand/`.
7
+ - Branded Skill directories and YAML `name` fields use `i3-<upstream-id>`.
8
+ - All three command directories use `i3-<upstream-stem>` filenames, retaining the existing `plan`/`planning` host mapping.
9
+ - Native commands include `/i3-spec` and `/i3-build`; plugin commands include `/i3-composer-agent:i3-spec`.
10
+ - Rewrite local references, hooks, routing fixtures and documentation together. Preserve external upstream links, attribution, and Skill frontmatter other than `name`.
11
+ - Retain helper script filenames and executable permissions when their containing Skill directory is renamed.
12
+ - Replay and validation accept only a complete reviewed source catalog or its mapped branded catalog. Replaying branded output is idempotent.
13
+ - Installation migrates only legacy Skill/command paths listed in this package's prior installation manifest. Back up retired paths and support rollback. Unowned commands and skills remain in place.
14
+ - Verify source tests, branded validation/tests, routing/hooks, packed CLI installation, migration, rollback and the actual project installation. IDE discovery and model execution require separate host verification.
15
+
16
+ Release 2.0.0 applies this breaking identifier change. The user authorized publication on 2026-10-07. Publish and verify the reviewed new-version tarball; previously published tarballs remain immutable. The upstream baseline stays at 0.6.12.
@@ -8,7 +8,7 @@
8
8
  - `agent/source` 保留上游原始名称和源码,在 `rebrand/` 保存本项目的分发工具与转换规则。
9
9
  - 候选从 `agent/source` 创建,在候选中重放;`main` 保存经过验证的品牌快照。
10
10
  - GSD 仓库只读,不使用它的源码、分支或安装产物。
11
- - Skill ID、流程命令内容、Persona、参考文件和 MIT 来源署名保持既有契约。
11
+ - 源码保留上游 Skill ID;品牌版按 PREFIX-SPEC.md 使用 i3- 前缀。流程内容、Persona、参考文件和 MIT 来源署名保持。
12
12
  - 本次完善源码同步和品牌重放;交互安装向导、Codex 命令适配及新的 npm 发布独立处理。
13
13
 
14
14
  ## 实现与命令
@@ -24,7 +24,7 @@
24
24
  1. 从干净上游源码及本项目规则能生成完整品牌包,重复重放不产生差异。
25
25
  2. 在 `agent/source` 上执行写入式重放必须失败且不修改源码。
26
26
  3. 记录上游新增 Skill/Command 后能生成相应清单和说明;删失或改写已记录 Skill ID 时校验失败。
27
- 4. 上游的 25 个 Skill frontmatter、24 个非元 Skill、4 个 Persona、7 个共享参考保持原始内容;9 个流程只变品牌命名空间。
27
+ 4. 品牌版的 Skill name、目录和命令文件名统一使用 i3-;frontmatter 的其他字段、Persona、共享参考和流程契约保持。
28
28
  5. 本地候选通过完整测试,并从打包结果运行 CLI 与校验。
29
29
  6. 独立品牌仓库中的源/发行分支及远程关系正确;首次发布标签保持原来的 0.6.12 提交。
30
30
 
@@ -11,8 +11,8 @@
11
11
 
12
12
  ## 品牌候选
13
13
 
14
- - Skill、命令、Persona、references 和全部已记录普通运行文件与上游目录一致。
15
- - Skill frontmatter 的名称和字段内容保持;换行差异不作为字段变更。
14
+ - Skill 和命令路径按 PREFIX-SPEC.md 映射为 i3- 名称;其余已记录运行文件保持目录一致。
15
+ - Skill frontmatter 只改 name;逆向映射 name 后比较上游哈希,换行差异不作为字段变更。
16
16
  - 新增上游 Skill/Command 能进入目录、品牌说明和打包;缺失内容会失败。
17
17
  - 文字补丁失去匹配时必须失败,不能静默遗漏。
18
18
  - 重放后 --check 成功,完整 Node、路由与 hook 检查通过。
@@ -4,7 +4,7 @@
4
4
 
5
5
  | 信息 | 权威来源 | 当前发行值 |
6
6
  | --- | --- | --- |
7
- | i3 发行版本 | brand.json 的 releaseVersion | 1.0.1 |
7
+ | i3 发行版本 | brand.json 的 releaseVersion | 2.0.0 |
8
8
  | 上游版本 | upstream.json 的 upstreamVersion | 0.6.12 |
9
9
  | 上游提交 | upstream.json 的 upstreamCommit | 1401c8b8030e023baeebb31781a6653fe8e93026 |
10
10
 
@@ -20,14 +20,16 @@ package.json 的 i3ComposerAgent 来源字段。package.template.json 不保存
20
20
  README、CLI 帮助和准备完成提示显示:
21
21
 
22
22
  ```text
23
- i3 Composer Agent v1.0.1
23
+ i3 Composer Agent v2.0.0
24
24
  Based on agent-skills v0.6.12
25
25
  ```
26
26
 
27
- 在上述例子中,--version 输出 1.0.1,保留脚本使用的单一版本格式。--dry-run 的 JSON
27
+ 在上述例子中,--version 输出 2.0.0,保留脚本使用的单一版本格式。--dry-run 的 JSON
28
28
  分别提供 version、upstreamVersion、upstreamCommit。
29
29
 
30
30
  已经发布的 @givolt/i3-composer-agent@0.6.12 及其 Git 标签作为历史记录保留。
31
31
  之前的 0.6.13 是未发布候选,新的独立版本候选替代它。
32
32
  1.0.0 已发布。1.0.1 用于修复安装向导遗漏,版本与发布已由用户确认。
33
+ 2.0.0 为命令和 Skill 的 i3- 前缀变更;使用者需要调整调用名,因此递增 major。
34
+ 用户于 2026-10-07 要求修改并授权发布;上游版本和提交保持不变。
33
35
  源码与打包验证不代表 npm 发布;发布仍按 MAINTENANCE.md 单独执行。
package/rebrand/apply.cjs CHANGED
@@ -5,6 +5,7 @@ const fs = require('node:fs');
5
5
  const path = require('node:path');
6
6
  const { spawnSync } = require('node:child_process');
7
7
  const { validateCatalog, frontmatter } = require('./catalog.cjs');
8
+ const { skillId, runtimePath, rewriteReferences } = require('./identifiers.cjs');
8
9
  const brand = require('./brand.json');
9
10
  const upstream = require('./upstream.json');
10
11
  const root = path.resolve(__dirname, '..');
@@ -20,7 +21,24 @@ if (mode === '--apply') {
20
21
  process.exit(1);
21
22
  }
22
23
  }
23
- const inventory = validateCatalog(root, upstream);
24
+ const branded = fs.existsSync(path.join(root, 'skills', skillId(upstream.skills[0])));
25
+ validateCatalog(root, upstream, { branded });
26
+ const inventory = upstream;
27
+ const renames = new Map();
28
+ if (!branded) {
29
+ for (const id of inventory.skills) renames.set(`skills/${id}`, `skills/${skillId(id)}`);
30
+ for (const file of inventory.runtimeFiles.filter(file => /^(?:\.claude\/commands|\.gemini\/commands|commands)\/[^/]+\.(?:md|toml)$/.test(file))) renames.set(file, runtimePath(file));
31
+ for (const target of renames.values()) if (fs.existsSync(path.join(root, target))) throw new Error(`Brand destination already exists: ${target}`);
32
+ }
33
+ for (const id of inventory.skills) {
34
+ for (const file of [`evals/cases/${id}.json`, `evals/fixtures/${id}`]) {
35
+ if (fs.existsSync(path.join(root, file))) {
36
+ const target = runtimePath(file);
37
+ if (fs.existsSync(path.join(root, target))) throw new Error(`Brand destination already exists: ${target}`);
38
+ renames.set(file, target);
39
+ }
40
+ }
41
+ }
24
42
  const packageFile = path.join(root, 'package.json');
25
43
  if (fs.existsSync(packageFile) && JSON.parse(fs.readFileSync(packageFile, 'utf8')).name !== brand.npmName) {
26
44
  console.error('Upstream package.json now exists; explicitly adapt the distribution overlay before replaying.');
@@ -30,6 +48,7 @@ const changes = new Map();
30
48
  function update(relative, content) {
31
49
  const file = path.join(root, relative);
32
50
  if (!fs.existsSync(file) || fs.readFileSync(file, 'utf8') !== content) changes.set(relative, content);
51
+ else changes.delete(relative);
33
52
  }
34
53
  function transform(content, relative) {
35
54
  const head = /^skills\/[^/]+\/SKILL\.md$/.test(relative) ? frontmatter(content) : '';
@@ -43,7 +62,7 @@ function transform(content, relative) {
43
62
  .replaceAll('addy-agent-skills', brand.name)
44
63
  .replaceAll('agent-skills@addy-agent-skills', `${brand.name}@${brand.name}`)
45
64
  .replaceAll('agent-skills@agent-skills', `${brand.name}@${brand.name}`)
46
- .replaceAll('agent-skills:', `${brand.name}:`)
65
+ .replace(/(?<![\w-])agent-skills:/g, `${brand.name}:`)
47
66
  .replaceAll('/path/to/agent-skills', `/path/to/${brand.name}`)
48
67
  .replaceAll('./agent-skills', `./${brand.name}`)
49
68
  .replace(/(?<![\w/.-])agent-skills(?![\w-])/g, brand.name)
@@ -74,7 +93,9 @@ function transform(content, relative) {
74
93
  .replace(/\[[^\]]+\]\(https:\/\/github\.com\/addyosmani\/agent-skills\/issues\/(\d+)\)/g,
75
94
  (_, issue) => `[upstream agent-skills #${issue}](https://github.com/addyosmani/agent-skills/issues/${issue})`);
76
95
  }
77
- return head + result;
96
+ const name = head.match(/^name:\s*([^\s]+)\s*$/m)?.[1];
97
+ const brandedHead = name && inventory.skills.includes(name) ? head.replace(/^name:.*$/m, `name: ${skillId(name)}`) : head;
98
+ return brandedHead + rewriteReferences(result, false, inventory, !relative.startsWith('scripts/'));
78
99
  }
79
100
  const skipDirectories = new Set(['.git', 'node_modules', 'rebrand', 'dist', 'tests', 'bin']);
80
101
  const skipFiles = new Set(['LICENSE', 'NOTICE.md', 'CHANGELOG.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']);
@@ -83,7 +104,7 @@ function walk(directory, prefix = '') {
83
104
  const relative = prefix ? `${prefix}/${entry.name}` : entry.name;
84
105
  if (entry.isDirectory()) {
85
106
  if (!skipDirectories.has(entry.name) && !relative.startsWith('evals/results')) walk(path.join(directory, entry.name), relative);
86
- } else if (entry.isFile() && !skipFiles.has(relative) && /\.(?:md|js|cjs|sh|toml|yml)$/.test(entry.name)) {
107
+ } else if (entry.isFile() && !skipFiles.has(relative) && /\.(?:md|js|cjs|sh|toml|yml|json|patch|diff)$/.test(entry.name)) {
87
108
  const original = fs.readFileSync(path.join(root, relative), 'utf8');
88
109
  update(relative, transform(original, relative));
89
110
  }
@@ -116,7 +137,7 @@ for (const relative of ['plugin.json', '.claude-plugin/plugin.json', '.codex-plu
116
137
  manifest.interface.developerName = brand.maintainer;
117
138
  manifest.interface.shortDescription = 'Engineering workflow skills';
118
139
  manifest.interface.longDescription = `${brand.displayName} packages ${inventory.skills.length} engineering skills from Addy Osmani's Agent Skills, covering requirements, planning, implementation, testing, review, and shipping.`;
119
- manifest.interface.defaultPrompt = manifest.interface.defaultPrompt.map(prompt => prompt.replaceAll('Agent Skills', brand.displayName));
140
+ manifest.interface.defaultPrompt = manifest.interface.defaultPrompt.map(prompt => rewriteReferences(prompt.replaceAll('Agent Skills', brand.displayName)));
120
141
  }
121
142
  update(relative, JSON.stringify(manifest, null, 2) + '\n');
122
143
  }
@@ -164,7 +185,8 @@ pkg.i3ComposerAgent.upstreamRepository = brand.upstream;
164
185
  update('package.json', JSON.stringify(pkg, null, 2) + '\n');
165
186
  update('NOTICE.md', fs.readFileSync(path.join(__dirname, 'NOTICE.md'), 'utf8'));
166
187
  function description(relative) {
167
- const head = fs.readFileSync(path.join(root, relative), 'utf8').match(/^---\r?\n([\s\S]*?)\r?\n---/)?.[1] || '';
188
+ const file = path.join(root, branded ? runtimePath(relative) : relative);
189
+ const head = fs.readFileSync(file, 'utf8').match(/^---\r?\n([\s\S]*?)\r?\n---/)?.[1] || '';
168
190
  return (head.match(/^description:\s*(.*)$/m)?.[1] || '').replace(/^["']|["']$/g, '').replaceAll('|', '\\|');
169
191
  }
170
192
  const values = {
@@ -173,8 +195,8 @@ const values = {
173
195
  SKILL_COUNT: inventory.skills.length,
174
196
  COMMAND_COUNT: inventory.commands.length,
175
197
  PERSONA_COUNT: inventory.personas.length,
176
- SKILL_TABLE: inventory.skills.map(id => `| [${id}](skills/${id}/SKILL.md) | ${description(`skills/${id}/SKILL.md`)} |`).join('\n'),
177
- COMMAND_TABLE: inventory.commands.map(id => `| /${brand.name}:${id} | ${description(`.claude/commands/${id}.md`)} |`).join('\n'),
198
+ SKILL_TABLE: inventory.skills.map(id => `| [${skillId(id)}](skills/${skillId(id)}/SKILL.md) | ${description(`skills/${id}/SKILL.md`)} |`).join('\n'),
199
+ COMMAND_TABLE: inventory.commands.map(id => `| /${brand.name}:${skillId(id)} | ${description(`.claude/commands/${id}.md`)} |`).join('\n'),
178
200
  };
179
201
  for (const [relative, template] of [
180
202
  ['README.md', 'README.md'], ['docs/codex-setup.md', 'codex-setup.md'], ['docs/codebuddy-setup.md', 'codebuddy-setup.md'],
@@ -190,5 +212,6 @@ if (mode === '--apply') for (const [relative, content] of changes) {
190
212
  fs.writeFileSync(path.join(root, relative), content);
191
213
  }
192
214
  if (mode === '--apply') fs.chmodSync(path.join(root, 'bin/i3-composer-agent.cjs'), 0o755);
193
- console.log(JSON.stringify({ mode, changedFiles: [...changes.keys()] }, null, 2));
194
- if (mode === '--check' && changes.size) process.exitCode = 1;
215
+ if (mode === '--apply') for (const [source, target] of renames) fs.renameSync(path.join(root, source), path.join(root, target));
216
+ console.log(JSON.stringify({ mode, changedFiles: [...changes.keys()], renamedPaths: Object.fromEntries(renames) }, null, 2));
217
+ if (mode === '--check' && (changes.size || renames.size)) process.exitCode = 1;
@@ -9,5 +9,5 @@
9
9
  "repository": "https://github.com/49780522/i3-composer-agent",
10
10
  "sourceBranch": "agent/source",
11
11
  "releaseBranch": "main",
12
- "releaseVersion": "1.0.1"
12
+ "releaseVersion": "2.0.0"
13
13
  }
@@ -4,6 +4,7 @@ const fs = require('node:fs');
4
4
  const path = require('node:path');
5
5
  const crypto = require('node:crypto');
6
6
  const assert = require('node:assert/strict');
7
+ const { skillId, runtimePath } = require('./identifiers.cjs');
7
8
  const runtimeRoots = ['skills', 'references', 'agents', 'commands', '.claude/commands', '.gemini/commands', 'hooks', '.claude-plugin', '.codex-plugin', '.agents/plugins'];
8
9
  const runtimeFiles = ['plugin.json', 'LICENSE'];
9
10
 
@@ -46,10 +47,23 @@ function catalog(root) {
46
47
  for (const name of runtimeFiles) if (fs.existsSync(path.join(root, name))) files.push(name);
47
48
  return describe(files, file => fs.readFileSync(path.join(root, file), 'utf8'));
48
49
  }
49
- function validateCatalog(root, expected) {
50
+ function validateCatalog(root, expected, { branded = false } = {}) {
50
51
  const actual = catalog(root);
52
+ const mapped = branded ? {
53
+ ...expected,
54
+ skills: expected.skills.map(skillId),
55
+ commands: expected.commands.map(skillId),
56
+ runtimeFiles: expected.runtimeFiles.map(file => runtimePath(file, false, expected)).sort(),
57
+ skillFrontmatter: Object.fromEntries(expected.skills.map(id => {
58
+ const name = skillId(id);
59
+ const head = frontmatter(fs.readFileSync(path.join(root, 'skills', name, 'SKILL.md'), 'utf8'));
60
+ const normalized = head.replace(new RegExp(`^name:.*$`, 'm'), `name: ${id}`).replace(/\r\n/g, '\n');
61
+ actual.skillFrontmatter[name] = crypto.createHash('sha256').update(normalized).digest('hex');
62
+ return [name, expected.skillFrontmatter[id]];
63
+ })),
64
+ } : expected;
51
65
  for (const field of ['skills', 'commands', 'personas', 'references', 'runtimeFiles', 'skillFrontmatter']) {
52
- assert.deepEqual(actual[field], expected[field], `upstream preservation failed: ${field}`);
66
+ assert.deepEqual(actual[field], mapped[field], `upstream preservation failed: ${field}`);
53
67
  }
54
68
  return actual;
55
69
  }
@@ -1,4 +1,19 @@
1
1
  [
2
+ {
3
+ "file": "scripts/lib/skill-lint.js",
4
+ "from": "const SECTION_EXEMPT_SKILLS = {",
5
+ "to": "const SECTION_EXEMPT_SKILLS = {\n 'i3-using-agent-skills': 'Branded alias of the reviewed upstream meta-skill.',\n 'i3-idea-refine': 'Branded alias of the reviewed upstream legacy structure.',"
6
+ },
7
+ {
8
+ "file": "scripts/validate-artifact-paths.js",
9
+ "from": "function findViolations(relPath) {",
10
+ "to": "GUARDED_FILES.push(...GUARDED_FILES.filter(relative => /(?:^|\\/)commands\\//.test(relative)).map(relative => relative.replace(/(commands\\/)([^/]+)(\\.md|\\.toml)$/, '$1i3-$2$3')));\n\nfunction findViolations(relPath) {"
11
+ },
12
+ {
13
+ "file": "scripts/validate-commands.js",
14
+ "from": " plan: 'planning',",
15
+ "to": " plan: 'planning',\n 'i3-plan': 'i3-planning',"
16
+ },
2
17
  {
3
18
  "file": "scripts/validate-versions.js",
4
19
  "from": "const manifestPaths = [\n \"plugin.json\",",
@@ -0,0 +1,41 @@
1
+ 'use strict';
2
+
3
+ const upstream = require('./upstream.json');
4
+ const prefix = 'i3-';
5
+ const skillId = id => prefix + id;
6
+ const escape = value => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
7
+
8
+ function runtimePath(relative, reverse = false, inventory = upstream) {
9
+ const skills = new Map(inventory.skills.map(id => reverse ? [skillId(id), id] : [id, skillId(id)]));
10
+ relative = relative.replace(/^(skills|evals\/fixtures)\/([^/]+)(?=\/|$)/, (match, folder, id) => skills.has(id) ? `${folder}/${skills.get(id)}` : match);
11
+ relative = relative.replace(/^evals\/cases\/([^/]+)\.json$/, (match, id) => skills.has(id) ? `evals/cases/${skills.get(id)}.json` : match);
12
+ const commands = inventory.runtimeFiles.filter(file => /^(?:\.claude\/commands|\.gemini\/commands|commands)\/[^/]+\.(?:md|toml)$/.test(file));
13
+ for (const file of commands) {
14
+ const branded = file.replace(/([^/]+)\.(md|toml)$/, `${prefix}$1.$2`);
15
+ if (relative === (reverse ? branded : file)) return reverse ? file : branded;
16
+ }
17
+ return relative;
18
+ }
19
+
20
+ function rewriteReferences(content, reverse = false, inventory = upstream, commandReferences = true) {
21
+ const skills = new Map(inventory.skills.map(id => reverse ? [skillId(id), id] : [id, skillId(id)]));
22
+ const names = [...new Set([...inventory.commands, ...inventory.runtimeFiles.filter(file => /commands\/[^/]+\.toml$/.test(file)).map(file => file.split('/').at(-1).slice(0, -5))])];
23
+ const commands = new Map(names.map(id => reverse ? [prefix + id, id] : [id, prefix + id]));
24
+ const skillPattern = new RegExp(`(?<![\\w-])(${[...skills.keys()].map(escape).join('|')})(?![\\w-]|\\.(?:sh|py|js|cjs)\\b)`, 'g');
25
+ const commandPattern = [...commands.keys()].map(escape).join('|');
26
+ const slash = new RegExp(`(?<![\\w/.-])/(${commandPattern})(?![\\w-])`, 'g');
27
+ const filenames = new RegExp(`(commands/)(${commandPattern})\\.(md|toml)\\b`, 'g');
28
+ const namespace = new RegExp(`((?:agent-skills|i3-composer-agent|\\$\\{name\\}):)(${commandPattern})(?![\\w-])`, 'g');
29
+ // External links refer to the upstream repository's original paths.
30
+ return content.split(/(https?:\/\/[^\s)'"<>`]+)/g).map(part => {
31
+ if (/^https?:\/\//.test(part)) return part;
32
+ part = part.replace(skillPattern, match => skills.get(match));
33
+ if (!commandReferences) return part;
34
+ return part
35
+ .replace(slash, (_, id) => '/' + commands.get(id))
36
+ .replace(filenames, (_, folder, id, extension) => `${folder}${commands.get(id)}.${extension}`)
37
+ .replace(namespace, (_, scope, id) => scope + commands.get(id));
38
+ }).join('');
39
+ }
40
+
41
+ module.exports = { prefix, skillId, runtimePath, rewriteReferences };
@@ -1,5 +1,22 @@
1
1
  # i3 Composer Agent changes
2
2
 
3
+ ## 2.0.0 — 2026-10-07
4
+
5
+ Upstream baseline: agent-skills 0.6.12 at commit 1401c8b8030e023baeebb31781a6653fe8e93026.
6
+
7
+ ### Changed
8
+
9
+ - Commands and Skill IDs use the `i3-` prefix, such as `/i3-spec` and `$i3-spec-driven-development`.
10
+ - Native upgrades back up and retire this package's manifest-owned unprefixed paths. Unowned entries remain in place; failed migrations roll back.
11
+ - Local command references, hooks, routing fixtures and setup documentation follow the renamed identifiers.
12
+
13
+ ### Migration
14
+
15
+ - Replace `/spec`, `/plan`, `/build` and other lifecycle calls with `/i3-spec`, `/i3-plan`, `/i3-build` and their prefixed equivalents. Plugin calls use `/i3-composer-agent:i3-<command>`.
16
+ - Replace Skill calls such as `$spec-driven-development` with `$i3-spec-driven-development`.
17
+ - Upgrade with `npx @givolt/i3-composer-agent@2.0.0 --codebuddy`, confirm replacement, then reload the host. The installer backs up manifest-owned legacy entries before retiring them.
18
+ - Keep using the pinned 1.0.1 package if a consuming workflow needs the old identifiers. Existing published versions remain available.
19
+
3
20
  ## 1.0.1 — 2026-10-07
4
21
 
5
22
  Upstream baseline: agent-skills 0.6.12 at commit 1401c8b8030e023baeebb31781a6653fe8e93026.
@@ -127,7 +127,7 @@ function prepare() {
127
127
  } else {
128
128
  console.log(`/plugin marketplace add ${quote(directory)}`);
129
129
  console.log(`/plugin install ${selector}`);
130
- console.log(`Use /${name}:spec, /${name}:plan, /${name}:build, and /${name}:ship in ${host === 'claude' ? 'Claude Code' : 'CodeBuddy'}.`);
130
+ console.log(`Use /${name}:i3-spec, /${name}:i3-plan, /${name}:i3-build, and /${name}:i3-ship in ${host === 'claude' ? 'Claude Code' : 'CodeBuddy'}.`);
131
131
  }
132
132
  }
133
133
  async function main() {
@@ -180,7 +180,7 @@ async function main() {
180
180
  console.log(identity);
181
181
  for (const target of plan.targets) {
182
182
  console.log(`Installed ${target.agents.join(', ')} skills at ${target.skillsDirectory}`);
183
- if (target.commandsDirectory) console.log(`Commands: /spec, /plan, /build, /ship (all ${fs.readdirSync(target.commandsDirectory).filter(file => file.endsWith('.md')).length} workflows) at ${target.commandsDirectory}`);
183
+ if (target.commandsDirectory) console.log(`Commands: /i3-spec, /i3-plan, /i3-build, /i3-ship (all ${fs.readdirSync(target.commandsDirectory).filter(file => file.endsWith('.md')).length} workflows) at ${target.commandsDirectory}`);
184
184
  }
185
185
  for (const backup of backups) console.log(`Previous assets preserved at ${backup}`);
186
186
  console.log('Reload the IDE window or start a new host session to discover installed files.');
@@ -5,6 +5,7 @@ const path = require('node:path');
5
5
  const os = require('node:os');
6
6
  const crypto = require('node:crypto');
7
7
  const registry = require('./agent-targets.json');
8
+ const upstream = require('../rebrand/upstream.json');
8
9
  const root = path.resolve(__dirname, '..');
9
10
  const name = 'i3-composer-agent';
10
11
  const aliases = { claude: 'claude-code', gemini: 'gemini-cli', copilot: 'github-copilot' };
@@ -82,7 +83,19 @@ function planInstallation({ agents, scope, projectDir = process.cwd(), home = os
82
83
  }
83
84
  assets.push({ source: path.join(root, 'LICENSE'), destination: destination(path.join(target.base, `${name}-LICENSE`)), kind: 'attribution' });
84
85
  assets.push({ source: path.join(root, 'NOTICE.md'), destination: destination(path.join(target.base, `${name}-NOTICE.md`)), kind: 'attribution' });
85
- assets.push({ target, destination: destination(path.join(target.base, `.${name}.json`)), kind: 'manifest' });
86
+ const manifestFile = path.join(target.base, `.${name}.json`);
87
+ if (exists(manifestFile)) {
88
+ const previous = JSON.parse(fs.readFileSync(manifestFile, 'utf8'));
89
+ if (previous.name === name && Array.isArray(previous.assets)) {
90
+ const legacy = upstream.skills.map(id => `skills/${id}`);
91
+ if (target.commandsDirectory) legacy.push(...upstream.commands.map(id => `commands/${id}.md`));
92
+ for (const relative of legacy) {
93
+ const file = destination(path.join(target.base, relative));
94
+ if (previous.assets.includes(relative) && exists(file)) assets.push({ destination: file, kind: 'legacy' });
95
+ }
96
+ }
97
+ }
98
+ assets.push({ target, destination: destination(manifestFile), kind: 'manifest' });
86
99
  for (const asset of assets.slice(start)) {
87
100
  asset.base = target.base;
88
101
  asset.codebuddyCommand = asset.kind === 'command' && target.agents.includes('codebuddy');
@@ -120,9 +133,10 @@ function executeInstallation(plan, { force = false } = {}) {
120
133
  contexts.set(asset.base, { staging: fs.mkdtempSync(path.join(asset.base, `.${name}-stage-`)), backup: path.join(asset.base, `.${name}-backup-${crypto.randomUUID()}`) });
121
134
  }
122
135
  const context = contexts.get(asset.base);
136
+ if (asset.kind === 'legacy') continue;
123
137
  asset.staged = path.join(context.staging, String(index));
124
138
  if (asset.kind === 'manifest') {
125
- fs.writeFileSync(asset.staged, JSON.stringify({ name, version: pkg.version, upstreamVersion: pkg.i3ComposerAgent.upstreamVersion, upstreamCommit: pkg.i3ComposerAgent.upstreamCommit, scope: plan.scope, agents: asset.target.agents, assets: plan.assets.filter(item => item.base === asset.base).map(item => path.relative(asset.base, item.destination)) }, null, 2) + '\n');
139
+ fs.writeFileSync(asset.staged, JSON.stringify({ name, version: pkg.version, entryPrefix: 'i3-', upstreamVersion: pkg.i3ComposerAgent.upstreamVersion, upstreamCommit: pkg.i3ComposerAgent.upstreamCommit, scope: plan.scope, agents: asset.target.agents, assets: plan.assets.filter(item => item.base === asset.base && item.kind !== 'legacy').map(item => path.relative(asset.base, item.destination)) }, null, 2) + '\n');
126
140
  } else {
127
141
  fs.cpSync(asset.source, asset.staged, { recursive: true, filter: file => {
128
142
  if (fs.lstatSync(file).isSymbolicLink()) throw new Error(`Package contains a symlink: ${file}`);
@@ -143,8 +157,10 @@ function executeInstallation(plan, { force = false } = {}) {
143
157
  fs.renameSync(asset.destination, change.backup);
144
158
  }
145
159
  committed.push(change);
146
- fs.renameSync(asset.staged, asset.destination);
147
- change.written = true;
160
+ if (asset.kind !== 'legacy') {
161
+ fs.renameSync(asset.staged, asset.destination);
162
+ change.written = true;
163
+ }
148
164
  }
149
165
  return [...contexts.values()].map(context => context.backup).filter(exists);
150
166
  } catch (error) {
@@ -9,7 +9,7 @@ const brand = require('../rebrand/brand.json');
9
9
  const pkg = require('../package.json');
10
10
  const upstream = require('../rebrand/upstream.json');
11
11
  const { validateCatalog } = require('../rebrand/catalog.cjs');
12
- validateCatalog(root, upstream);
12
+ validateCatalog(root, upstream, { branded: true });
13
13
  function json(relative) { return JSON.parse(fs.readFileSync(path.join(root, relative), 'utf8')); }
14
14
  assert.equal(pkg.name, brand.npmName);
15
15
  assert.equal(pkg.version, brand.releaseVersion);
@@ -31,13 +31,13 @@ for (const relative of ['.claude-plugin/marketplace.json', '.agents/plugins/mark
31
31
  assert.ok(json('.codex-plugin/plugin.json').interface.shortDescription.length <= 30);
32
32
  const skills = fs.readdirSync(path.join(root, 'skills')).filter(name => fs.existsSync(path.join(root, 'skills', name, 'SKILL.md')));
33
33
  assert.equal(skills.length, upstream.skills.length, 'brand conversion must preserve the reviewed upstream skills');
34
- assert.ok(skills.includes('using-agent-skills'), 'meta-skill ID must remain stable');
34
+ assert.ok(skills.includes('i3-using-agent-skills'), 'meta-skill ID must use the branded prefix');
35
35
  const commands = fs.readdirSync(path.join(root, '.claude/commands')).filter(name => name.endsWith('.md'));
36
36
  assert.equal(commands.length, upstream.commands.length, 'brand conversion must preserve the reviewed upstream commands');
37
37
  for (const command of commands) {
38
38
  const body = fs.readFileSync(path.join(root, '.claude/commands', command), 'utf8');
39
39
  assert.ok(!body.includes('agent-skills:'), `${command}: stale plugin namespace`);
40
- for (const match of body.matchAll(/i3-composer-agent:([a-z-]+)/g)) assert.ok(skills.includes(match[1]), `${command}: unknown skill ${match[1]}`);
40
+ for (const match of body.matchAll(/(?<!\/)i3-composer-agent:([a-z0-9-]+)/g)) assert.ok(skills.includes(match[1]), `${command}: unknown skill ${match[1]}`);
41
41
  }
42
42
  for (const relative of pkg.i3ComposerAgent.pluginFiles) assert.ok(fs.existsSync(path.join(root, relative)), `bundle is missing ${relative}`);
43
43
  assert.match(fs.readFileSync(path.join(root, 'LICENSE'), 'utf8'), /Copyright \(c\) 2025 Addy Osmani/);
@@ -25,10 +25,10 @@ test('native CodeBuddy installation includes short commands, personas and usable
25
25
  assert.equal(fs.readdirSync(path.join(base, 'skills')).length, upstream.skills.length);
26
26
  assert.equal(fs.readdirSync(path.join(base, 'commands')).length, upstream.commands.length);
27
27
  assert.equal(fs.readdirSync(path.join(base, 'agents')).length, upstream.personas.length);
28
- const command = fs.readFileSync(path.join(base, 'commands/spec.md'), 'utf8');
29
- assert.match(command, /Invoke the spec-driven-development skill/);
28
+ const command = fs.readFileSync(path.join(base, 'commands/i3-spec.md'), 'utf8');
29
+ assert.match(command, /Invoke the i3-spec-driven-development skill/);
30
30
  assert.doesNotMatch(command, /i3-composer-agent:/);
31
- const ship = fs.readFileSync(path.join(base, 'commands/ship.md'), 'utf8');
31
+ const ship = fs.readFileSync(path.join(base, 'commands/i3-ship.md'), 'utf8');
32
32
  assert.match(ship, /\.codebuddy\/agents\//);
33
33
  assert.doesNotMatch(ship, /\.claude\/agents\//);
34
34
  assert.ok(fs.existsSync(path.join(base, 'references/definition-of-done.md')));
@@ -36,7 +36,7 @@ test('native CodeBuddy installation includes short commands, personas and usable
36
36
  assert.match(fs.readFileSync(path.join(base, 'i3-composer-agent-NOTICE.md'), 'utf8'), /Addy Osmani/);
37
37
  assert.equal(fs.existsSync(path.join(directory, 'AGENTS.md')), false);
38
38
  assert.equal(fs.existsSync(path.join(directory, 'i3-composer-agent')), false);
39
- assert.match(result.stdout, /\/spec/);
39
+ assert.match(result.stdout, /\/i3-spec/);
40
40
  });
41
41
  test('multiple tools retain their own destinations and share universal skills without duplicate work', t => {
42
42
  const directory = workspace(t);
@@ -80,16 +80,64 @@ test('all copied Markdown reference links and stable skill frontmatter remain va
80
80
  }
81
81
  }
82
82
  visit(path.join(base, 'skills'));
83
- for (const id of upstream.skills) {
83
+ for (const id of upstream.skills.map(id => `i3-${id}`)) {
84
84
  const head = content => content.match(/^---\r?\n[\s\S]*?\r?\n---/)[0];
85
85
  assert.equal(head(fs.readFileSync(path.join(base, 'skills', id, 'SKILL.md'), 'utf8')), head(fs.readFileSync(path.join(root, 'skills', id, 'SKILL.md'), 'utf8')));
86
86
  }
87
87
  });
88
+ function legacyInstallation(directory) {
89
+ const base = path.join(directory, '.codebuddy');
90
+ fs.mkdirSync(path.join(base, 'commands'), { recursive: true });
91
+ fs.mkdirSync(path.join(base, 'skills/spec-driven-development'), { recursive: true });
92
+ fs.writeFileSync(path.join(base, 'commands/spec.md'), 'original owned command');
93
+ fs.writeFileSync(path.join(base, 'skills/spec-driven-development/SKILL.md'), 'original owned Skill');
94
+ fs.writeFileSync(path.join(base, 'commands/build.md'), 'unowned custom command');
95
+ fs.writeFileSync(path.join(base, '.i3-composer-agent.json'), JSON.stringify({ name: 'i3-composer-agent', version: '1.0.1', assets: ['commands/spec.md', 'skills/spec-driven-development'] }));
96
+ return base;
97
+ }
98
+ test('prefix migration retires only owned legacy paths and preserves their backups', t => {
99
+ const directory = workspace(t);
100
+ const base = legacyInstallation(directory);
101
+ const args = ['--codebuddy', '--scope', 'project', '--yes'];
102
+ assert.equal(run(directory, args).status, 1);
103
+ assert.equal(fs.readFileSync(path.join(base, 'commands/spec.md'), 'utf8'), 'original owned command');
104
+ const result = run(directory, [...args, '--force']);
105
+ assert.equal(result.status, 0, result.stderr);
106
+ assert.equal(fs.existsSync(path.join(base, 'commands/spec.md')), false);
107
+ assert.equal(fs.existsSync(path.join(base, 'skills/spec-driven-development')), false);
108
+ assert.ok(fs.existsSync(path.join(base, 'commands/i3-spec.md')));
109
+ assert.match(fs.readFileSync(path.join(base, 'skills/i3-spec-driven-development/SKILL.md'), 'utf8'), /^name: i3-spec-driven-development$/m);
110
+ assert.equal(fs.readFileSync(path.join(base, 'commands/build.md'), 'utf8'), 'unowned custom command');
111
+ const backup = fs.readdirSync(base).find(file => file.startsWith('.i3-composer-agent-backup-'));
112
+ assert.equal(fs.readFileSync(path.join(base, backup, 'commands/spec.md'), 'utf8'), 'original owned command');
113
+ assert.equal(fs.readFileSync(path.join(base, backup, 'skills/spec-driven-development/SKILL.md'), 'utf8'), 'original owned Skill');
114
+ const manifest = JSON.parse(fs.readFileSync(path.join(base, '.i3-composer-agent.json'), 'utf8'));
115
+ assert.equal(manifest.entryPrefix, 'i3-');
116
+ assert.ok(!manifest.assets.includes('commands/spec.md'));
117
+ });
118
+ test('a failure after retiring legacy paths rolls the migration back', t => {
119
+ const directory = workspace(t);
120
+ const base = legacyInstallation(directory);
121
+ const before = fs.readFileSync(path.join(base, '.i3-composer-agent.json'), 'utf8');
122
+ const { planInstallation, executeInstallation } = require('../bin/install.cjs');
123
+ const plan = planInstallation({ agents: ['codebuddy'], scope: 'project', projectDir: directory });
124
+ const realRename = fs.renameSync;
125
+ fs.renameSync = (source, destination) => {
126
+ if (destination === path.join(base, '.i3-composer-agent.json') && source.includes('-stage-')) throw new Error('simulated manifest failure');
127
+ return realRename(source, destination);
128
+ };
129
+ try { assert.throws(() => executeInstallation(plan, { force: true }), /simulated manifest failure/); }
130
+ finally { fs.renameSync = realRename; }
131
+ assert.equal(fs.readFileSync(path.join(base, '.i3-composer-agent.json'), 'utf8'), before);
132
+ assert.equal(fs.readFileSync(path.join(base, 'commands/spec.md'), 'utf8'), 'original owned command');
133
+ assert.equal(fs.readFileSync(path.join(base, 'skills/spec-driven-development/SKILL.md'), 'utf8'), 'original owned Skill');
134
+ assert.equal(fs.existsSync(path.join(base, 'commands/i3-spec.md')), false);
135
+ });
88
136
  test('existing assets are protected; confirmed replacement backs them up and preserves unrelated settings', t => {
89
137
  const directory = workspace(t);
90
138
  const base = path.join(directory, '.codebuddy');
91
139
  fs.mkdirSync(path.join(base, 'commands'), { recursive: true });
92
- fs.writeFileSync(path.join(base, 'commands/spec.md'), 'my custom command');
140
+ fs.writeFileSync(path.join(base, 'commands/i3-spec.md'), 'my custom command');
93
141
  fs.writeFileSync(path.join(base, 'settings.json'), '{"keep":"my settings"}\n');
94
142
  const args = ['--codebuddy', '--scope', 'project', '--yes'];
95
143
  assert.equal(run(directory, args).status, 1);
@@ -98,7 +146,7 @@ test('existing assets are protected; confirmed replacement backs them up and pre
98
146
  assert.equal(result.status, 0, result.stderr);
99
147
  const backups = fs.readdirSync(base).filter(file => file.startsWith('.i3-composer-agent-backup-'));
100
148
  assert.equal(backups.length, 1);
101
- assert.equal(fs.readFileSync(path.join(base, backups[0], 'commands/spec.md'), 'utf8'), 'my custom command');
149
+ assert.equal(fs.readFileSync(path.join(base, backups[0], 'commands/i3-spec.md'), 'utf8'), 'my custom command');
102
150
  assert.equal(fs.readFileSync(path.join(base, 'settings.json'), 'utf8'), '{"keep":"my settings"}\n');
103
151
  assert.equal(fs.existsSync(path.join(base, backups[0], 'settings.json')), false);
104
152
  });
@@ -133,7 +181,7 @@ test('the pinned tool catalog plans all project choices and rejects unsupported
133
181
  test('failed installation restores prior assets and removes all newly written files', t => {
134
182
  const directory = workspace(t);
135
183
  const { planInstallation, executeInstallation } = require('../bin/install.cjs');
136
- const prior = path.join(directory, '.codebuddy/skills/api-and-interface-design');
184
+ const prior = path.join(directory, '.codebuddy/skills/i3-api-and-interface-design');
137
185
  fs.mkdirSync(prior, { recursive: true });
138
186
  fs.writeFileSync(path.join(prior, 'custom.md'), 'prior skill content');
139
187
  const plan = planInstallation({ agents: ['codebuddy', 'codex'], scope: 'project', projectDir: directory });
@@ -146,7 +194,7 @@ test('failed installation restores prior assets and removes all newly written fi
146
194
  try { assert.throws(() => executeInstallation(plan, { force: true }), /simulated disk failure/); }
147
195
  finally { fs.renameSync = realRename; }
148
196
  assert.equal(fs.readFileSync(path.join(prior, 'custom.md'), 'utf8'), 'prior skill content');
149
- assert.deepEqual(fs.readdirSync(path.dirname(prior)), ['api-and-interface-design']);
197
+ assert.deepEqual(fs.readdirSync(path.dirname(prior)), ['i3-api-and-interface-design']);
150
198
  assert.deepEqual(fs.readdirSync(path.join(directory, '.codebuddy')), ['skills']);
151
199
  assert.equal(fs.existsSync(path.join(directory, '.agents')), false);
152
200
  });
@@ -157,14 +205,14 @@ test('replacing a skill symlink backs up the link and leaves its external source
157
205
  fs.mkdirSync(external);
158
206
  fs.writeFileSync(path.join(external, 'custom.md'), 'external source');
159
207
  fs.mkdirSync(skills, { recursive: true });
160
- fs.symlinkSync(external, path.join(skills, 'spec-driven-development'), 'dir');
208
+ fs.symlinkSync(external, path.join(skills, 'i3-spec-driven-development'), 'dir');
161
209
  const result = run(directory, ['--codebuddy', '--scope', 'project', '--yes', '--force']);
162
210
  assert.equal(result.status, 0, result.stderr);
163
211
  assert.deepEqual(fs.readdirSync(external), ['custom.md']);
164
- assert.equal(fs.lstatSync(path.join(skills, 'spec-driven-development')).isSymbolicLink(), false);
212
+ assert.equal(fs.lstatSync(path.join(skills, 'i3-spec-driven-development')).isSymbolicLink(), false);
165
213
  const base = path.dirname(skills);
166
214
  const backup = fs.readdirSync(base).find(file => file.startsWith('.i3-composer-agent-backup-'));
167
- assert.equal(fs.lstatSync(path.join(base, backup, 'skills/spec-driven-development')).isSymbolicLink(), true);
215
+ assert.equal(fs.lstatSync(path.join(base, backup, 'skills/i3-spec-driven-development')).isSymbolicLink(), true);
168
216
  });
169
217
  test('package destinations, shared directory symlinks and ambiguous noninteractive flags fail without writes', t => {
170
218
  const directory = workspace(t);
@@ -9,7 +9,7 @@ Based on [Agent Skills](https://github.com/addyosmani/agent-skills) by Addy Osma
9
9
  (MIT). See [NOTICE.md](NOTICE.md) for attribution.
10
10
 
11
11
  The npm package is `@givolt/i3-composer-agent`; the plugin and marketplace ID is
12
- `i3-composer-agent`. Skill IDs retain their upstream names.
12
+ `i3-composer-agent`. Commands and Skill IDs use the `i3-` prefix.
13
13
 
14
14
  ## Install with the wizard
15
15
 
@@ -49,6 +49,12 @@ under each tool configuration root. Unrelated settings are left in place.
49
49
  `npx -y` accepts npm's package download prompt; the package's own `--yes` flag
50
50
  accepts the explicit installation plan.
51
51
 
52
+ Earlier native installations migrate their unprefixed Skill and command paths
53
+ when those paths belong to this package's previous installation manifest.
54
+ The migration preserves legacy paths in the backup directory. Unowned entries
55
+ remain in place. Use `/i3-spec` in CodeBuddy or `$i3-spec-driven-development`
56
+ in Codex after upgrading.
57
+
52
58
  ## Prepare the complete plugin
53
59
 
54
60
  For native plugin registration, including plugin hooks, explicitly prepare a
@@ -78,21 +84,21 @@ codex plugin marketplace add ./i3-composer-agent
78
84
  codex plugin add i3-composer-agent@i3-composer-agent
79
85
  ```
80
86
 
81
- Start a new session after enabling the plugin. Codex uses the existing Skill
82
- names, such as `$spec-driven-development`; lifecycle slash-command adaptation
87
+ Start a new session after enabling the plugin. Codex uses the branded Skill
88
+ names, such as `$i3-spec-driven-development`; lifecycle slash-command adaptation
83
89
  is maintained separately.
84
90
 
85
91
  ## Commands
86
92
 
87
93
  Native CodeBuddy and Claude Code installations use short filenames such as
88
- `/spec`, `/plan`, `/build` and `/ship`. Hosts supporting Claude-compatible plugin
94
+ `/i3-spec`, `/i3-plan`, `/i3-build` and `/i3-ship`. Hosts supporting Claude-compatible plugin
89
95
  commands load the same workflows under the plugin namespace:
90
96
 
91
97
  | Command | Description |
92
98
  | --- | --- |
93
99
  {{COMMAND_TABLE}}
94
100
 
95
- `/i3-composer-agent:build auto` runs the existing approved-plan workflow.
101
+ `/i3-composer-agent:i3-build auto` runs the existing approved-plan workflow.
96
102
 
97
103
  ## Skills
98
104