@givolt/i3-composer-agent 0.0.0-stage → 1.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 (231) hide show
  1. package/.agents/plugins/marketplace.json +23 -0
  2. package/.claude/commands/build.md +44 -0
  3. package/.claude/commands/code-simplify.md +22 -0
  4. package/.claude/commands/constraints.md +32 -0
  5. package/.claude/commands/plan.md +18 -0
  6. package/.claude/commands/review.md +16 -0
  7. package/.claude/commands/ship.md +72 -0
  8. package/.claude/commands/spec.md +17 -0
  9. package/.claude/commands/test.md +19 -0
  10. package/.claude/commands/webperf.md +32 -0
  11. package/.claude-plugin/marketplace.json +27 -0
  12. package/.claude-plugin/plugin.json +19 -0
  13. package/.codex-plugin/plugin.json +28 -0
  14. package/.gemini/commands/build.toml +43 -0
  15. package/.gemini/commands/code-simplify.toml +22 -0
  16. package/.gemini/commands/constraints.toml +32 -0
  17. package/.gemini/commands/planning.toml +18 -0
  18. package/.gemini/commands/review.toml +16 -0
  19. package/.gemini/commands/ship.toml +72 -0
  20. package/.gemini/commands/spec.toml +17 -0
  21. package/.gemini/commands/test.toml +19 -0
  22. package/.gemini/commands/webperf.toml +32 -0
  23. package/CHANGELOG.md +23 -0
  24. package/LICENSE +21 -0
  25. package/NOTICE.md +9 -0
  26. package/README.md +117 -2
  27. package/agents/code-reviewer.md +102 -0
  28. package/agents/security-auditor.md +112 -0
  29. package/agents/test-engineer.md +95 -0
  30. package/agents/web-performance-auditor.md +184 -0
  31. package/bin/i3-composer-agent.cjs +122 -0
  32. package/commands/build.toml +43 -0
  33. package/commands/code-simplify.toml +22 -0
  34. package/commands/constraints.toml +32 -0
  35. package/commands/planning.toml +18 -0
  36. package/commands/review.toml +16 -0
  37. package/commands/ship.toml +72 -0
  38. package/commands/spec.toml +17 -0
  39. package/commands/test.toml +19 -0
  40. package/commands/webperf.toml +32 -0
  41. package/docs/adoption-guide.md +129 -0
  42. package/docs/advanced-per-agent-configuration.md +70 -0
  43. package/docs/agents.md +123 -0
  44. package/docs/antigravity-setup.md +128 -0
  45. package/docs/codebuddy-setup.md +41 -0
  46. package/docs/codex-setup.md +34 -0
  47. package/docs/commandcode-setup.md +69 -0
  48. package/docs/comparison.md +131 -0
  49. package/docs/copilot-cli-setup.md +64 -0
  50. package/docs/copilot-setup.md +162 -0
  51. package/docs/cursor-setup.md +225 -0
  52. package/docs/developer-onboarding.md +116 -0
  53. package/docs/gemini-cli-setup.md +133 -0
  54. package/docs/getting-started.md +208 -0
  55. package/docs/opencode-setup.md +259 -0
  56. package/docs/other-hosts.md +7 -0
  57. package/docs/skill-anatomy.md +203 -0
  58. package/docs/windsurf-setup.md +48 -0
  59. package/evals/README.md +101 -0
  60. package/evals/cases/api-and-interface-design.json +45 -0
  61. package/evals/cases/browser-testing-with-devtools.json +44 -0
  62. package/evals/cases/ci-cd-and-automation.json +45 -0
  63. package/evals/cases/code-review-and-quality.json +49 -0
  64. package/evals/cases/code-simplification.json +45 -0
  65. package/evals/cases/constraint-driven-development.json +79 -0
  66. package/evals/cases/context-engineering.json +44 -0
  67. package/evals/cases/debugging-and-error-recovery.json +58 -0
  68. package/evals/cases/deprecation-and-migration.json +52 -0
  69. package/evals/cases/documentation-and-adrs.json +44 -0
  70. package/evals/cases/doubt-driven-development.json +43 -0
  71. package/evals/cases/frontend-ui-engineering.json +52 -0
  72. package/evals/cases/git-workflow-and-versioning.json +47 -0
  73. package/evals/cases/idea-refine.json +43 -0
  74. package/evals/cases/incremental-implementation.json +57 -0
  75. package/evals/cases/interview-me.json +42 -0
  76. package/evals/cases/observability-and-instrumentation.json +44 -0
  77. package/evals/cases/performance-optimization.json +53 -0
  78. package/evals/cases/planning-and-task-breakdown.json +45 -0
  79. package/evals/cases/security-and-hardening.json +53 -0
  80. package/evals/cases/shipping-and-launch.json +56 -0
  81. package/evals/cases/source-driven-development.json +44 -0
  82. package/evals/cases/spec-driven-development.json +72 -0
  83. package/evals/cases/test-driven-development.json +73 -0
  84. package/evals/cases/using-agent-skills.json +44 -0
  85. package/evals/fixtures/api-and-interface-design/service-brief.md +19 -0
  86. package/evals/fixtures/browser-testing-with-devtools/README.md +5 -0
  87. package/evals/fixtures/browser-testing-with-devtools/index.html +24 -0
  88. package/evals/fixtures/browser-testing-with-devtools/server.js +15 -0
  89. package/evals/fixtures/ci-cd-and-automation/package.json +8 -0
  90. package/evals/fixtures/ci-cd-and-automation/src/slug.js +3 -0
  91. package/evals/fixtures/ci-cd-and-automation/test/slug.test.js +9 -0
  92. package/evals/fixtures/code-review-and-quality/user-search.diff +16 -0
  93. package/evals/fixtures/code-simplification/config-parser.js +46 -0
  94. package/evals/fixtures/code-simplification/config-parser.test.js +15 -0
  95. package/evals/fixtures/context-engineering/context-audit.md +15 -0
  96. package/evals/fixtures/debugging-and-error-recovery/pagination.js +8 -0
  97. package/evals/fixtures/debugging-and-error-recovery/pagination.test.js +9 -0
  98. package/evals/fixtures/debugging-and-error-recovery/time-pressure.md +6 -0
  99. package/evals/fixtures/deprecation-and-migration/api-inventory.md +9 -0
  100. package/evals/fixtures/documentation-and-adrs/decision-context.md +16 -0
  101. package/evals/fixtures/doubt-driven-development/migration-plan.md +19 -0
  102. package/evals/fixtures/frontend-ui-engineering/Button.tsx +7 -0
  103. package/evals/fixtures/frontend-ui-engineering/design-system.md +11 -0
  104. package/evals/fixtures/git-workflow-and-versioning/.eval/working-tree.patch +21 -0
  105. package/evals/fixtures/git-workflow-and-versioning/app.js +7 -0
  106. package/evals/fixtures/git-workflow-and-versioning/app.test.js +9 -0
  107. package/evals/fixtures/incremental-implementation/reports.js +7 -0
  108. package/evals/fixtures/incremental-implementation/reports.test.js +12 -0
  109. package/evals/fixtures/incremental-implementation/tasks/plan.md +8 -0
  110. package/evals/fixtures/incremental-implementation-pressure/draft-export.js +17 -0
  111. package/evals/fixtures/incremental-implementation-pressure/scenario.md +9 -0
  112. package/evals/fixtures/observability-and-instrumentation/operations.md +11 -0
  113. package/evals/fixtures/observability-and-instrumentation/payment-retry.js +14 -0
  114. package/evals/fixtures/performance-optimization/benchmark.js +15 -0
  115. package/evals/fixtures/performance-optimization/products.js +14 -0
  116. package/evals/fixtures/planning-and-task-breakdown/notifications-spec.md +18 -0
  117. package/evals/fixtures/security-and-hardening/webhook.js +11 -0
  118. package/evals/fixtures/security-and-hardening/webhook.test.js +13 -0
  119. package/evals/fixtures/shipping-and-launch/authority-pressure.md +6 -0
  120. package/evals/fixtures/shipping-and-launch/launch-status.md +11 -0
  121. package/evals/fixtures/source-driven-development/framework-task.md +10 -0
  122. package/evals/fixtures/spec-driven-development/billing-brief.md +16 -0
  123. package/evals/fixtures/spec-driven-development-decomposition/portal-brief.md +22 -0
  124. package/evals/fixtures/test-driven-development/BUG.md +10 -0
  125. package/evals/fixtures/test-driven-development/README.md +28 -0
  126. package/evals/fixtures/test-driven-development/package.json +9 -0
  127. package/evals/fixtures/test-driven-development/src/split.js +8 -0
  128. package/evals/fixtures/test-driven-development/test/split.test.js +13 -0
  129. package/evals/fixtures/test-driven-development-ecosystem/README.md +9 -0
  130. package/evals/fixtures/test-driven-development-ecosystem/ledger.py +15 -0
  131. package/evals/fixtures/test-driven-development-ecosystem/test_ledger.py +19 -0
  132. package/evals/fixtures/using-agent-skills/incident.md +6 -0
  133. package/evals/plugin/code-review-fires/graders/off-by-one.md +7 -0
  134. package/evals/plugin/code-review-fires/graders/severity-labels.md +4 -0
  135. package/evals/plugin/code-review-fires/graders/skill-fired.md +5 -0
  136. package/evals/plugin/code-review-fires/prompt.md +31 -0
  137. package/evals/plugin/code-review-stays-quiet/graders/not-fired.md +8 -0
  138. package/evals/plugin/code-review-stays-quiet/graders/tdd-fired.md +6 -0
  139. package/evals/plugin/code-review-stays-quiet/prompt.md +8 -0
  140. package/evals/plugin/code-review-stays-quiet-on-commit-message/graders/not-fired.md +8 -0
  141. package/evals/plugin/code-review-stays-quiet-on-commit-message/prompt.md +25 -0
  142. package/evals/skill-impact.md +6 -0
  143. package/hooks/SDD-CACHE.md +167 -0
  144. package/hooks/SIMPLIFY-IGNORE.md +91 -0
  145. package/hooks/sdd-cache-post.sh +135 -0
  146. package/hooks/sdd-cache-pre.sh +106 -0
  147. package/hooks/sdd-cache-test.sh +246 -0
  148. package/hooks/session-start-test.sh +47 -0
  149. package/hooks/session-start.sh +33 -0
  150. package/hooks/simplify-ignore-test.sh +476 -0
  151. package/hooks/simplify-ignore.sh +352 -0
  152. package/package.json +89 -4
  153. package/plugin.json +7 -0
  154. package/rebrand/MAINTENANCE.md +112 -0
  155. package/rebrand/NOTICE.md +9 -0
  156. package/rebrand/PR-WORKFLOW.md +34 -0
  157. package/rebrand/UNIFICATION-SPEC.md +33 -0
  158. package/rebrand/VALIDATION.md +28 -0
  159. package/rebrand/VERSIONING.md +32 -0
  160. package/rebrand/apply.cjs +194 -0
  161. package/rebrand/brand.json +13 -0
  162. package/rebrand/catalog.cjs +56 -0
  163. package/rebrand/fork-patches.json +12 -0
  164. package/rebrand/overlay/.github/workflows/test-plugin-install.yml +177 -0
  165. package/rebrand/overlay/CHANGELOG.md +23 -0
  166. package/rebrand/overlay/bin/i3-composer-agent.cjs +122 -0
  167. package/rebrand/overlay/scripts/validate-brand.cjs +44 -0
  168. package/rebrand/overlay/tests/bundle.test.cjs +85 -0
  169. package/rebrand/package.template.json +82 -0
  170. package/rebrand/rebrand.sh +4 -0
  171. package/rebrand/record-upstream.cjs +37 -0
  172. package/rebrand/templates/README.md +86 -0
  173. package/rebrand/templates/codebuddy-setup.md +41 -0
  174. package/rebrand/templates/codex-setup.md +34 -0
  175. package/rebrand/tests/pipeline.test.cjs +185 -0
  176. package/rebrand/upstream.json +171 -0
  177. package/references/accessibility-checklist.md +160 -0
  178. package/references/definition-of-done.md +67 -0
  179. package/references/observability-checklist.md +92 -0
  180. package/references/orchestration-patterns.md +370 -0
  181. package/references/performance-checklist.md +236 -0
  182. package/references/security-checklist.md +248 -0
  183. package/references/testing-patterns.md +235 -0
  184. package/scripts/floor-guard-reference-test.js +291 -0
  185. package/scripts/lib/skill-lint-test.js +650 -0
  186. package/scripts/lib/skill-lint.js +584 -0
  187. package/scripts/run-evals-test.js +623 -0
  188. package/scripts/run-evals.js +638 -0
  189. package/scripts/validate-artifact-paths-test.js +179 -0
  190. package/scripts/validate-artifact-paths.js +128 -0
  191. package/scripts/validate-brand.cjs +44 -0
  192. package/scripts/validate-commands-test.js +216 -0
  193. package/scripts/validate-commands.js +222 -0
  194. package/scripts/validate-reference-links-test.js +495 -0
  195. package/scripts/validate-reference-links.js +187 -0
  196. package/scripts/validate-skills.js +69 -0
  197. package/scripts/validate-versions-test.js +32 -0
  198. package/scripts/validate-versions.js +35 -0
  199. package/skills/api-and-interface-design/SKILL.md +367 -0
  200. package/skills/browser-testing-with-devtools/SKILL.md +317 -0
  201. package/skills/ci-cd-and-automation/SKILL.md +390 -0
  202. package/skills/code-review-and-quality/SKILL.md +398 -0
  203. package/skills/code-simplification/SKILL.md +331 -0
  204. package/skills/constraint-driven-development/SKILL.md +311 -0
  205. package/skills/constraint-driven-development/references/floor-guard.md +182 -0
  206. package/skills/context-engineering/SKILL.md +353 -0
  207. package/skills/debugging-and-error-recovery/SKILL.md +300 -0
  208. package/skills/deprecation-and-migration/SKILL.md +247 -0
  209. package/skills/documentation-and-adrs/SKILL.md +288 -0
  210. package/skills/doubt-driven-development/SKILL.md +243 -0
  211. package/skills/frontend-ui-engineering/SKILL.md +340 -0
  212. package/skills/git-workflow-and-versioning/SKILL.md +355 -0
  213. package/skills/idea-refine/SKILL.md +178 -0
  214. package/skills/idea-refine/examples.md +238 -0
  215. package/skills/idea-refine/frameworks.md +99 -0
  216. package/skills/idea-refine/refinement-criteria.md +113 -0
  217. package/skills/idea-refine/scripts/idea-refine.sh +15 -0
  218. package/skills/incremental-implementation/SKILL.md +249 -0
  219. package/skills/interview-me/SKILL.md +235 -0
  220. package/skills/observability-and-instrumentation/SKILL.md +238 -0
  221. package/skills/performance-optimization/SKILL.md +267 -0
  222. package/skills/performance-optimization/references/optimization-patterns.md +250 -0
  223. package/skills/planning-and-task-breakdown/SKILL.md +257 -0
  224. package/skills/security-and-hardening/SKILL.md +216 -0
  225. package/skills/security-and-hardening/references/hardening-patterns.md +324 -0
  226. package/skills/shipping-and-launch/SKILL.md +330 -0
  227. package/skills/source-driven-development/SKILL.md +216 -0
  228. package/skills/spec-driven-development/SKILL.md +259 -0
  229. package/skills/test-driven-development/SKILL.md +398 -0
  230. package/skills/using-agent-skills/SKILL.md +192 -0
  231. package/tests/bundle.test.cjs +85 -0
@@ -0,0 +1,28 @@
1
+ # Agent 维护流程验收合同
2
+
3
+ 本合同对应 UNIFICATION-SPEC.md;完整执行记录写入每次的审计或发布目录。
4
+
5
+ ## 源维护
6
+
7
+ - 上游 ref 是明确的 Git 提交;目录与 frontmatter 从该 ref 的对象记录。
8
+ - `agent/source` 的上游文件保留原始名称与内容;本项目新增文件限定在 rebrand/。
9
+ - 重放在源码分支上写入前失败。
10
+ - 重放规则改变时,运行 rebrand/tests/pipeline.test.cjs 并验证源候选到品牌的完整路径。
11
+
12
+ ## 品牌候选
13
+
14
+ - Skill、命令、Persona、references 和全部已记录普通运行文件与上游目录一致。
15
+ - Skill frontmatter 的名称和字段内容保持;换行差异不作为字段变更。
16
+ - 新增上游 Skill/Command 能进入目录、品牌说明和打包;缺失内容会失败。
17
+ - 文字补丁失去匹配时必须失败,不能静默遗漏。
18
+ - 重放后 --check 成功,完整 Node、路由与 hook 检查通过。
19
+ - npm package、插件和市场身份一致;六份版本一致。
20
+ - 品牌修复能独立递增发行版本,保留上游目录记录原文;包来源元数据与该记录一致。
21
+ - README、CLI 帮助和准备提示显示品牌版本与上游基线;--version 保持单一品牌版本输出。
22
+ - 打包后从压缩包重新验证完整布局、CLI 和宿主清单。
23
+
24
+ ## 证据边界
25
+
26
+ 源或包校验不等于 registry 发布,也不等于实际宿主启用和模型执行。
27
+ 英文确定性 TF-IDF 路由分数不能代替中文或真实模型行为验收。
28
+ 安装向导、宿主范围、升级和移除沿用安装遗漏审计的独立验收项。
@@ -0,0 +1,32 @@
1
+ # i3 Composer Agent 版本规则
2
+
3
+ 本规则已经用户确认,仅适用于 i3 Composer Agent 仓库。
4
+
5
+ | 信息 | 权威来源 | 本次确认值 |
6
+ | --- | --- | --- |
7
+ | i3 发行版本 | brand.json 的 releaseVersion | 1.0.0 |
8
+ | 上游版本 | upstream.json 的 upstreamVersion | 0.6.12 |
9
+ | 上游提交 | upstream.json 的 upstreamCommit | 1401c8b8030e023baeebb31781a6653fe8e93026 |
10
+
11
+ 品牌版本采用独立的 major.minor.patch 编号。1.0.0 是这套编号的起点;
12
+ 兼容的 i3 修复递增 patch,兼容的新功能递增 minor,需要使用者调整用法的变更递增 major。
13
+ 实际同步上游并审查选定提交后,才用 record-upstream.cjs 更新上游版本与提交。
14
+ 上游版本变动不自动决定品牌版本;品牌版本根据本次发行的实际变化确定。
15
+
16
+ 重放将品牌版本写入 npm 包和插件清单,把上游版本、提交及仓库写入
17
+ package.json 的 i3ComposerAgent 来源字段。package.template.json 不保存发行版本,
18
+ 发行版本统一由 brand.json 生成。
19
+
20
+ README、CLI 帮助和准备完成提示显示:
21
+
22
+ ```text
23
+ i3 Composer Agent v1.0.0
24
+ Based on agent-skills v0.6.12
25
+ ```
26
+
27
+ 在上述例子中,--version 输出 1.0.0,保留脚本使用的单一版本格式。--dry-run 的 JSON
28
+ 分别提供 version、upstreamVersion、upstreamCommit。
29
+
30
+ 已经发布的 @givolt/i3-composer-agent@0.6.12 及其 Git 标签作为历史记录保留。
31
+ 之前的 0.6.13 是未发布候选,新的独立版本候选替代它。
32
+ 1.0.0 的源码与打包验证不代表 npm 发布;发布仍按 MAINTENANCE.md 单独执行。
@@ -0,0 +1,194 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const fs = require('node:fs');
5
+ const path = require('node:path');
6
+ const { spawnSync } = require('node:child_process');
7
+ const { validateCatalog, frontmatter } = require('./catalog.cjs');
8
+ const brand = require('./brand.json');
9
+ const upstream = require('./upstream.json');
10
+ const root = path.resolve(__dirname, '..');
11
+ const mode = process.argv[2];
12
+ if (!['--apply', '--check'].includes(mode)) {
13
+ console.error('Usage: node rebrand/apply.cjs --apply | --check');
14
+ process.exit(1);
15
+ }
16
+ if (mode === '--apply') {
17
+ const branch = spawnSync('git', ['-C', root, 'branch', '--show-current'], { encoding: 'utf8' });
18
+ if (branch.status === 0 && branch.stdout.trim() === brand.sourceBranch) {
19
+ console.error(`Refusing to transform the source branch ${brand.sourceBranch}; create a release candidate first.`);
20
+ process.exit(1);
21
+ }
22
+ }
23
+ const inventory = validateCatalog(root, upstream);
24
+ const packageFile = path.join(root, 'package.json');
25
+ if (fs.existsSync(packageFile) && JSON.parse(fs.readFileSync(packageFile, 'utf8')).name !== brand.npmName) {
26
+ console.error('Upstream package.json now exists; explicitly adapt the distribution overlay before replaying.');
27
+ process.exit(1);
28
+ }
29
+ const changes = new Map();
30
+ function update(relative, content) {
31
+ const file = path.join(root, relative);
32
+ if (!fs.existsSync(file) || fs.readFileSync(file, 'utf8') !== content) changes.set(relative, content);
33
+ }
34
+ function transform(content, relative) {
35
+ const head = /^skills\/[^/]+\/SKILL\.md$/.test(relative) ? frontmatter(content) : '';
36
+ content = content.slice(head.length);
37
+ // Agent Skills is also the name of an independent specification.
38
+ const standard = '__I3_AGENT_SKILLS_STANDARD__';
39
+ let result = content
40
+ .replace('agents working on the [`addyosmani/agent-skills`](https://github.com/addyosmani/agent-skills) repository itself',
41
+ 'agents working on the i3 Composer Agent repository itself, derived from [`addyosmani/agent-skills`](https://github.com/addyosmani/agent-skills)')
42
+ .replace(/Agent Skills(?=\s+(?:specification|spec\b|format\b|standard\b))/g, standard)
43
+ .replaceAll('addy-agent-skills', brand.name)
44
+ .replaceAll('agent-skills@addy-agent-skills', `${brand.name}@${brand.name}`)
45
+ .replaceAll('agent-skills@agent-skills', `${brand.name}@${brand.name}`)
46
+ .replaceAll('agent-skills:', `${brand.name}:`)
47
+ .replaceAll('/path/to/agent-skills', `/path/to/${brand.name}`)
48
+ .replaceAll('./agent-skills', `./${brand.name}`)
49
+ .replace(/(?<![\w/.-])agent-skills(?![\w-])/g, brand.name)
50
+ .replaceAll('Agent Skills', brand.displayName)
51
+ .replaceAll(standard, 'Agent Skills');
52
+ if (relative.startsWith('docs/')) {
53
+ result = result.split('\n').map(line => {
54
+ if (/^\s*git clone https:\/\/github\.com\/addyosmani\/agent-skills(?:\.git)?\s*$/.test(line)) {
55
+ return `${line.match(/^\s*/)[0]}npx ${brand.npmName} --extract --dir ./${brand.name}`;
56
+ }
57
+ if (/^\s*(?:npx |codex |copilot |cmd |agy |gemini |\/plugin )/.test(line)) {
58
+ return line.replaceAll('https://github.com/addyosmani/agent-skills.git', `/path/to/${brand.name}`)
59
+ .replaceAll('https://github.com/addyosmani/agent-skills', `/path/to/${brand.name}`)
60
+ .replaceAll('addyosmani/agent-skills', `/path/to/${brand.name}`);
61
+ }
62
+ return line;
63
+ }).join('\n');
64
+ result = result
65
+ .replace(/^cmd skills add \/path\/to\/i3-composer-agent@main[^\n]*$/gm,
66
+ '# Branch selectors apply to Git sources; prepared npm bundles have no Git history.')
67
+ .replaceAll('Clone the repository', 'Prepare the plugin bundle')
68
+ .replaceAll('Clone this repository', 'Prepare the plugin bundle')
69
+ .replaceAll('Install from the remote repository', 'Install from a prepared local bundle')
70
+ .replaceAll('npx skills add addyosmani/agent-skills', `npx skills add /path/to/${brand.name}`)
71
+ .replaceAll('plugin marketplace add addyosmani/agent-skills', `plugin marketplace add /path/to/${brand.name}`)
72
+ .replaceAll('~/.gemini/config/plugins/agent-skills/', `~/.gemini/config/plugins/${brand.name}/`)
73
+ .replaceAll('.cursor/rules/agent-skills.mdc', `.cursor/rules/${brand.name}.mdc`)
74
+ .replace(/\[[^\]]+\]\(https:\/\/github\.com\/addyosmani\/agent-skills\/issues\/(\d+)\)/g,
75
+ (_, issue) => `[upstream agent-skills #${issue}](https://github.com/addyosmani/agent-skills/issues/${issue})`);
76
+ }
77
+ return head + result;
78
+ }
79
+ const skipDirectories = new Set(['.git', 'node_modules', 'rebrand', 'dist', 'tests', 'bin']);
80
+ 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']);
81
+ function walk(directory, prefix = '') {
82
+ for (const entry of fs.readdirSync(directory, { withFileTypes: true })) {
83
+ const relative = prefix ? `${prefix}/${entry.name}` : entry.name;
84
+ if (entry.isDirectory()) {
85
+ 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)) {
87
+ const original = fs.readFileSync(path.join(root, relative), 'utf8');
88
+ update(relative, transform(original, relative));
89
+ }
90
+ }
91
+ }
92
+ walk(root);
93
+ for (const patch of require('./fork-patches.json')) {
94
+ if (path.isAbsolute(patch.file) || patch.file.split(/[\\/]/).includes('..')) throw new Error('Patch must stay inside this Agent repository.');
95
+ const original = (changes.get(patch.file) ?? fs.readFileSync(path.join(root, patch.file), 'utf8')).replace(/\r\n/g, '\n');
96
+ if (original.includes(patch.to)) continue;
97
+ if (!original.includes(patch.from)) throw new Error(`Upstream changed ${patch.file}; review the fork patch before proceeding.`);
98
+ update(patch.file, original.replace(patch.from, patch.to));
99
+ }
100
+ const comparisonPath = 'docs/comparison.md';
101
+ const comparison = fs.readFileSync(path.join(root, comparisonPath), 'utf8');
102
+ if (!comparison.includes('> **Upstream research:**')) {
103
+ const note = `> **Upstream research:** This comparison is retained from Addy Osmani's \`agent-skills\` at commit \`${brand.upstreamCommit}\`. Its experiments describe the upstream project; they are not independent evaluations of ${brand.displayName}.\n\n`;
104
+ update(comparisonPath, comparison.replace('# How agent-skills compares\n\n', '# How agent-skills compares\n\n' + note));
105
+ }
106
+ for (const relative of ['plugin.json', '.claude-plugin/plugin.json', '.codex-plugin/plugin.json']) {
107
+ const manifest = JSON.parse(fs.readFileSync(path.join(root, relative), 'utf8'));
108
+ manifest.name = brand.name;
109
+ manifest.version = brand.releaseVersion;
110
+ manifest.description = brand.description;
111
+ if (manifest.author) manifest.author = { name: brand.maintainer };
112
+ manifest.homepage = brand.repository;
113
+ manifest.repository = brand.repository;
114
+ if (manifest.interface) {
115
+ manifest.interface.displayName = brand.displayName;
116
+ manifest.interface.developerName = brand.maintainer;
117
+ manifest.interface.shortDescription = 'Engineering workflow skills';
118
+ 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));
120
+ }
121
+ update(relative, JSON.stringify(manifest, null, 2) + '\n');
122
+ }
123
+ for (const relative of ['.claude-plugin/marketplace.json', '.agents/plugins/marketplace.json']) {
124
+ const manifest = JSON.parse(fs.readFileSync(path.join(root, relative), 'utf8'));
125
+ manifest.name = brand.name;
126
+ if (manifest.version) manifest.version = brand.releaseVersion;
127
+ if (manifest.description) manifest.description = brand.description;
128
+ if (manifest.owner) manifest.owner = { name: brand.maintainer };
129
+ if (manifest.interface) manifest.interface.displayName = brand.displayName;
130
+ for (const plugin of manifest.plugins) {
131
+ plugin.name = brand.name;
132
+ plugin.version = brand.releaseVersion;
133
+ plugin.description = brand.description;
134
+ plugin.source = relative.startsWith('.agents/') ? { source: 'local', path: './' } : './';
135
+ plugin.homepage = brand.repository;
136
+ }
137
+ update(relative, JSON.stringify(manifest, null, 2) + '\n');
138
+ }
139
+ function overlay(directory, prefix = '') {
140
+ for (const entry of fs.readdirSync(directory, { withFileTypes: true })) {
141
+ const relative = prefix ? `${prefix}/${entry.name}` : entry.name;
142
+ if (relative === '.github' && !fs.existsSync(path.join(root, '.github'))) continue;
143
+ if (entry.isDirectory()) overlay(path.join(directory, entry.name), relative);
144
+ else if (entry.isFile()) update(relative, fs.readFileSync(path.join(directory, entry.name), 'utf8'));
145
+ else throw new Error(`Unsupported distribution overlay entry: ${relative}`);
146
+ }
147
+ }
148
+ overlay(path.join(__dirname, 'overlay'));
149
+ const ignoreFile = path.join(root, '.gitignore');
150
+ if (fs.existsSync(ignoreFile)) {
151
+ const original = fs.readFileSync(ignoreFile, 'utf8');
152
+ const entries = new Set(original.split(/\r?\n/));
153
+ const missing = ['dist/', '*.tgz', `${brand.name}/`].filter(entry => !entries.has(entry));
154
+ if (missing.length) update('.gitignore', original.replace(/\n?$/, '\n') + missing.join('\n') + '\n');
155
+ }
156
+ const pkg = JSON.parse(fs.readFileSync(path.join(__dirname, 'package.template.json'), 'utf8'));
157
+ pkg.name = brand.npmName;
158
+ pkg.version = brand.releaseVersion;
159
+ pkg.repository = { type: 'git', url: brand.repository + '.git' };
160
+ pkg.homepage = brand.repository + '#readme';
161
+ pkg.i3ComposerAgent.upstreamVersion = upstream.upstreamVersion;
162
+ pkg.i3ComposerAgent.upstreamCommit = upstream.upstreamCommit;
163
+ pkg.i3ComposerAgent.upstreamRepository = brand.upstream;
164
+ update('package.json', JSON.stringify(pkg, null, 2) + '\n');
165
+ update('NOTICE.md', fs.readFileSync(path.join(__dirname, 'NOTICE.md'), 'utf8'));
166
+ function description(relative) {
167
+ const head = fs.readFileSync(path.join(root, relative), 'utf8').match(/^---\r?\n([\s\S]*?)\r?\n---/)?.[1] || '';
168
+ return (head.match(/^description:\s*(.*)$/m)?.[1] || '').replace(/^["']|["']$/g, '').replaceAll('|', '\\|');
169
+ }
170
+ const values = {
171
+ RELEASE_VERSION: brand.releaseVersion,
172
+ UPSTREAM_VERSION: upstream.upstreamVersion,
173
+ SKILL_COUNT: inventory.skills.length,
174
+ COMMAND_COUNT: inventory.commands.length,
175
+ 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'),
178
+ };
179
+ for (const [relative, template] of [
180
+ ['README.md', 'README.md'], ['docs/codex-setup.md', 'codex-setup.md'], ['docs/codebuddy-setup.md', 'codebuddy-setup.md'],
181
+ ]) {
182
+ const content = fs.readFileSync(path.join(__dirname, 'templates', template), 'utf8').replace(/\{\{([A-Z_]+)\}\}/g, (_, key) => {
183
+ if (!(key in values)) throw new Error(`Unknown template variable: ${key}`);
184
+ return values[key];
185
+ });
186
+ update(relative, content);
187
+ }
188
+ if (mode === '--apply') for (const [relative, content] of changes) {
189
+ fs.mkdirSync(path.dirname(path.join(root, relative)), { recursive: true });
190
+ fs.writeFileSync(path.join(root, relative), content);
191
+ }
192
+ 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;
@@ -0,0 +1,13 @@
1
+ {
2
+ "name": "i3-composer-agent",
3
+ "displayName": "i3 Composer Agent",
4
+ "npmName": "@givolt/i3-composer-agent",
5
+ "maintainer": "Givolt",
6
+ "upstream": "https://github.com/addyosmani/agent-skills",
7
+ "upstreamCommit": "1401c8b8030e023baeebb31781a6653fe8e93026",
8
+ "description": "Production-grade engineering skills for AI coding agents covering the development lifecycle from spec to ship.",
9
+ "repository": "https://github.com/49780522/i3-composer-agent",
10
+ "sourceBranch": "agent/source",
11
+ "releaseBranch": "main",
12
+ "releaseVersion": "1.0.0"
13
+ }
@@ -0,0 +1,56 @@
1
+ 'use strict';
2
+
3
+ const fs = require('node:fs');
4
+ const path = require('node:path');
5
+ const crypto = require('node:crypto');
6
+ const assert = require('node:assert/strict');
7
+ const runtimeRoots = ['skills', 'references', 'agents', 'commands', '.claude/commands', '.gemini/commands', 'hooks', '.claude-plugin', '.codex-plugin', '.agents/plugins'];
8
+ const runtimeFiles = ['plugin.json', 'LICENSE'];
9
+
10
+ function frontmatter(content) {
11
+ const match = content.match(/^---\r?\n[\s\S]*?\r?\n---(?:\r?\n|$)/);
12
+ assert.ok(match, 'Skill must have YAML frontmatter');
13
+ return match[0];
14
+ }
15
+ function describe(files, read) {
16
+ files = files.filter(file => path.basename(file) !== '.DS_Store');
17
+ const select = pattern => files.filter(name => pattern.test(name)).sort();
18
+ const skillFiles = select(/^skills\/[^/]+\/SKILL\.md$/);
19
+ const skillFrontmatter = {};
20
+ for (const file of skillFiles) {
21
+ const id = file.split('/')[1];
22
+ const head = frontmatter(read(file));
23
+ const name = head.match(/^name:\s*["']?([^\s"']+)["']?\s*$/m)?.[1];
24
+ assert.equal(name, id, `${file}: unstable skill identifier`);
25
+ skillFrontmatter[id] = crypto.createHash('sha256').update(head.replace(/\r\n/g, '\n')).digest('hex');
26
+ }
27
+ return {
28
+ skills: skillFiles.map(file => file.split('/')[1]),
29
+ commands: select(/^\.claude\/commands\/[^/]+\.md$/).map(file => path.basename(file, '.md')),
30
+ personas: select(/^agents\/[^/]+\.md$/).map(file => path.basename(file, '.md')),
31
+ references: select(/^references\/[^/]+\.md$/),
32
+ runtimeFiles: files.filter(file => runtimeFiles.includes(file) || runtimeRoots.some(root => file.startsWith(root + '/'))).sort(),
33
+ skillFrontmatter,
34
+ };
35
+ }
36
+ function catalog(root) {
37
+ const files = [];
38
+ function walk(directory, prefix) {
39
+ for (const entry of fs.readdirSync(directory, { withFileTypes: true })) {
40
+ const relative = `${prefix}/${entry.name}`;
41
+ if (entry.isDirectory()) walk(path.join(directory, entry.name), relative);
42
+ else if (entry.isFile()) files.push(relative);
43
+ }
44
+ }
45
+ for (const name of runtimeRoots) if (fs.existsSync(path.join(root, name))) walk(path.join(root, name), name);
46
+ for (const name of runtimeFiles) if (fs.existsSync(path.join(root, name))) files.push(name);
47
+ return describe(files, file => fs.readFileSync(path.join(root, file), 'utf8'));
48
+ }
49
+ function validateCatalog(root, expected) {
50
+ const actual = catalog(root);
51
+ for (const field of ['skills', 'commands', 'personas', 'references', 'runtimeFiles', 'skillFrontmatter']) {
52
+ assert.deepEqual(actual[field], expected[field], `upstream preservation failed: ${field}`);
53
+ }
54
+ return actual;
55
+ }
56
+ module.exports = { runtimeRoots, runtimeFiles, frontmatter, describe, catalog, validateCatalog };
@@ -0,0 +1,12 @@
1
+ [
2
+ {
3
+ "file": "scripts/validate-versions.js",
4
+ "from": "const manifestPaths = [\n \"plugin.json\",",
5
+ "to": "const manifestPaths = [\n \"package.json\",\n \"plugin.json\","
6
+ },
7
+ {
8
+ "file": "scripts/validate-versions-test.js",
9
+ "from": "const manifestPaths = [\n \"plugin.json\",",
10
+ "to": "const manifestPaths = [\n \"package.json\",\n \"plugin.json\","
11
+ }
12
+ ]
@@ -0,0 +1,177 @@
1
+ name: Test Plugin Installation
2
+
3
+ on:
4
+ push:
5
+ pull_request:
6
+ workflow_dispatch:
7
+
8
+ jobs:
9
+ validate-skills:
10
+ name: Validate skill content
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - uses: actions/checkout@v6
14
+ with:
15
+ fetch-depth: 0
16
+
17
+ - name: Set up Node.js
18
+ uses: actions/setup-node@v6
19
+ with:
20
+ node-version: '24'
21
+
22
+ - name: Validate all skills
23
+ run: node scripts/validate-skills.js
24
+
25
+ - name: Test skill lint rules
26
+ run: node --test scripts/lib/skill-lint-test.js
27
+
28
+ - name: Validate manifest versions
29
+ run: node scripts/validate-versions.js
30
+
31
+ - name: Validate i3 Composer Agent identity and replay
32
+ run: |
33
+ node scripts/validate-brand.cjs
34
+ node rebrand/apply.cjs --check
35
+
36
+ - name: Test npm bundle CLI
37
+ run: node --test tests/*.test.cjs rebrand/tests/*.test.cjs
38
+
39
+ - name: Test manifest version validator
40
+ run: node --test scripts/validate-versions-test.js
41
+
42
+ - name: Test skill eval runner
43
+ run: node --test scripts/run-evals-test.js
44
+
45
+ - name: Run skill evals (trigger + routing)
46
+ run: node scripts/run-evals.js --min-rank1 95
47
+
48
+ - name: Validate references/ links in skills
49
+ run: node scripts/validate-reference-links.js
50
+
51
+ - name: Test reference-link validator
52
+ run: node --test scripts/validate-reference-links-test.js
53
+
54
+ - name: Test floor-guard reference
55
+ run: node --test scripts/floor-guard-reference-test.js
56
+
57
+ - name: Test session-start hook payload
58
+ run: bash hooks/session-start-test.sh
59
+
60
+ validate-commands:
61
+ name: Validate command parity and description sync
62
+ runs-on: ubuntu-latest
63
+ steps:
64
+ - uses: actions/checkout@v6
65
+
66
+ - name: Set up Node.js
67
+ uses: actions/setup-node@v6
68
+ with:
69
+ node-version: '24'
70
+
71
+ - name: Validate commands across all tool directories
72
+ run: node scripts/validate-commands.js
73
+
74
+ - name: Test command validator
75
+ run: node --test scripts/validate-commands-test.js
76
+
77
+ - name: Validate spec/plan/todo artifact paths
78
+ run: node scripts/validate-artifact-paths.js
79
+
80
+ - name: Test artifact-path validator
81
+ run: node --test scripts/validate-artifact-paths-test.js
82
+
83
+ # Ubuntu coverage stays in the existing jobs above, preserving their check names.
84
+ validate-platforms:
85
+ name: Validate tooling (${{ matrix.os }})
86
+ runs-on: ${{ matrix.os }}
87
+ strategy:
88
+ fail-fast: false
89
+ matrix:
90
+ os: [macos-latest, windows-latest]
91
+ steps:
92
+ - uses: actions/checkout@v6
93
+ with:
94
+ fetch-depth: 0
95
+
96
+ - name: Set up Node.js
97
+ uses: actions/setup-node@v6
98
+ with:
99
+ node-version: '24'
100
+
101
+ - name: Test validators and eval runner
102
+ run: >-
103
+ node --test
104
+ scripts/lib/skill-lint-test.js
105
+ scripts/validate-versions-test.js
106
+ scripts/run-evals-test.js
107
+ scripts/validate-reference-links-test.js
108
+ scripts/validate-commands-test.js
109
+ scripts/validate-artifact-paths-test.js
110
+ scripts/floor-guard-reference-test.js
111
+ tests/*.test.cjs
112
+ rebrand/tests/*.test.cjs
113
+
114
+ - name: Validate all skills
115
+ run: node scripts/validate-skills.js
116
+
117
+ - name: Validate manifest versions
118
+ run: node scripts/validate-versions.js
119
+
120
+ - name: Validate references/ links in skills
121
+ run: node scripts/validate-reference-links.js
122
+
123
+ - name: Validate commands across all tool directories
124
+ run: node scripts/validate-commands.js
125
+
126
+ - name: Validate spec/plan/todo artifact paths
127
+ run: node scripts/validate-artifact-paths.js
128
+
129
+ - name: Run skill evals (trigger + routing)
130
+ run: node scripts/run-evals.js --min-rank1 95
131
+
132
+ test-hooks:
133
+ name: Hook regression tests
134
+ runs-on: ubuntu-latest
135
+ steps:
136
+ - uses: actions/checkout@v6
137
+
138
+ - name: Test sdd-cache hooks (stubbed curl, no network)
139
+ run: bash hooks/sdd-cache-test.sh
140
+
141
+ - name: Test simplify-ignore hook
142
+ run: bash hooks/simplify-ignore-test.sh
143
+
144
+ validate:
145
+ name: Validate plugin structure
146
+ needs: [validate-skills, validate-commands, validate-platforms]
147
+ runs-on: ubuntu-latest
148
+ steps:
149
+ - uses: actions/checkout@v6
150
+
151
+ - name: Install Claude Code
152
+ run: npm install -g @anthropic-ai/claude-code
153
+
154
+ - name: Validate marketplace and plugin manifests
155
+ run: claude plugin validate .
156
+
157
+ test-install:
158
+ name: Test plugin installation
159
+ runs-on: ubuntu-latest
160
+ needs: validate
161
+ steps:
162
+ - uses: actions/checkout@v6
163
+
164
+ - name: Install Claude Code
165
+ run: npm install -g @anthropic-ai/claude-code
166
+
167
+ - name: Configure git to use HTTPS
168
+ run: git config --global url."https://github.com/".insteadOf "git@github.com:"
169
+
170
+ - name: Add marketplace
171
+ run: claude plugin marketplace add ./
172
+
173
+ - name: List marketplaces
174
+ run: claude plugin marketplace list
175
+
176
+ - name: Install plugin
177
+ run: claude plugin install i3-composer-agent@i3-composer-agent --scope user
@@ -0,0 +1,23 @@
1
+ # i3 Composer Agent changes
2
+
3
+ ## 1.0.0 — Unreleased
4
+
5
+ Upstream baseline: agent-skills 0.6.12 at commit 1401c8b8030e023baeebb31781a6653fe8e93026.
6
+
7
+ ### Changed
8
+
9
+ - Start independent i3 release numbering. The upstream baseline remains 0.6.12; this replaces the unpublished 0.6.13 candidate.
10
+ - Display the i3 release and upstream baseline together in the README, CLI help, and bundle preparation output. Keep --version machine-readable.
11
+ - Include the upstream version, commit, and repository in package metadata.
12
+ - Maintain source changes on agent/source, generate and validate a branded candidate, then update main in this independent repository.
13
+
14
+ ### Fixed
15
+
16
+ - Preserve complete reviewed runtime assets when replaying branding, including newly approved upstream skills and commands.
17
+ - Keep replay checks repeatable in npm bundles without repository CI files.
18
+ - Preserve branded ignore rules and exclude Finder metadata from runtime preservation checks.
19
+
20
+ ## 0.6.12
21
+
22
+ - Publish the first i3 Composer Agent npm distribution based on agent-skills 0.6.12.
23
+ - Retain upstream skill IDs, command workflows, specialist personas, shared references, and MIT attribution.
@@ -0,0 +1,122 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const fs = require('node:fs');
5
+ const path = require('node:path');
6
+ const crypto = require('node:crypto');
7
+ const root = path.resolve(__dirname, '..');
8
+ const pkg = require('../package.json');
9
+ const name = 'i3-composer-agent';
10
+ const args = process.argv.slice(2);
11
+ const identity = `i3 Composer Agent v${pkg.version}\nBased on agent-skills v${pkg.i3ComposerAgent.upstreamVersion}`;
12
+ const help = `${identity}
13
+ ${pkg.name}
14
+
15
+ Prepare the complete i3 Composer Agent plugin, including shared references.
16
+
17
+ Usage:
18
+ npx ${pkg.name} --codebuddy [--dir <directory>]
19
+ npx ${pkg.name} --codex [--dir <directory>]
20
+ npx ${pkg.name} --claude [--dir <directory>]
21
+ npx ${pkg.name} --extract --dir <directory>
22
+
23
+ Options:
24
+ --dir <directory> Output directory (default: ./i3-composer-agent)
25
+ --dry-run Show the planned bundle without writing files
26
+ --force Replace an existing i3 bundle, preserving a backup
27
+ --version Print the package version
28
+ --help Show this help
29
+
30
+ Host flags prepare the bundle and print native registration commands.
31
+ Execute those commands in the intended host to enable the plugin.
32
+ `;
33
+
34
+ function quote(value) { return "'" + value.replaceAll("'", "'\\''") + "'"; }
35
+ function realDestination(target) {
36
+ let existing = target;
37
+ const suffix = [];
38
+ while (!fs.existsSync(existing)) {
39
+ suffix.unshift(path.basename(existing));
40
+ const parent = path.dirname(existing);
41
+ if (parent === existing) throw new Error(`Cannot resolve destination: ${target}`);
42
+ existing = parent;
43
+ }
44
+ return path.join(fs.realpathSync(existing), ...suffix);
45
+ }
46
+ function main() {
47
+ if (!args.length || args.includes('--help')) { console.log(help); return; }
48
+ if (args.length === 1 && args[0] === '--version') { console.log(pkg.version); return; }
49
+ let host;
50
+ let directory = path.join(process.cwd(), name);
51
+ let dryRun = false;
52
+ let force = false;
53
+ for (let i = 0; i < args.length; i++) {
54
+ const arg = args[i];
55
+ if (['--codebuddy', '--codex', '--claude', '--extract'].includes(arg)) {
56
+ if (host) throw new Error('Choose exactly one host flag or --extract.');
57
+ host = arg.slice(2);
58
+ } else if (arg === '--dir') {
59
+ if (!args[i + 1] || args[i + 1].startsWith('--')) throw new Error('--dir requires a directory.');
60
+ directory = path.resolve(args[++i]);
61
+ } else if (arg === '--dry-run') dryRun = true;
62
+ else if (arg === '--force') force = true;
63
+ else throw new Error(`Unknown option: ${arg}`);
64
+ }
65
+ if (!host) throw new Error('Choose --codebuddy, --codex, --claude, or --extract.');
66
+ directory = realDestination(directory);
67
+ const sourceRoot = fs.realpathSync(root);
68
+ if (directory === sourceRoot || directory.startsWith(sourceRoot + path.sep) || sourceRoot.startsWith(directory + path.sep)) {
69
+ throw new Error('The output directory must be outside this package directory.');
70
+ }
71
+ let exists = false;
72
+ try { fs.lstatSync(directory); exists = true; } catch (error) { if (error.code !== 'ENOENT') throw error; }
73
+ if (exists) {
74
+ if (!force) throw new Error(`Output already exists: ${directory}. Choose a new directory or use --force for an i3 bundle.`);
75
+ const manifest = JSON.parse(fs.readFileSync(path.join(directory, 'plugin.json'), 'utf8'));
76
+ if (manifest.name !== name) throw new Error('Refusing to replace a directory belonging to another plugin.');
77
+ }
78
+ if (dryRun) {
79
+ console.log(JSON.stringify({ name, version: pkg.version, upstreamVersion: pkg.i3ComposerAgent.upstreamVersion, upstreamCommit: pkg.i3ComposerAgent.upstreamCommit, directory, host, files: pkg.i3ComposerAgent.pluginFiles, replacesExisting: exists }, null, 2));
80
+ return;
81
+ }
82
+ fs.mkdirSync(path.dirname(directory), { recursive: true });
83
+ const staging = fs.mkdtempSync(path.join(path.dirname(directory), `.${name}-`));
84
+ let backup;
85
+ try {
86
+ for (const relative of pkg.i3ComposerAgent.pluginFiles) {
87
+ const source = path.join(root, relative);
88
+ const destination = path.join(staging, relative);
89
+ fs.mkdirSync(path.dirname(destination), { recursive: true });
90
+ fs.cpSync(source, destination, {
91
+ recursive: true,
92
+ filter: file => {
93
+ if (path.basename(file) === '.DS_Store') return false;
94
+ if (fs.lstatSync(file).isSymbolicLink()) throw new Error(`Bundle contains a symlink: ${file}`);
95
+ return !/(?:^|[\\/])(?:results|node_modules|\.git)(?:[\\/]|$)/.test(path.relative(root, file));
96
+ },
97
+ });
98
+ }
99
+ if (exists) {
100
+ backup = `${directory}.backup-${crypto.randomUUID()}`;
101
+ fs.renameSync(directory, backup);
102
+ }
103
+ try { fs.renameSync(staging, directory); }
104
+ catch (error) { if (backup) fs.renameSync(backup, directory); throw error; }
105
+ } finally { if (fs.existsSync(staging)) fs.rmSync(staging, { recursive: true, force: true }); }
106
+ console.log(identity);
107
+ console.log(`Prepared ${name} at ${directory}`);
108
+ if (backup) console.log(`Previous bundle preserved at ${backup}`);
109
+ if (host === 'extract') return;
110
+ console.log('\nRegister and enable the plugin with these native commands:');
111
+ const selector = `${name}@${name}`;
112
+ if (host === 'codex') {
113
+ console.log(`codex plugin marketplace add ${quote(directory)}`);
114
+ console.log(`codex plugin add ${selector}`);
115
+ console.log('Start a new Codex session and invoke the existing skill names. Lifecycle slash-command adaptation is separate.');
116
+ } else {
117
+ console.log(`/plugin marketplace add ${quote(directory)}`);
118
+ console.log(`/plugin install ${selector}`);
119
+ console.log(`Use /${name}:spec, /${name}:plan, /${name}:build, and /${name}:ship in ${host === 'claude' ? 'Claude Code' : 'CodeBuddy'}.`);
120
+ }
121
+ }
122
+ try { main(); } catch (error) { console.error(`${name}: ${error.message}`); process.exitCode = 1; }