@givolt/i3-composer-agent 1.0.0 → 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 (210) 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 +29 -1
  24. package/NOTICE.md +8 -2
  25. package/README.md +98 -54
  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/agent-targets.json +726 -0
  31. package/bin/i3-composer-agent.cjs +84 -16
  32. package/bin/install.cjs +180 -0
  33. package/bin/skills-registry.LICENSE +21 -0
  34. package/bin/wizard.cjs +66 -0
  35. package/commands/{build.toml → i3-build.toml} +10 -10
  36. package/commands/{code-simplify.toml → i3-code-simplify.toml} +2 -2
  37. package/commands/{constraints.toml → i3-constraints.toml} +4 -4
  38. package/commands/{planning.toml → i3-planning.toml} +1 -1
  39. package/{.gemini/commands/review.toml → commands/i3-review.toml} +3 -3
  40. package/commands/{ship.toml → i3-ship.toml} +4 -4
  41. package/commands/{spec.toml → i3-spec.toml} +1 -1
  42. package/{.gemini/commands/test.toml → commands/i3-test.toml} +2 -2
  43. package/commands/{webperf.toml → i3-webperf.toml} +1 -1
  44. package/docs/adoption-guide.md +35 -35
  45. package/docs/agents.md +12 -12
  46. package/docs/antigravity-setup.md +14 -14
  47. package/docs/codebuddy-setup.md +64 -16
  48. package/docs/codex-setup.md +17 -6
  49. package/docs/commandcode-setup.md +5 -5
  50. package/docs/copilot-cli-setup.md +5 -5
  51. package/docs/copilot-setup.md +22 -22
  52. package/docs/cursor-setup.md +20 -20
  53. package/docs/developer-onboarding.md +5 -5
  54. package/docs/gemini-cli-setup.md +26 -26
  55. package/docs/getting-started.md +36 -36
  56. package/docs/opencode-setup.md +27 -27
  57. package/docs/skill-anatomy.md +3 -3
  58. package/docs/windsurf-setup.md +7 -7
  59. package/evals/cases/{api-and-interface-design.json → i3-api-and-interface-design.json} +4 -4
  60. package/evals/cases/{browser-testing-with-devtools.json → i3-browser-testing-with-devtools.json} +4 -4
  61. package/evals/cases/{ci-cd-and-automation.json → i3-ci-cd-and-automation.json} +4 -4
  62. package/evals/cases/{code-review-and-quality.json → i3-code-review-and-quality.json} +4 -4
  63. package/evals/cases/{code-simplification.json → i3-code-simplification.json} +4 -4
  64. package/evals/cases/{constraint-driven-development.json → i3-constraint-driven-development.json} +4 -4
  65. package/evals/cases/{context-engineering.json → i3-context-engineering.json} +4 -4
  66. package/evals/cases/{debugging-and-error-recovery.json → i3-debugging-and-error-recovery.json} +5 -5
  67. package/evals/cases/{deprecation-and-migration.json → i3-deprecation-and-migration.json} +4 -4
  68. package/evals/cases/{documentation-and-adrs.json → i3-documentation-and-adrs.json} +4 -4
  69. package/evals/cases/{doubt-driven-development.json → i3-doubt-driven-development.json} +3 -3
  70. package/evals/cases/{frontend-ui-engineering.json → i3-frontend-ui-engineering.json} +4 -4
  71. package/evals/cases/{git-workflow-and-versioning.json → i3-git-workflow-and-versioning.json} +3 -3
  72. package/evals/cases/{idea-refine.json → i3-idea-refine.json} +3 -3
  73. package/evals/cases/{incremental-implementation.json → i3-incremental-implementation.json} +4 -4
  74. package/evals/cases/{interview-me.json → i3-interview-me.json} +3 -3
  75. package/evals/cases/{observability-and-instrumentation.json → i3-observability-and-instrumentation.json} +3 -3
  76. package/evals/cases/{performance-optimization.json → i3-performance-optimization.json} +4 -4
  77. package/evals/cases/{planning-and-task-breakdown.json → i3-planning-and-task-breakdown.json} +4 -4
  78. package/evals/cases/{security-and-hardening.json → i3-security-and-hardening.json} +4 -4
  79. package/evals/cases/{shipping-and-launch.json → i3-shipping-and-launch.json} +4 -4
  80. package/evals/cases/{source-driven-development.json → i3-source-driven-development.json} +4 -4
  81. package/evals/cases/{spec-driven-development.json → i3-spec-driven-development.json} +5 -5
  82. package/evals/cases/{test-driven-development.json → i3-test-driven-development.json} +5 -5
  83. package/evals/cases/{using-agent-skills.json → i3-using-agent-skills.json} +4 -4
  84. package/evals/fixtures/{git-workflow-and-versioning → i3-git-workflow-and-versioning}/.eval/working-tree.patch +3 -3
  85. package/evals/plugin/code-review-fires/graders/skill-fired.md +1 -1
  86. package/evals/plugin/code-review-stays-quiet/graders/not-fired.md +1 -1
  87. package/evals/plugin/code-review-stays-quiet/graders/tdd-fired.md +1 -1
  88. package/evals/plugin/code-review-stays-quiet/prompt.md +2 -2
  89. package/evals/plugin/code-review-stays-quiet-on-commit-message/graders/not-fired.md +1 -1
  90. package/evals/plugin/code-review-stays-quiet-on-commit-message/prompt.md +2 -2
  91. package/hooks/SDD-CACHE.md +3 -3
  92. package/hooks/SIMPLIFY-IGNORE.md +2 -2
  93. package/hooks/session-start-test.sh +1 -1
  94. package/hooks/session-start.sh +3 -3
  95. package/package.json +1 -1
  96. package/plugin.json +1 -1
  97. package/rebrand/INSTALLATION-SPEC.md +47 -0
  98. package/rebrand/MAINTENANCE.md +5 -3
  99. package/rebrand/NOTICE.md +8 -2
  100. package/rebrand/PREFIX-SPEC.md +16 -0
  101. package/rebrand/UNIFICATION-SPEC.md +2 -2
  102. package/rebrand/VALIDATION.md +6 -2
  103. package/rebrand/VERSIONING.md +8 -5
  104. package/rebrand/apply.cjs +33 -10
  105. package/rebrand/brand.json +1 -1
  106. package/rebrand/catalog.cjs +16 -2
  107. package/rebrand/fork-patches.json +15 -0
  108. package/rebrand/identifiers.cjs +41 -0
  109. package/rebrand/overlay/CHANGELOG.md +29 -1
  110. package/rebrand/overlay/bin/agent-targets.json +726 -0
  111. package/rebrand/overlay/bin/i3-composer-agent.cjs +84 -16
  112. package/rebrand/overlay/bin/install.cjs +180 -0
  113. package/rebrand/overlay/bin/skills-registry.LICENSE +21 -0
  114. package/rebrand/overlay/bin/wizard.cjs +66 -0
  115. package/rebrand/overlay/scripts/validate-brand.cjs +3 -3
  116. package/rebrand/overlay/tests/installer.test.cjs +241 -0
  117. package/rebrand/templates/README.md +62 -18
  118. package/rebrand/templates/codebuddy-setup.md +64 -16
  119. package/rebrand/templates/codex-setup.md +17 -6
  120. package/rebrand/tests/pipeline.test.cjs +71 -3
  121. package/references/accessibility-checklist.md +1 -1
  122. package/references/definition-of-done.md +7 -7
  123. package/references/observability-checklist.md +3 -3
  124. package/references/orchestration-patterns.md +17 -17
  125. package/references/performance-checklist.md +2 -2
  126. package/references/security-checklist.md +1 -1
  127. package/references/testing-patterns.md +1 -1
  128. package/scripts/floor-guard-reference-test.js +2 -2
  129. package/scripts/lib/skill-lint.js +2 -0
  130. package/scripts/run-evals-test.js +2 -2
  131. package/scripts/validate-artifact-paths-test.js +3 -3
  132. package/scripts/validate-artifact-paths.js +4 -2
  133. package/scripts/validate-brand.cjs +3 -3
  134. package/scripts/validate-commands.js +1 -0
  135. package/scripts/validate-reference-links-test.js +11 -11
  136. package/scripts/validate-reference-links.js +1 -1
  137. package/skills/{api-and-interface-design → i3-api-and-interface-design}/SKILL.md +2 -2
  138. package/skills/{browser-testing-with-devtools → i3-browser-testing-with-devtools}/SKILL.md +1 -1
  139. package/skills/{ci-cd-and-automation → i3-ci-cd-and-automation}/SKILL.md +2 -2
  140. package/skills/{code-review-and-quality → i3-code-review-and-quality}/SKILL.md +5 -5
  141. package/skills/{code-simplification → i3-code-simplification}/SKILL.md +1 -1
  142. package/skills/{constraint-driven-development → i3-constraint-driven-development}/SKILL.md +15 -15
  143. package/skills/{context-engineering → i3-context-engineering}/SKILL.md +1 -1
  144. package/skills/{debugging-and-error-recovery → i3-debugging-and-error-recovery}/SKILL.md +2 -2
  145. package/skills/{deprecation-and-migration → i3-deprecation-and-migration}/SKILL.md +2 -2
  146. package/skills/{documentation-and-adrs → i3-documentation-and-adrs}/SKILL.md +1 -1
  147. package/skills/{doubt-driven-development → i3-doubt-driven-development}/SKILL.md +8 -8
  148. package/skills/{frontend-ui-engineering → i3-frontend-ui-engineering}/SKILL.md +1 -1
  149. package/skills/{git-workflow-and-versioning → i3-git-workflow-and-versioning}/SKILL.md +4 -4
  150. package/skills/{idea-refine → i3-idea-refine}/SKILL.md +2 -2
  151. package/skills/{idea-refine → i3-idea-refine}/scripts/idea-refine.sh +1 -1
  152. package/skills/{incremental-implementation → i3-incremental-implementation}/SKILL.md +3 -3
  153. package/skills/{interview-me → i3-interview-me}/SKILL.md +12 -12
  154. package/skills/{observability-and-instrumentation → i3-observability-and-instrumentation}/SKILL.md +5 -5
  155. package/skills/{performance-optimization → i3-performance-optimization}/SKILL.md +1 -1
  156. package/skills/{performance-optimization → i3-performance-optimization}/references/optimization-patterns.md +1 -1
  157. package/skills/{planning-and-task-breakdown → i3-planning-and-task-breakdown}/SKILL.md +2 -2
  158. package/skills/{security-and-hardening → i3-security-and-hardening}/SKILL.md +3 -3
  159. package/skills/{security-and-hardening → i3-security-and-hardening}/references/hardening-patterns.md +1 -1
  160. package/skills/{shipping-and-launch → i3-shipping-and-launch}/SKILL.md +2 -2
  161. package/skills/{source-driven-development → i3-source-driven-development}/SKILL.md +2 -2
  162. package/skills/{spec-driven-development → i3-spec-driven-development}/SKILL.md +7 -7
  163. package/skills/{test-driven-development → i3-test-driven-development}/SKILL.md +2 -2
  164. package/skills/{using-agent-skills → i3-using-agent-skills}/SKILL.md +67 -67
  165. package/tests/installer.test.cjs +241 -0
  166. /package/evals/fixtures/{api-and-interface-design → i3-api-and-interface-design}/service-brief.md +0 -0
  167. /package/evals/fixtures/{browser-testing-with-devtools → i3-browser-testing-with-devtools}/README.md +0 -0
  168. /package/evals/fixtures/{browser-testing-with-devtools → i3-browser-testing-with-devtools}/index.html +0 -0
  169. /package/evals/fixtures/{browser-testing-with-devtools → i3-browser-testing-with-devtools}/server.js +0 -0
  170. /package/evals/fixtures/{ci-cd-and-automation → i3-ci-cd-and-automation}/package.json +0 -0
  171. /package/evals/fixtures/{ci-cd-and-automation → i3-ci-cd-and-automation}/src/slug.js +0 -0
  172. /package/evals/fixtures/{ci-cd-and-automation → i3-ci-cd-and-automation}/test/slug.test.js +0 -0
  173. /package/evals/fixtures/{code-review-and-quality → i3-code-review-and-quality}/user-search.diff +0 -0
  174. /package/evals/fixtures/{code-simplification → i3-code-simplification}/config-parser.js +0 -0
  175. /package/evals/fixtures/{code-simplification → i3-code-simplification}/config-parser.test.js +0 -0
  176. /package/evals/fixtures/{context-engineering → i3-context-engineering}/context-audit.md +0 -0
  177. /package/evals/fixtures/{debugging-and-error-recovery → i3-debugging-and-error-recovery}/pagination.js +0 -0
  178. /package/evals/fixtures/{debugging-and-error-recovery → i3-debugging-and-error-recovery}/pagination.test.js +0 -0
  179. /package/evals/fixtures/{debugging-and-error-recovery → i3-debugging-and-error-recovery}/time-pressure.md +0 -0
  180. /package/evals/fixtures/{deprecation-and-migration → i3-deprecation-and-migration}/api-inventory.md +0 -0
  181. /package/evals/fixtures/{documentation-and-adrs → i3-documentation-and-adrs}/decision-context.md +0 -0
  182. /package/evals/fixtures/{doubt-driven-development → i3-doubt-driven-development}/migration-plan.md +0 -0
  183. /package/evals/fixtures/{frontend-ui-engineering → i3-frontend-ui-engineering}/Button.tsx +0 -0
  184. /package/evals/fixtures/{frontend-ui-engineering → i3-frontend-ui-engineering}/design-system.md +0 -0
  185. /package/evals/fixtures/{git-workflow-and-versioning → i3-git-workflow-and-versioning}/app.js +0 -0
  186. /package/evals/fixtures/{git-workflow-and-versioning → i3-git-workflow-and-versioning}/app.test.js +0 -0
  187. /package/evals/fixtures/{incremental-implementation → i3-incremental-implementation}/reports.js +0 -0
  188. /package/evals/fixtures/{incremental-implementation → i3-incremental-implementation}/reports.test.js +0 -0
  189. /package/evals/fixtures/{incremental-implementation → i3-incremental-implementation}/tasks/plan.md +0 -0
  190. /package/evals/fixtures/{observability-and-instrumentation → i3-observability-and-instrumentation}/operations.md +0 -0
  191. /package/evals/fixtures/{observability-and-instrumentation → i3-observability-and-instrumentation}/payment-retry.js +0 -0
  192. /package/evals/fixtures/{performance-optimization → i3-performance-optimization}/benchmark.js +0 -0
  193. /package/evals/fixtures/{performance-optimization → i3-performance-optimization}/products.js +0 -0
  194. /package/evals/fixtures/{planning-and-task-breakdown → i3-planning-and-task-breakdown}/notifications-spec.md +0 -0
  195. /package/evals/fixtures/{security-and-hardening → i3-security-and-hardening}/webhook.js +0 -0
  196. /package/evals/fixtures/{security-and-hardening → i3-security-and-hardening}/webhook.test.js +0 -0
  197. /package/evals/fixtures/{shipping-and-launch → i3-shipping-and-launch}/authority-pressure.md +0 -0
  198. /package/evals/fixtures/{shipping-and-launch → i3-shipping-and-launch}/launch-status.md +0 -0
  199. /package/evals/fixtures/{source-driven-development → i3-source-driven-development}/framework-task.md +0 -0
  200. /package/evals/fixtures/{spec-driven-development → i3-spec-driven-development}/billing-brief.md +0 -0
  201. /package/evals/fixtures/{test-driven-development → i3-test-driven-development}/BUG.md +0 -0
  202. /package/evals/fixtures/{test-driven-development → i3-test-driven-development}/README.md +0 -0
  203. /package/evals/fixtures/{test-driven-development → i3-test-driven-development}/package.json +0 -0
  204. /package/evals/fixtures/{test-driven-development → i3-test-driven-development}/src/split.js +0 -0
  205. /package/evals/fixtures/{test-driven-development → i3-test-driven-development}/test/split.test.js +0 -0
  206. /package/evals/fixtures/{using-agent-skills → i3-using-agent-skills}/incident.md +0 -0
  207. /package/skills/{constraint-driven-development → i3-constraint-driven-development}/references/floor-guard.md +0 -0
  208. /package/skills/{idea-refine → i3-idea-refine}/examples.md +0 -0
  209. /package/skills/{idea-refine → i3-idea-refine}/frameworks.md +0 -0
  210. /package/skills/{idea-refine → i3-idea-refine}/refinement-criteria.md +0 -0
@@ -0,0 +1,241 @@
1
+ 'use strict';
2
+
3
+ const test = require('node:test');
4
+ const assert = require('node:assert/strict');
5
+ const fs = require('node:fs');
6
+ const os = require('node:os');
7
+ const path = require('node:path');
8
+ const { spawnSync } = require('node:child_process');
9
+ const root = path.resolve(__dirname, '..');
10
+ const cli = path.join(root, 'bin/i3-composer-agent.cjs');
11
+ const upstream = require('../rebrand/upstream.json');
12
+ function workspace(t) {
13
+ const directory = fs.mkdtempSync(path.join(os.tmpdir(), 'i3-agent-install-'));
14
+ t.after(() => fs.rmSync(directory, { recursive: true, force: true }));
15
+ return fs.realpathSync(directory);
16
+ }
17
+ function run(directory, args) {
18
+ return spawnSync(process.execPath, [cli, ...args], { cwd: directory, encoding: 'utf8' });
19
+ }
20
+ test('native CodeBuddy installation includes short commands, personas and usable references', t => {
21
+ const directory = workspace(t);
22
+ const result = run(directory, ['--codebuddy', '--scope', 'project', '--yes']);
23
+ assert.equal(result.status, 0, result.stderr);
24
+ const base = path.join(directory, '.codebuddy');
25
+ assert.equal(fs.readdirSync(path.join(base, 'skills')).length, upstream.skills.length);
26
+ assert.equal(fs.readdirSync(path.join(base, 'commands')).length, upstream.commands.length);
27
+ assert.equal(fs.readdirSync(path.join(base, 'agents')).length, upstream.personas.length);
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
+ assert.doesNotMatch(command, /i3-composer-agent:/);
31
+ const ship = fs.readFileSync(path.join(base, 'commands/i3-ship.md'), 'utf8');
32
+ assert.match(ship, /\.codebuddy\/agents\//);
33
+ assert.doesNotMatch(ship, /\.claude\/agents\//);
34
+ assert.ok(fs.existsSync(path.join(base, 'references/definition-of-done.md')));
35
+ assert.equal(fs.readFileSync(path.join(base, 'i3-composer-agent-LICENSE'), 'utf8'), fs.readFileSync(path.join(root, 'LICENSE'), 'utf8'));
36
+ assert.match(fs.readFileSync(path.join(base, 'i3-composer-agent-NOTICE.md'), 'utf8'), /Addy Osmani/);
37
+ assert.equal(fs.existsSync(path.join(directory, 'AGENTS.md')), false);
38
+ assert.equal(fs.existsSync(path.join(directory, 'i3-composer-agent')), false);
39
+ assert.match(result.stdout, /\/i3-spec/);
40
+ });
41
+ test('multiple tools retain their own destinations and share universal skills without duplicate work', t => {
42
+ const directory = workspace(t);
43
+ const result = run(directory, ['--agents', 'codebuddy,codex,cursor,claude-code', '--scope', 'project', '--yes']);
44
+ assert.equal(result.status, 0, result.stderr);
45
+ for (const base of ['.codebuddy', '.agents', '.claude']) {
46
+ assert.equal(fs.readdirSync(path.join(directory, base, 'skills')).length, upstream.skills.length);
47
+ assert.ok(fs.existsSync(path.join(directory, base, 'references/testing-patterns.md')));
48
+ }
49
+ const manifest = JSON.parse(fs.readFileSync(path.join(directory, '.agents/.i3-composer-agent.json')));
50
+ assert.deepEqual(manifest.agents.sort(), ['codex', 'cursor']);
51
+ assert.equal(fs.existsSync(path.join(directory, '.agents/commands')), false);
52
+ });
53
+ test('installation dry run describes scope and destinations without changing project files', t => {
54
+ const directory = workspace(t);
55
+ const result = run(directory, ['--agents', 'codebuddy,codex', '--scope', 'project', '--dry-run']);
56
+ assert.equal(result.status, 0, result.stderr);
57
+ const plan = JSON.parse(result.stdout);
58
+ assert.equal(plan.mode, 'install');
59
+ assert.equal(plan.scope, 'project');
60
+ assert.equal(plan.targets.length, 2);
61
+ assert.deepEqual(fs.readdirSync(directory), []);
62
+ });
63
+ test('all copied Markdown reference links and stable skill frontmatter remain valid', t => {
64
+ const directory = workspace(t);
65
+ assert.equal(run(directory, ['--codebuddy', '--scope', 'project', '--yes']).status, 0);
66
+ const base = path.join(directory, '.codebuddy');
67
+ function visit(folder) {
68
+ for (const entry of fs.readdirSync(folder, { withFileTypes: true })) {
69
+ const file = path.join(folder, entry.name);
70
+ if (entry.isDirectory()) visit(file);
71
+ else if (entry.name.endsWith('.md')) {
72
+ const content = fs.readFileSync(file, 'utf8');
73
+ for (const match of content.matchAll(/\]\(([^)]+)\)/g)) {
74
+ const relative = match[1].split('#')[0];
75
+ if (relative.includes('references/') && !/^[a-z]+:/i.test(relative)) {
76
+ assert.ok(fs.existsSync(path.resolve(path.dirname(file), relative)), `${file}: ${relative}`);
77
+ }
78
+ }
79
+ }
80
+ }
81
+ }
82
+ visit(path.join(base, 'skills'));
83
+ for (const id of upstream.skills.map(id => `i3-${id}`)) {
84
+ const head = content => content.match(/^---\r?\n[\s\S]*?\r?\n---/)[0];
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
+ }
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
+ });
136
+ test('existing assets are protected; confirmed replacement backs them up and preserves unrelated settings', t => {
137
+ const directory = workspace(t);
138
+ const base = path.join(directory, '.codebuddy');
139
+ fs.mkdirSync(path.join(base, 'commands'), { recursive: true });
140
+ fs.writeFileSync(path.join(base, 'commands/i3-spec.md'), 'my custom command');
141
+ fs.writeFileSync(path.join(base, 'settings.json'), '{"keep":"my settings"}\n');
142
+ const args = ['--codebuddy', '--scope', 'project', '--yes'];
143
+ assert.equal(run(directory, args).status, 1);
144
+ assert.equal(fs.existsSync(path.join(base, 'skills')), false);
145
+ const result = run(directory, [...args, '--force']);
146
+ assert.equal(result.status, 0, result.stderr);
147
+ const backups = fs.readdirSync(base).filter(file => file.startsWith('.i3-composer-agent-backup-'));
148
+ assert.equal(backups.length, 1);
149
+ assert.equal(fs.readFileSync(path.join(base, backups[0], 'commands/i3-spec.md'), 'utf8'), 'my custom command');
150
+ assert.equal(fs.readFileSync(path.join(base, 'settings.json'), 'utf8'), '{"keep":"my settings"}\n');
151
+ assert.equal(fs.existsSync(path.join(base, backups[0], 'settings.json')), false);
152
+ });
153
+ test('global installation uses injected home and config roots without touching the real user configuration', t => {
154
+ const directory = workspace(t);
155
+ const { planInstallation, executeInstallation } = require('../bin/install.cjs');
156
+ const plan = planInstallation({ agents: ['codebuddy', 'codex', 'claude-code', 'opencode'], scope: 'global', home: directory, env: { XDG_CONFIG_HOME: path.join(directory, 'config'), CLAUDE_CONFIG_DIR: path.join(directory, 'custom-claude') } });
157
+ assert.ok(plan.targets.every(target => target.skillsDirectory.startsWith(directory + path.sep)));
158
+ assert.ok(plan.targets.some(target => target.skillsDirectory === path.join(directory, 'custom-claude/skills')));
159
+ assert.ok(plan.targets.some(target => target.skillsDirectory === path.join(directory, 'config/opencode/skills')));
160
+ executeInstallation(plan);
161
+ for (const target of plan.targets) {
162
+ assert.equal(fs.readdirSync(target.skillsDirectory).length, upstream.skills.length);
163
+ assert.ok(fs.existsSync(path.join(target.referencesDirectory, 'definition-of-done.md')));
164
+ }
165
+ });
166
+ test('the pinned tool catalog plans all project choices and rejects unsupported global choices before writing', t => {
167
+ const directory = workspace(t);
168
+ const { registry, planInstallation } = require('../bin/install.cjs');
169
+ assert.equal(registry.agents.length, 79);
170
+ assert.equal(registry.commit, '48dc9e8eb8aa19040e91cb90ba0b642c9cbad57e');
171
+ const plan = planInstallation({ agents: registry.agents.map(agent => agent.id), scope: 'project', projectDir: directory });
172
+ assert.equal(plan.agents.length, registry.agents.length);
173
+ assert.ok(plan.targets.length < plan.agents.length);
174
+ assert.equal(new Set(plan.assets.map(asset => asset.destination)).size, plan.assets.length);
175
+ for (const agent of registry.agents) {
176
+ if (agent.globalSkillsDir) assert.ok(planInstallation({ agents: [agent.id], scope: 'global', home: directory, env: {} }).targets[0].skillsDirectory.startsWith(directory + path.sep));
177
+ else assert.throws(() => planInstallation({ agents: [agent.id], scope: 'global', home: directory, env: {} }), /project installation only/);
178
+ }
179
+ assert.deepEqual(fs.readdirSync(directory), []);
180
+ });
181
+ test('failed installation restores prior assets and removes all newly written files', t => {
182
+ const directory = workspace(t);
183
+ const { planInstallation, executeInstallation } = require('../bin/install.cjs');
184
+ const prior = path.join(directory, '.codebuddy/skills/i3-api-and-interface-design');
185
+ fs.mkdirSync(prior, { recursive: true });
186
+ fs.writeFileSync(path.join(prior, 'custom.md'), 'prior skill content');
187
+ const plan = planInstallation({ agents: ['codebuddy', 'codex'], scope: 'project', projectDir: directory });
188
+ const realRename = fs.renameSync;
189
+ let failed = false;
190
+ fs.renameSync = (source, destination) => {
191
+ if (!failed && destination === plan.assets[1].destination) { failed = true; throw new Error('simulated disk failure'); }
192
+ return realRename(source, destination);
193
+ };
194
+ try { assert.throws(() => executeInstallation(plan, { force: true }), /simulated disk failure/); }
195
+ finally { fs.renameSync = realRename; }
196
+ assert.equal(fs.readFileSync(path.join(prior, 'custom.md'), 'utf8'), 'prior skill content');
197
+ assert.deepEqual(fs.readdirSync(path.dirname(prior)), ['i3-api-and-interface-design']);
198
+ assert.deepEqual(fs.readdirSync(path.join(directory, '.codebuddy')), ['skills']);
199
+ assert.equal(fs.existsSync(path.join(directory, '.agents')), false);
200
+ });
201
+ test('replacing a skill symlink backs up the link and leaves its external source untouched', t => {
202
+ const directory = workspace(t);
203
+ const external = path.join(directory, 'external-skill');
204
+ const skills = path.join(directory, '.codebuddy/skills');
205
+ fs.mkdirSync(external);
206
+ fs.writeFileSync(path.join(external, 'custom.md'), 'external source');
207
+ fs.mkdirSync(skills, { recursive: true });
208
+ fs.symlinkSync(external, path.join(skills, 'i3-spec-driven-development'), 'dir');
209
+ const result = run(directory, ['--codebuddy', '--scope', 'project', '--yes', '--force']);
210
+ assert.equal(result.status, 0, result.stderr);
211
+ assert.deepEqual(fs.readdirSync(external), ['custom.md']);
212
+ assert.equal(fs.lstatSync(path.join(skills, 'i3-spec-driven-development')).isSymbolicLink(), false);
213
+ const base = path.dirname(skills);
214
+ const backup = fs.readdirSync(base).find(file => file.startsWith('.i3-composer-agent-backup-'));
215
+ assert.equal(fs.lstatSync(path.join(base, backup, 'skills/i3-spec-driven-development')).isSymbolicLink(), true);
216
+ });
217
+ test('package destinations, shared directory symlinks and ambiguous noninteractive flags fail without writes', t => {
218
+ const directory = workspace(t);
219
+ for (const args of [ ['--codebuddy'], ['--codebuddy', '--yes'], ['--agents', 'unknown', '--scope', 'project', '--yes'], ['--codebuddy', '--scope', 'invalid', '--yes'], ['--codebuddy', '--scope', 'project', '--global', '--yes'] ]) {
220
+ assert.equal(run(directory, args).status, 1);
221
+ assert.deepEqual(fs.readdirSync(directory), []);
222
+ }
223
+ assert.equal(run(directory, ['--codebuddy', '--scope', 'project', '--yes', '--project-dir', root]).status, 1);
224
+ fs.mkdirSync(path.join(directory, '.codebuddy'));
225
+ fs.symlinkSync(path.join(root, 'skills'), path.join(directory, '.codebuddy/skills'), 'dir');
226
+ assert.equal(run(directory, ['--codebuddy', '--scope', 'project', '--yes', '--force']).status, 1);
227
+ assert.deepEqual(fs.readdirSync(path.join(directory, '.codebuddy')), ['skills']);
228
+ });
229
+ test('explicit plugin preparation remains available and does not install native host files', t => {
230
+ const directory = workspace(t);
231
+ const result = run(directory, ['--prepare', '--codebuddy']);
232
+ assert.equal(result.status, 0, result.stderr);
233
+ assert.match(result.stdout, /\/plugin install/);
234
+ assert.equal(fs.existsSync(path.join(directory, 'i3-composer-agent/plugin.json')), true);
235
+ assert.equal(fs.existsSync(path.join(directory, '.codebuddy')), false);
236
+ const listing = run(directory, ['--list-agents']);
237
+ assert.equal(listing.status, 0, listing.stderr);
238
+ assert.equal(listing.stdout.trim().split('\n').length, 79);
239
+ assert.match(listing.stdout, /codebuddy/);
240
+ assert.match(listing.stdout, /windsurf/);
241
+ });
@@ -9,27 +9,68 @@ 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
- ## Prepare the complete plugin
14
+ ## Install with the wizard
15
15
 
16
- Run in the project where you want to prepare the plugin:
16
+ Run in the project where you want to use the skills:
17
17
 
18
18
  ```bash
19
+ npx @givolt/i3-composer-agent
20
+ # Preselect a tool; the wizard still allows multiple selections:
19
21
  npx @givolt/i3-composer-agent --codebuddy
20
- # Other hosts:
21
- npx @givolt/i3-composer-agent --codex
22
- npx @givolt/i3-composer-agent --claude
23
22
  ```
24
23
 
25
- The command prepares a persistent `./i3-composer-agent/` directory containing
26
- {{SKILL_COUNT}} skills, {{COMMAND_COUNT}} commands, {{PERSONA_COUNT}} personas,
27
- and shared references. It prints native registration commands; run those in
28
- the selected host to enable the plugin. Preparing files does not select a host
29
- installation scope. See [CodeBuddy setup](docs/codebuddy-setup.md) and
30
- [Codex setup](docs/codex-setup.md).
24
+ The interactive terminal wizard offers multiple tools, project or global scope,
25
+ an installation summary, and confirmation. Its 79 tool directory presets come
26
+ from the pinned [Vercel Skills CLI registry](https://github.com/vercel-labs/skills/blob/48dc9e8eb8aa19040e91cb90ba0b642c9cbad57e/src/agents.ts).
27
+ Choose by tool ID or comma-separated menu numbers. Use `--list-agents` to list
28
+ the choices. Directory presets are not an execution test of every host.
29
+
30
+ Every selected tool receives all {{SKILL_COUNT}} skills and shared references.
31
+ CodeBuddy and Claude Code also receive {{COMMAND_COUNT}} short command workflows
32
+ and {{PERSONA_COUNT}} persona files. Other tools use their native skill support;
33
+ short lifecycle commands depend on the host. Shared destinations are installed
34
+ once. License and attribution files accompany each native installation.
35
+ Reload the IDE window or start a new session after installation. See
36
+ [CodeBuddy setup](docs/codebuddy-setup.md) and [Codex setup](docs/codex-setup.md).
37
+
38
+ For an explicit installation without prompts:
39
+
40
+ ```bash
41
+ npx @givolt/i3-composer-agent --agents codebuddy,codex --scope project --yes
42
+ npx @givolt/i3-composer-agent --claude --scope global --yes
43
+ npx @givolt/i3-composer-agent --codebuddy --scope project --dry-run
44
+ ```
45
+
46
+ Existing assets require confirmation; use `--force` with noninteractive installs.
47
+ Replacement preserves previous files in a `.i3-composer-agent-backup-*` directory
48
+ under each tool configuration root. Unrelated settings are left in place.
49
+ `npx -y` accepts npm's package download prompt; the package's own `--yes` flag
50
+ accepts the explicit installation plan.
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
+
58
+ ## Prepare the complete plugin
59
+
60
+ For native plugin registration, including plugin hooks, explicitly prepare a
61
+ persistent `./i3-composer-agent/` bundle:
62
+
63
+ ```bash
64
+ npx @givolt/i3-composer-agent --prepare --codebuddy
65
+ npx @givolt/i3-composer-agent --prepare --codex
66
+ npx @givolt/i3-composer-agent --prepare --claude
67
+ ```
68
+
69
+ The bundle includes skills, commands, personas, hooks and references. Run the
70
+ registration commands printed by the CLI in the intended host. This preparation
71
+ mode does not install native skills or choose the host plugin manager's scope.
31
72
 
32
- CodeBuddy / Claude Code:
73
+ CodeBuddy Code (terminal) / Claude Code:
33
74
 
34
75
  ```text
35
76
  /plugin marketplace add ./i3-composer-agent
@@ -43,19 +84,21 @@ codex plugin marketplace add ./i3-composer-agent
43
84
  codex plugin add i3-composer-agent@i3-composer-agent
44
85
  ```
45
86
 
46
- Start a new session after enabling the plugin. Codex uses the existing Skill
47
- 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
48
89
  is maintained separately.
49
90
 
50
91
  ## Commands
51
92
 
52
- Hosts supporting Claude-compatible plugin commands load these workflows:
93
+ Native CodeBuddy and Claude Code installations use short filenames such as
94
+ `/i3-spec`, `/i3-plan`, `/i3-build` and `/i3-ship`. Hosts supporting Claude-compatible plugin
95
+ commands load the same workflows under the plugin namespace:
53
96
 
54
97
  | Command | Description |
55
98
  | --- | --- |
56
99
  {{COMMAND_TABLE}}
57
100
 
58
- `/i3-composer-agent:build auto` runs the existing approved-plan workflow.
101
+ `/i3-composer-agent:i3-build auto` runs the existing approved-plan workflow.
59
102
 
60
103
  ## Skills
61
104
 
@@ -71,7 +114,8 @@ npx @givolt/i3-composer-agent --codebuddy --dir /path/to/plugin --dry-run
71
114
  npx @givolt/i3-composer-agent --codebuddy --dir /path/to/plugin --force
72
115
  ```
73
116
 
74
- Replacement preserves the previous i3 bundle as a backup. Repository-scoped
117
+ Explicit `--dir` retains the original plugin preparation behavior. Replacement
118
+ preserves the previous i3 bundle as a backup. Repository-scoped
75
119
  AGENTS.md and CLAUDE.md are not copied into business projects.
76
120
 
77
121
  ## Maintaining this fork
@@ -1,12 +1,60 @@
1
1
  # Using i3 Composer Agent with CodeBuddy
2
2
 
3
- Prepare the complete plugin inside the project where you want to use it:
3
+ ## Desktop IDE installation
4
+
5
+ Run inside your business project:
4
6
 
5
7
  ```bash
6
8
  npx @givolt/i3-composer-agent --codebuddy
7
9
  ```
8
10
 
9
- In the CodeBuddy chat, register the prepared directory and install the plugin:
11
+ The terminal wizard preselects CodeBuddy, still allows multiple tools, and asks
12
+ for project or global scope before installing. Project scope writes these paths:
13
+
14
+ - `.codebuddy/skills/` — all {{SKILL_COUNT}} skills with `i3-` IDs.
15
+ - `.codebuddy/references/` — shared checklists used by skill-relative links.
16
+ - `.codebuddy/commands/` — all {{COMMAND_COUNT}} existing lifecycle workflows.
17
+ - `.codebuddy/agents/` — all {{PERSONA_COUNT}} persona definitions.
18
+
19
+ Global scope uses the same layout under `~/.codebuddy/`. Existing assets require
20
+ confirmed replacement and are preserved in backup directories. Settings are
21
+ not replaced. Reload the CodeBuddy window or start a new chat, then inspect
22
+ the Skills list and type `/` to inspect the command menu.
23
+
24
+ ```text
25
+ /i3-spec
26
+ /i3-plan
27
+ /i3-build
28
+ /i3-build auto
29
+ /i3-review
30
+ /i3-ship
31
+ ```
32
+
33
+ The command wrappers reference installed skill IDs without the plugin namespace.
34
+ Their workflow content and approval gates are retained. File installation does
35
+ not itself prove that the IDE has discovered or executed every workflow.
36
+
37
+ For multiple tools or a noninteractive installation:
38
+
39
+ ```bash
40
+ npx @givolt/i3-composer-agent --agents codebuddy,codex --scope project --yes
41
+ npx @givolt/i3-composer-agent --codebuddy --scope global --yes
42
+ ```
43
+
44
+ CodeBuddy documents [IDE skills](https://www.codebuddy.cn/docs/ide/Features/Skills)
45
+ and [IDE custom commands](https://www.codebuddy.cn/docs/ide/User-guide/Slash-Commands).
46
+ The directory layout follows its [configuration directory reference](https://www.codebuddy.cn/docs/cli/codebuddy-dir).
47
+
48
+ ## CodeBuddy Code native plugin registration
49
+
50
+ For the terminal CodeBuddy Code plugin manager, explicitly prepare the full
51
+ plugin instead of native skill installation:
52
+
53
+ ```bash
54
+ npx @givolt/i3-composer-agent --prepare --codebuddy
55
+ ```
56
+
57
+ In CodeBuddy Code, register the prepared directory and install the plugin:
10
58
 
11
59
  ```text
12
60
  /plugin marketplace add ./i3-composer-agent
@@ -14,28 +62,28 @@ In the CodeBuddy chat, register the prepared directory and install the plugin:
14
62
  ```
15
63
 
16
64
  Use the absolute directory printed by the CLI if CodeBuddy has a different
17
- working directory. Choose the intended installation scope in CodeBuddy's native
65
+ working directory. Choose the intended installation scope in CodeBuddy Code's native
18
66
  plugin manager. Reload plugins or start a new session after installation.
19
67
 
20
- CodeBuddy supports the existing `.claude-plugin/plugin.json` compatibility
68
+ CodeBuddy Code supports the existing `.claude-plugin/plugin.json` compatibility
21
69
  manifest. It declares `.claude/commands/` and `commands/`, preserving the nine
22
70
  original lifecycle commands and their workflow content.
23
71
 
24
72
  ```text
25
- /i3-composer-agent:spec
26
- /i3-composer-agent:plan
27
- /i3-composer-agent:build
28
- /i3-composer-agent:build auto
29
- /i3-composer-agent:review
30
- /i3-composer-agent:ship
73
+ /i3-composer-agent:i3-spec
74
+ /i3-composer-agent:i3-plan
75
+ /i3-composer-agent:i3-build
76
+ /i3-composer-agent:i3-build auto
77
+ /i3-composer-agent:i3-review
78
+ /i3-composer-agent:i3-ship
31
79
  ```
32
80
 
33
- Skill IDs, persona names, artifact paths, and workflow gates retain their
34
- upstream behavior. The plugin namespace changes to `i3-composer-agent`.
81
+ Skill IDs and command filenames use `i3-`. Persona names, artifact paths,
82
+ and workflow gates retain their upstream behavior. The plugin namespace is
83
+ `i3-composer-agent`.
35
84
 
36
- The bundle includes all skills and shared `references/`. Installing individual
37
- skills is a different distribution method and does not install the command
38
- wrappers or persona definitions.
85
+ The prepared plugin includes all skills, personas, commands, hooks and shared
86
+ `references/`. Native skill installation above does not enable plugin hooks.
39
87
 
40
- The CLI prepares files and prints registration commands. Actual host discovery
88
+ In this explicit mode the CLI prepares files and prints registration commands. Actual host discovery
41
89
  and model execution should be verified after registering the plugin.
@@ -1,12 +1,23 @@
1
1
  # Using i3 Composer Agent with Codex
2
2
 
3
- Prepare the complete plugin inside the project where you want to use it:
3
+ For the multi-tool native skill wizard, run in your project:
4
4
 
5
5
  ```bash
6
6
  npx @givolt/i3-composer-agent --codex
7
7
  ```
8
8
 
9
- The CLI copies a persistent `./i3-composer-agent/` bundle and prints these
9
+ Choose project or global scope. Native installation uses `.agents/skills/`
10
+ or `~/.agents/skills/`, plus the sibling `references/` directory. It installs
11
+ the {{SKILL_COUNT}} skills with `i3-` IDs. This mode does not add short lifecycle
12
+ slash commands or enable plugin hooks.
13
+
14
+ For complete plugin registration, prepare a persistent bundle explicitly:
15
+
16
+ ```bash
17
+ npx @givolt/i3-composer-agent --prepare --codex
18
+ ```
19
+
20
+ This mode copies a persistent `./i3-composer-agent/` bundle and prints these
10
21
  native registration commands. Run them to enable the plugin:
11
22
 
12
23
  ```bash
@@ -14,20 +25,20 @@ codex plugin marketplace add ./i3-composer-agent
14
25
  codex plugin add i3-composer-agent@i3-composer-agent
15
26
  ```
16
27
 
17
- Start a new Codex session after registration. All 25 existing skills keep their
18
- original IDs. In CLI/IDE, use `/skills` or `$spec-driven-development`; in chat,
28
+ Start a new Codex session after registration. All {{SKILL_COUNT}} skills use
29
+ `i3-` IDs. In CLI/IDE, use `/skills` or `$i3-spec-driven-development`; in chat,
19
30
  explicitly request the relevant skill from i3 Composer Agent.
20
31
 
21
32
  The adapter in `.codex-plugin/plugin.json` points at the unchanged `skills/`
22
33
  layout. Shared checklists remain under `references/`, so skill-relative links
23
34
  resolve inside the complete plugin bundle.
24
35
 
25
- The short lifecycle commands (`/spec`, `/plan`, `/build`, `/ship`) remain
36
+ The short lifecycle commands (`/i3-spec`, `/i3-plan`, `/i3-build`, `/i3-ship`) remain
26
37
  available in hosts that load the Claude-compatible command manifest. Codex
27
38
  lifecycle-command adaptation is separate from this brand conversion. Native
28
39
  Codex `/plan` switches planning mode; it is not the plugin's planning wrapper.
29
40
 
30
- Do not preload `using-agent-skills/SKILL.md` into always-on context: Codex routes
41
+ Do not preload `i3-using-agent-skills/SKILL.md` into always-on context: Codex routes
31
42
  skills natively. The meta-skill can remain installed and explicitly invoked.
32
43
 
33
44
  For local source testing, replace `./i3-composer-agent` above with the absolute
@@ -8,6 +8,8 @@ const path = require('node:path');
8
8
  const { spawnSync } = require('node:child_process');
9
9
  const root = path.resolve(__dirname, '../..');
10
10
  const baselineVersion = require('../upstream.json').upstreamVersion;
11
+ const upstream = require('../upstream.json');
12
+ const { runtimePath, rewriteReferences } = require('../identifiers.cjs');
11
13
 
12
14
  function run(directory, executable, args) {
13
15
  return spawnSync(executable, args, { cwd: directory, encoding: 'utf8' });
@@ -24,6 +26,19 @@ function fixture(t, branch = 'release/test-candidate') {
24
26
  for (const name of ['skills', 'references', 'agents', 'commands', '.claude', '.gemini', '.claude-plugin', '.codex-plugin', '.agents', 'hooks', 'docs', 'scripts', 'evals', 'rebrand', 'LICENSE', 'plugin.json', 'README.md']) {
25
27
  fs.cpSync(path.join(root, name), path.join(directory, name), { recursive: true, filter: file => !file.includes(`${path.sep}results${path.sep}`) });
26
28
  }
29
+ function restore(folder) {
30
+ for (const entry of fs.readdirSync(folder, { withFileTypes: true })) {
31
+ if (entry.name === 'rebrand') continue;
32
+ const file = path.join(folder, entry.name);
33
+ if (entry.isDirectory()) restore(file);
34
+ else if (/\.(?:md|js|cjs|sh|toml|json|yml|patch|diff)$/.test(entry.name)) fs.writeFileSync(file, rewriteReferences(fs.readFileSync(file, 'utf8'), true));
35
+ }
36
+ }
37
+ restore(directory);
38
+ for (const source of [...upstream.skills.map(id => `skills/${id}`), ...upstream.skills.map(id => `evals/cases/${id}.json`), ...upstream.skills.map(id => `evals/fixtures/${id}`), ...upstream.runtimeFiles.filter(file => /commands\/[^/]+\.(md|toml)$/.test(file))]) {
39
+ const branded = runtimePath(source);
40
+ if (fs.existsSync(path.join(directory, branded))) fs.renameSync(path.join(directory, branded), path.join(directory, source));
41
+ }
27
42
  // Model an upstream source checkout, including when this suite runs in a packed branded bundle.
28
43
  for (const name of ['plugin.json', '.claude-plugin/plugin.json', '.codex-plugin/plugin.json']) {
29
44
  const file = path.join(directory, name);
@@ -57,9 +72,62 @@ test('a source checkout generates a complete, repeatable branded distribution',
57
72
  const brand = JSON.parse(fs.readFileSync(path.join(directory, 'rebrand/brand.json'), 'utf8'));
58
73
  assert.equal(pkg.version, brand.releaseVersion);
59
74
  assert.equal(fs.existsSync(path.join(directory, 'bin/i3-composer-agent.cjs')), true);
60
- assert.equal(node(directory, 'scripts/validate-brand.cjs').status, 0);
75
+ const validation = node(directory, 'scripts/validate-brand.cjs');
76
+ assert.equal(validation.status, 0, validation.stdout + validation.stderr);
77
+ const complete = run(directory, 'npm', ['run', 'validate']);
78
+ assert.equal(complete.status, 0, complete.stdout + complete.stderr);
79
+ const routing = node(directory, 'scripts/run-evals.js', ['--min-rank1', '95']);
80
+ assert.equal(routing.status, 0, routing.stdout + routing.stderr);
81
+ const check = node(directory, 'rebrand/apply.cjs', ['--check']);
82
+ assert.equal(check.status, 0, check.stdout + check.stderr);
83
+ });
84
+
85
+ test('branded commands and skills use i3 identifiers with working local references', t => {
86
+ const directory = fixture(t);
87
+ record(directory);
88
+ apply(directory);
89
+ const skill = 'i3-spec-driven-development';
90
+ const file = path.join(directory, 'skills', skill, 'SKILL.md');
91
+ assert.ok(fs.existsSync(file), 'branded Skill directory must use i3-');
92
+ assert.match(fs.readFileSync(file, 'utf8'), /^name: i3-spec-driven-development$/m);
93
+ assert.equal(fs.existsSync(path.join(directory, 'skills/spec-driven-development')), false);
94
+ const command = fs.readFileSync(path.join(directory, '.claude/commands/i3-spec.md'), 'utf8');
95
+ assert.match(command, /i3-composer-agent:i3-spec-driven-development/);
96
+ assert.equal(fs.existsSync(path.join(directory, '.claude/commands/spec.md')), false);
97
+ const helper = 'skills/i3-idea-refine/scripts/idea-refine.sh';
98
+ assert.ok(fs.statSync(path.join(directory, helper)).mode & 0o111, 'helper execution permissions must survive renaming');
99
+ assert.ok(fs.readFileSync(path.join(directory, 'skills/i3-idea-refine/SKILL.md'), 'utf8').includes(helper), 'helper reference must resolve to its retained filename');
100
+ for (const commands of ['commands', '.gemini/commands']) {
101
+ assert.ok(fs.existsSync(path.join(directory, commands, 'i3-planning.toml')));
102
+ }
103
+ const hook = fs.readFileSync(path.join(directory, 'hooks/session-start.sh'), 'utf8');
104
+ assert.match(hook, /i3-using-agent-skills\/SKILL\.md/);
105
+ assert.equal(node(directory, 'scripts/validate-commands.js').status, 0);
106
+ const readme = fs.readFileSync(path.join(directory, 'README.md'), 'utf8');
107
+ assert.match(readme, /\/i3-spec/);
108
+ assert.match(readme, /skills\/i3-spec-driven-development\/SKILL\.md/);
61
109
  const check = node(directory, 'rebrand/apply.cjs', ['--check']);
62
110
  assert.equal(check.status, 0, check.stdout + check.stderr);
111
+ apply(directory);
112
+ assert.equal(fs.existsSync(path.join(directory, 'skills/i3-i3-spec-driven-development')), false);
113
+ });
114
+
115
+ test('generated native installer preserves references and migrates legacy identifiers safely', t => {
116
+ const directory = fixture(t);
117
+ record(directory);
118
+ apply(directory);
119
+ const result = run(directory, process.execPath, ['--test', 'tests/installer.test.cjs']);
120
+ assert.equal(result.status, 0, result.stdout + result.stderr);
121
+ });
122
+
123
+ test('identifier rewriting preserves upstream URLs and avoids repeated prefixes', () => {
124
+ const content = 'Use spec-driven-development and /spec. https://github.com/addyosmani/agent-skills/blob/main/skills/spec-driven-development/SKILL.md';
125
+ const expected = 'Use i3-spec-driven-development and /i3-spec. https://github.com/addyosmani/agent-skills/blob/main/skills/spec-driven-development/SKILL.md';
126
+ assert.equal(rewriteReferences(content), expected);
127
+ assert.equal(rewriteReferences(expected), expected);
128
+ assert.equal(rewriteReferences(expected, true), content);
129
+ assert.equal(rewriteReferences('Save specs/auth/spec.md; use .claude/commands/spec.md.'), 'Save specs/auth/spec.md; use .claude/commands/i3-spec.md.');
130
+ assert.equal(rewriteReferences('skills/idea-refine/scripts/idea-refine.sh'), 'skills/i3-idea-refine/scripts/idea-refine.sh');
63
131
  });
64
132
 
65
133
  test('brand fixes advance independently while preserving upstream provenance', t => {
@@ -132,9 +200,9 @@ test('missing files and altered skill identifiers fail preservation validation',
132
200
  const directory = fixture(t);
133
201
  record(directory);
134
202
  apply(directory);
135
- const file = path.join(directory, 'skills/using-agent-skills/SKILL.md');
203
+ const file = path.join(directory, 'skills/i3-using-agent-skills/SKILL.md');
136
204
  const original = fs.readFileSync(file, 'utf8');
137
- fs.writeFileSync(file, original.replace('name: using-agent-skills', 'name: renamed-meta-skill'));
205
+ fs.writeFileSync(file, original.replace('name: i3-using-agent-skills', 'name: renamed-meta-skill'));
138
206
  assert.notEqual(node(directory, 'scripts/validate-brand.cjs').status, 0);
139
207
  fs.writeFileSync(file, original);
140
208
  fs.rmSync(file);
@@ -1,6 +1,6 @@
1
1
  # Accessibility Checklist
2
2
 
3
- Quick reference for WCAG 2.1 AA compliance. Use alongside the `frontend-ui-engineering` skill.
3
+ Quick reference for WCAG 2.1 AA compliance. Use alongside the `i3-frontend-ui-engineering` skill.
4
4
 
5
5
  ## Table of Contents
6
6