@givolt/i3-composer-agent 2.0.0 → 2.1.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 (158) hide show
  1. package/.agents/plugins/marketplace.json +1 -1
  2. package/.claude-plugin/marketplace.json +1 -1
  3. package/.claude-plugin/plugin.json +1 -1
  4. package/.codex-plugin/plugin.json +1 -1
  5. package/README.md +29 -32
  6. package/bin/agent-targets.json +11 -0
  7. package/bin/asset-fingerprint.cjs +38 -0
  8. package/bin/cleanup-backups.cjs +16 -0
  9. package/bin/i3-composer-agent.cjs +27 -12
  10. package/bin/install.cjs +74 -28
  11. package/bin/native-content.cjs +29 -0
  12. package/bin/wizard.cjs +2 -1
  13. package/docs/antigravity-setup.md +1 -1
  14. package/docs/codebuddy-setup.md +11 -3
  15. package/docs/cursor-setup.md +2 -2
  16. package/docs/getting-started.md +0 -2
  17. package/docs/opencode-setup.md +4 -4
  18. package/docs/workbuddy-setup.md +92 -0
  19. package/package.json +36 -20
  20. package/plugin.json +1 -1
  21. package/CHANGELOG.md +0 -51
  22. package/NOTICE.md +0 -15
  23. package/docs/advanced-per-agent-configuration.md +0 -70
  24. package/docs/comparison.md +0 -131
  25. package/docs/developer-onboarding.md +0 -116
  26. package/docs/skill-anatomy.md +0 -203
  27. package/evals/README.md +0 -101
  28. package/evals/cases/i3-api-and-interface-design.json +0 -45
  29. package/evals/cases/i3-browser-testing-with-devtools.json +0 -44
  30. package/evals/cases/i3-ci-cd-and-automation.json +0 -45
  31. package/evals/cases/i3-code-review-and-quality.json +0 -49
  32. package/evals/cases/i3-code-simplification.json +0 -45
  33. package/evals/cases/i3-constraint-driven-development.json +0 -79
  34. package/evals/cases/i3-context-engineering.json +0 -44
  35. package/evals/cases/i3-debugging-and-error-recovery.json +0 -58
  36. package/evals/cases/i3-deprecation-and-migration.json +0 -52
  37. package/evals/cases/i3-documentation-and-adrs.json +0 -44
  38. package/evals/cases/i3-doubt-driven-development.json +0 -43
  39. package/evals/cases/i3-frontend-ui-engineering.json +0 -52
  40. package/evals/cases/i3-git-workflow-and-versioning.json +0 -47
  41. package/evals/cases/i3-idea-refine.json +0 -43
  42. package/evals/cases/i3-incremental-implementation.json +0 -57
  43. package/evals/cases/i3-interview-me.json +0 -42
  44. package/evals/cases/i3-observability-and-instrumentation.json +0 -44
  45. package/evals/cases/i3-performance-optimization.json +0 -53
  46. package/evals/cases/i3-planning-and-task-breakdown.json +0 -45
  47. package/evals/cases/i3-security-and-hardening.json +0 -53
  48. package/evals/cases/i3-shipping-and-launch.json +0 -56
  49. package/evals/cases/i3-source-driven-development.json +0 -44
  50. package/evals/cases/i3-spec-driven-development.json +0 -72
  51. package/evals/cases/i3-test-driven-development.json +0 -73
  52. package/evals/cases/i3-using-agent-skills.json +0 -44
  53. package/evals/fixtures/i3-api-and-interface-design/service-brief.md +0 -19
  54. package/evals/fixtures/i3-browser-testing-with-devtools/README.md +0 -5
  55. package/evals/fixtures/i3-browser-testing-with-devtools/index.html +0 -24
  56. package/evals/fixtures/i3-browser-testing-with-devtools/server.js +0 -15
  57. package/evals/fixtures/i3-ci-cd-and-automation/package.json +0 -8
  58. package/evals/fixtures/i3-ci-cd-and-automation/src/slug.js +0 -3
  59. package/evals/fixtures/i3-ci-cd-and-automation/test/slug.test.js +0 -9
  60. package/evals/fixtures/i3-code-review-and-quality/user-search.diff +0 -16
  61. package/evals/fixtures/i3-code-simplification/config-parser.js +0 -46
  62. package/evals/fixtures/i3-code-simplification/config-parser.test.js +0 -15
  63. package/evals/fixtures/i3-context-engineering/context-audit.md +0 -15
  64. package/evals/fixtures/i3-debugging-and-error-recovery/pagination.js +0 -8
  65. package/evals/fixtures/i3-debugging-and-error-recovery/pagination.test.js +0 -9
  66. package/evals/fixtures/i3-debugging-and-error-recovery/time-pressure.md +0 -6
  67. package/evals/fixtures/i3-deprecation-and-migration/api-inventory.md +0 -9
  68. package/evals/fixtures/i3-documentation-and-adrs/decision-context.md +0 -16
  69. package/evals/fixtures/i3-doubt-driven-development/migration-plan.md +0 -19
  70. package/evals/fixtures/i3-frontend-ui-engineering/Button.tsx +0 -7
  71. package/evals/fixtures/i3-frontend-ui-engineering/design-system.md +0 -11
  72. package/evals/fixtures/i3-git-workflow-and-versioning/.eval/working-tree.patch +0 -21
  73. package/evals/fixtures/i3-git-workflow-and-versioning/app.js +0 -7
  74. package/evals/fixtures/i3-git-workflow-and-versioning/app.test.js +0 -9
  75. package/evals/fixtures/i3-incremental-implementation/reports.js +0 -7
  76. package/evals/fixtures/i3-incremental-implementation/reports.test.js +0 -12
  77. package/evals/fixtures/i3-incremental-implementation/tasks/plan.md +0 -8
  78. package/evals/fixtures/i3-observability-and-instrumentation/operations.md +0 -11
  79. package/evals/fixtures/i3-observability-and-instrumentation/payment-retry.js +0 -14
  80. package/evals/fixtures/i3-performance-optimization/benchmark.js +0 -15
  81. package/evals/fixtures/i3-performance-optimization/products.js +0 -14
  82. package/evals/fixtures/i3-planning-and-task-breakdown/notifications-spec.md +0 -18
  83. package/evals/fixtures/i3-security-and-hardening/webhook.js +0 -11
  84. package/evals/fixtures/i3-security-and-hardening/webhook.test.js +0 -13
  85. package/evals/fixtures/i3-shipping-and-launch/authority-pressure.md +0 -6
  86. package/evals/fixtures/i3-shipping-and-launch/launch-status.md +0 -11
  87. package/evals/fixtures/i3-source-driven-development/framework-task.md +0 -10
  88. package/evals/fixtures/i3-spec-driven-development/billing-brief.md +0 -16
  89. package/evals/fixtures/i3-test-driven-development/BUG.md +0 -10
  90. package/evals/fixtures/i3-test-driven-development/README.md +0 -28
  91. package/evals/fixtures/i3-test-driven-development/package.json +0 -9
  92. package/evals/fixtures/i3-test-driven-development/src/split.js +0 -8
  93. package/evals/fixtures/i3-test-driven-development/test/split.test.js +0 -13
  94. package/evals/fixtures/i3-using-agent-skills/incident.md +0 -6
  95. package/evals/fixtures/incremental-implementation-pressure/draft-export.js +0 -17
  96. package/evals/fixtures/incremental-implementation-pressure/scenario.md +0 -9
  97. package/evals/fixtures/spec-driven-development-decomposition/portal-brief.md +0 -22
  98. package/evals/fixtures/test-driven-development-ecosystem/README.md +0 -9
  99. package/evals/fixtures/test-driven-development-ecosystem/ledger.py +0 -15
  100. package/evals/fixtures/test-driven-development-ecosystem/test_ledger.py +0 -19
  101. package/evals/plugin/code-review-fires/graders/off-by-one.md +0 -7
  102. package/evals/plugin/code-review-fires/graders/severity-labels.md +0 -4
  103. package/evals/plugin/code-review-fires/graders/skill-fired.md +0 -5
  104. package/evals/plugin/code-review-fires/prompt.md +0 -31
  105. package/evals/plugin/code-review-stays-quiet/graders/not-fired.md +0 -8
  106. package/evals/plugin/code-review-stays-quiet/graders/tdd-fired.md +0 -6
  107. package/evals/plugin/code-review-stays-quiet/prompt.md +0 -8
  108. package/evals/plugin/code-review-stays-quiet-on-commit-message/graders/not-fired.md +0 -8
  109. package/evals/plugin/code-review-stays-quiet-on-commit-message/prompt.md +0 -25
  110. package/evals/skill-impact.md +0 -6
  111. package/rebrand/INSTALLATION-SPEC.md +0 -47
  112. package/rebrand/MAINTENANCE.md +0 -114
  113. package/rebrand/NOTICE.md +0 -15
  114. package/rebrand/PR-WORKFLOW.md +0 -34
  115. package/rebrand/PREFIX-SPEC.md +0 -16
  116. package/rebrand/UNIFICATION-SPEC.md +0 -33
  117. package/rebrand/VALIDATION.md +0 -32
  118. package/rebrand/VERSIONING.md +0 -35
  119. package/rebrand/apply.cjs +0 -217
  120. package/rebrand/brand.json +0 -13
  121. package/rebrand/catalog.cjs +0 -70
  122. package/rebrand/fork-patches.json +0 -27
  123. package/rebrand/identifiers.cjs +0 -41
  124. package/rebrand/overlay/.github/workflows/test-plugin-install.yml +0 -177
  125. package/rebrand/overlay/CHANGELOG.md +0 -51
  126. package/rebrand/overlay/bin/agent-targets.json +0 -726
  127. package/rebrand/overlay/bin/i3-composer-agent.cjs +0 -190
  128. package/rebrand/overlay/bin/install.cjs +0 -180
  129. package/rebrand/overlay/bin/skills-registry.LICENSE +0 -21
  130. package/rebrand/overlay/bin/wizard.cjs +0 -66
  131. package/rebrand/overlay/scripts/validate-brand.cjs +0 -44
  132. package/rebrand/overlay/tests/bundle.test.cjs +0 -85
  133. package/rebrand/overlay/tests/installer.test.cjs +0 -241
  134. package/rebrand/package.template.json +0 -82
  135. package/rebrand/rebrand.sh +0 -4
  136. package/rebrand/record-upstream.cjs +0 -37
  137. package/rebrand/templates/README.md +0 -130
  138. package/rebrand/templates/codebuddy-setup.md +0 -89
  139. package/rebrand/templates/codex-setup.md +0 -45
  140. package/rebrand/tests/pipeline.test.cjs +0 -253
  141. package/rebrand/upstream.json +0 -171
  142. package/scripts/floor-guard-reference-test.js +0 -291
  143. package/scripts/lib/skill-lint-test.js +0 -650
  144. package/scripts/lib/skill-lint.js +0 -586
  145. package/scripts/run-evals-test.js +0 -623
  146. package/scripts/run-evals.js +0 -638
  147. package/scripts/validate-artifact-paths-test.js +0 -179
  148. package/scripts/validate-artifact-paths.js +0 -130
  149. package/scripts/validate-brand.cjs +0 -44
  150. package/scripts/validate-commands-test.js +0 -216
  151. package/scripts/validate-commands.js +0 -223
  152. package/scripts/validate-reference-links-test.js +0 -495
  153. package/scripts/validate-reference-links.js +0 -187
  154. package/scripts/validate-skills.js +0 -69
  155. package/scripts/validate-versions-test.js +0 -32
  156. package/scripts/validate-versions.js +0 -35
  157. package/tests/bundle.test.cjs +0 -85
  158. package/tests/installer.test.cjs +0 -241
@@ -6,7 +6,7 @@
6
6
  "plugins": [
7
7
  {
8
8
  "name": "i3-composer-agent",
9
- "version": "2.0.0",
9
+ "version": "2.1.0",
10
10
  "description": "Production-grade engineering skills for AI coding agents covering the development lifecycle from spec to ship.",
11
11
  "source": {
12
12
  "source": "local",
@@ -8,7 +8,7 @@
8
8
  "plugins": [
9
9
  {
10
10
  "name": "i3-composer-agent",
11
- "version": "2.0.0",
11
+ "version": "2.1.0",
12
12
  "source": "./",
13
13
  "description": "Production-grade engineering skills for AI coding agents covering the development lifecycle from spec to ship.",
14
14
  "homepage": "https://github.com/49780522/i3-composer-agent",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "i3-composer-agent",
3
- "version": "2.0.0",
3
+ "version": "2.1.0",
4
4
  "description": "Production-grade engineering skills for AI coding agents covering the development lifecycle from spec to ship.",
5
5
  "author": {
6
6
  "name": "Givolt"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "i3-composer-agent",
3
- "version": "2.0.0",
3
+ "version": "2.1.0",
4
4
  "description": "Production-grade engineering skills for AI coding agents covering the development lifecycle from spec to ship.",
5
5
  "author": {
6
6
  "name": "Givolt"
package/README.md CHANGED
@@ -1,13 +1,7 @@
1
- # i3 Composer Agent v2.0.0
2
-
3
- **Based on agent-skills v0.6.12**
1
+ # i3 Composer Agent v2.1.0
4
2
 
5
3
  **Intelligence. Integration. Innovation.**
6
4
 
7
- Engineering skills, lifecycle commands, and specialist personas for AI coding agents.
8
- Based on [Agent Skills](https://github.com/addyosmani/agent-skills) by Addy Osmani
9
- (MIT). See [NOTICE.md](NOTICE.md) for attribution.
10
-
11
5
  The npm package is `@givolt/i3-composer-agent`; the plugin and marketplace ID is
12
6
  `i3-composer-agent`. Commands and Skill IDs use the `i3-` prefix.
13
7
 
@@ -19,40 +13,53 @@ Run in the project where you want to use the skills:
19
13
  npx @givolt/i3-composer-agent
20
14
  # Preselect a tool; the wizard still allows multiple selections:
21
15
  npx @givolt/i3-composer-agent --codebuddy
16
+ npx @givolt/i3-composer-agent --workbuddy
22
17
  ```
23
18
 
24
19
  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).
20
+ an installation summary, and confirmation. It offers 80 directory
21
+ presets: the pinned [Vercel Skills CLI registry](https://github.com/vercel-labs/skills/blob/48dc9e8eb8aa19040e91cb90ba0b642c9cbad57e/src/agents.ts)
22
+ plus a native WorkBuddy preset.
27
23
  Choose by tool ID or comma-separated menu numbers. Use `--list-agents` to list
28
24
  the choices. Directory presets are not an execution test of every host.
29
25
 
30
26
  Every selected tool receives all 25 skills and shared references.
31
- CodeBuddy and Claude Code also receive 9 short command workflows
27
+ CodeBuddy, WorkBuddy and Claude Code also receive 9 short command workflows
32
28
  and 4 persona files. Other tools use their native skill support;
33
29
  short lifecycle commands depend on the host. Shared destinations are installed
34
- once. License and attribution files accompany each native installation.
30
+ once. A standard MIT license accompanies the shared references.
35
31
  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).
32
+ [CodeBuddy setup](docs/codebuddy-setup.md), [WorkBuddy setup](docs/workbuddy-setup.md)
33
+ and [Codex setup](docs/codex-setup.md).
37
34
 
38
35
  For an explicit installation without prompts:
39
36
 
40
37
  ```bash
41
38
  npx @givolt/i3-composer-agent --agents codebuddy,codex --scope project --yes
39
+ npx @givolt/i3-composer-agent --workbuddy --scope project --yes
40
+ npx @givolt/i3-composer-agent --agents codebuddy,workbuddy --scope project --yes
41
+ npx @givolt/i3-composer-agent --workbuddy --scope global --yes
42
42
  npx @givolt/i3-composer-agent --claude --scope global --yes
43
43
  npx @givolt/i3-composer-agent --codebuddy --scope project --dry-run
44
44
  ```
45
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.
46
+ CodeBuddy and WorkBuddy share one project installation under `.codebuddy/`.
47
+ Existing `.workbuddy/` project settings are preserved. Global installations use
48
+ separate `~/.codebuddy/` and `~/.workbuddy/` directories.
49
+
50
+ Unchanged manifest-owned assets from the same version and scope are reused;
51
+ adding a client merges its ID into the shared installation manifest. Modified
52
+ files, unowned collisions and version upgrades require confirmation; use
53
+ `--force` with noninteractive installs after reviewing the dry run.
54
+ After successful installation, replaced files and installer-owned historical
55
+ backups are removed. A failed installation restores the previous files.
49
56
  `npx -y` accepts npm's package download prompt; the package's own `--yes` flag
50
57
  accepts the explicit installation plan.
51
58
 
52
59
  Earlier native installations migrate their unprefixed Skill and command paths
53
60
  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`
61
+ The migration removes owned legacy paths after successful installation. Use
62
+ `/i3-spec` in CodeBuddy or WorkBuddy, or `$i3-spec-driven-development`
56
63
  in Codex after upgrading.
57
64
 
58
65
  ## Prepare the complete plugin
@@ -90,7 +97,7 @@ is maintained separately.
90
97
 
91
98
  ## Commands
92
99
 
93
- Native CodeBuddy and Claude Code installations use short filenames such as
100
+ Native CodeBuddy, WorkBuddy and Claude Code installations use short filenames such as
94
101
  `/i3-spec`, `/i3-plan`, `/i3-build` and `/i3-ship`. Hosts supporting Claude-compatible plugin
95
102
  commands load the same workflows under the plugin namespace:
96
103
 
@@ -106,7 +113,8 @@ commands load the same workflows under the plugin namespace:
106
113
  | /i3-composer-agent:i3-test | Run TDD workflow — write failing tests, implement, verify. For bugs, use the Prove-It pattern. |
107
114
  | /i3-composer-agent:i3-webperf | Run a web performance audit via the web-performance-auditor persona |
108
115
 
109
- `/i3-composer-agent:i3-build auto` runs the existing approved-plan workflow.
116
+ `/i3-build auto` runs the existing approved-plan workflow in native installations;
117
+ plugin installations use `/i3-composer-agent:i3-build auto`.
110
118
 
111
119
  ## Skills
112
120
 
@@ -146,17 +154,6 @@ npx @givolt/i3-composer-agent --codebuddy --dir /path/to/plugin --dry-run
146
154
  npx @givolt/i3-composer-agent --codebuddy --dir /path/to/plugin --force
147
155
  ```
148
156
 
149
- Explicit `--dir` retains the original plugin preparation behavior. Replacement
150
- preserves the previous i3 bundle as a backup. Repository-scoped
157
+ Explicit `--dir` retains the plugin preparation behavior. Successful replacement
158
+ removes the previous bundle and this plugin's historical backups. Repository-scoped
151
159
  AGENTS.md and CLAUDE.md are not copied into business projects.
152
-
153
- ## Maintaining this fork
154
-
155
- This repository is independent of the GSD-based i3 Composer Work repository.
156
- `agent/source` retains upstream source and the `rebrand/` rules; `main` contains
157
- the validated branded distribution. Create release candidates from the source
158
- branch, replay branding, validate, then update the release branch.
159
-
160
- See [maintenance](rebrand/MAINTENANCE.md), [source PR workflow](rebrand/PR-WORKFLOW.md),
161
- [versioning](rebrand/VERSIONING.md), [changelog](CHANGELOG.md),
162
- and [validation contract](rebrand/VALIDATION.md).
@@ -721,6 +721,17 @@
721
721
  "base": "home",
722
722
  "path": ".zencoder/skills"
723
723
  }
724
+ },
725
+ {
726
+ "id": "workbuddy",
727
+ "label": "WorkBuddy",
728
+ "projectSkillsDir": ".codebuddy/skills",
729
+ "globalSkillsDir": {
730
+ "base": "env",
731
+ "env": "WORKBUDDY_CONFIG_DIR",
732
+ "fallback": ".workbuddy",
733
+ "path": "skills"
734
+ }
724
735
  }
725
736
  ]
726
737
  }
@@ -0,0 +1,38 @@
1
+ 'use strict';
2
+
3
+ const fs = require('node:fs');
4
+ const path = require('node:path');
5
+ const crypto = require('node:crypto');
6
+ const { nativeContent } = require('./native-content.cjs');
7
+
8
+ // Compare the complete tree without following links. When asset is provided,
9
+ // hash the source as it will be rendered by the native installer.
10
+ function fingerprint(file, asset) {
11
+ const hash = crypto.createHash('sha256');
12
+ function visit(current, relative) {
13
+ let stat;
14
+ try { stat = fs.lstatSync(current); }
15
+ catch (error) { if (error.code === 'ENOENT') return false; throw error; }
16
+ if (stat.isSymbolicLink() || (!stat.isDirectory() && !stat.isFile())) {
17
+ if (asset) throw new Error(`Package contains an unsupported file: ${current}`);
18
+ return false;
19
+ }
20
+ hash.update(JSON.stringify([relative, stat.isDirectory() ? 'directory' : 'file', stat.mode & 0o111]) + '\n');
21
+ if (stat.isDirectory()) {
22
+ for (const entry of fs.readdirSync(current).sort()) {
23
+ if (asset && entry === '.DS_Store') continue;
24
+ if (!visit(path.join(current, entry), path.join(relative, entry))) return false;
25
+ }
26
+ } else {
27
+ const content = asset && current.endsWith('.md')
28
+ ? Buffer.from(nativeContent(fs.readFileSync(current, 'utf8'), asset))
29
+ : fs.readFileSync(current);
30
+ hash.update(String(content.length) + '\n');
31
+ hash.update(content);
32
+ }
33
+ return true;
34
+ }
35
+ return visit(file, '') ? hash.digest('hex') : undefined;
36
+ }
37
+
38
+ module.exports = { fingerprint };
@@ -0,0 +1,16 @@
1
+ 'use strict';
2
+
3
+ const fs = require('node:fs');
4
+ const path = require('node:path');
5
+ const uuid = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
6
+
7
+ function cleanupBackups(directory, prefix, belongs = () => true) {
8
+ // Installer backups have a v4 UUID suffix. Ignore lookalikes and symlinks.
9
+ for (const entry of fs.readdirSync(directory, { withFileTypes: true })) {
10
+ if (!entry.isDirectory() || !entry.name.startsWith(prefix) || !uuid.test(entry.name.slice(prefix.length))) continue;
11
+ const backup = path.join(directory, entry.name);
12
+ if (belongs(backup)) fs.rmSync(backup, { recursive: true });
13
+ }
14
+ }
15
+
16
+ module.exports = { cleanupBackups };
@@ -4,11 +4,12 @@
4
4
  const fs = require('node:fs');
5
5
  const path = require('node:path');
6
6
  const crypto = require('node:crypto');
7
+ const { cleanupBackups } = require('./cleanup-backups.cjs');
7
8
  const root = path.resolve(__dirname, '..');
8
9
  const pkg = require('../package.json');
9
10
  const name = 'i3-composer-agent';
10
11
  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 identity = `i3 Composer Agent v${pkg.version}`;
12
13
  const help = `${identity}
13
14
  ${pkg.name}
14
15
 
@@ -17,6 +18,8 @@ Install engineering skills with a multi-tool installation wizard.
17
18
  Usage:
18
19
  npx ${pkg.name}
19
20
  npx ${pkg.name} --codebuddy
21
+ npx ${pkg.name} --workbuddy
22
+ npx ${pkg.name} --agents codebuddy,workbuddy --scope project --yes
20
23
  npx ${pkg.name} --agents codebuddy,codex --scope project --yes
21
24
  npx ${pkg.name} --prepare --claude --dir <directory>
22
25
  npx ${pkg.name} --extract --dir <directory>
@@ -24,6 +27,7 @@ Usage:
24
27
  Options:
25
28
  --agents <ids> Comma-separated tool IDs; multiple tools are supported
26
29
  --codebuddy Preselect CodeBuddy desktop IDE / CodeBuddy Code
30
+ --workbuddy Preselect WorkBuddy (shared project / independent global)
27
31
  --codex Preselect Codex
28
32
  --claude Preselect Claude Code
29
33
  --scope <scope> project or global (or use --global / --local)
@@ -33,12 +37,12 @@ Options:
33
37
  --prepare Prepare a complete plugin for native plugin registration
34
38
  --dir <directory> Plugin output directory; implies --prepare
35
39
  --dry-run Show the installation or bundle plan without writing files
36
- --force Replace existing assets, preserving backups
40
+ --force Replace existing assets; remove old files after success
37
41
  --version Print the package version
38
42
  --help Show this help
39
43
 
40
44
  The terminal wizard selects tools and scope, then installs native skill files.
41
- CodeBuddy and Claude Code also receive short lifecycle commands and personas.
45
+ CodeBuddy, WorkBuddy and Claude Code also receive short commands and personas.
42
46
  Other tools receive skills and references; command availability is host-specific.
43
47
  Use --prepare for complete plugins, including hooks and host registration.
44
48
  `;
@@ -63,6 +67,7 @@ function prepare() {
63
67
  for (let i = 0; i < args.length; i++) {
64
68
  const arg = args[i];
65
69
  if (arg === '--prepare') continue;
70
+ if (arg === '--workbuddy') throw new Error('For native WorkBuddy installation, use --workbuddy --scope project|global --yes without --prepare or --dir.');
66
71
  if (['--codebuddy', '--codex', '--claude', '--extract'].includes(arg)) {
67
72
  if (host) throw new Error('Choose exactly one host flag or --extract.');
68
73
  host = arg.slice(2);
@@ -87,12 +92,13 @@ function prepare() {
87
92
  if (manifest.name !== name) throw new Error('Refusing to replace a directory belonging to another plugin.');
88
93
  }
89
94
  if (dryRun) {
90
- 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));
95
+ console.log(JSON.stringify({ name, version: pkg.version, directory, host, files: pkg.i3ComposerAgent.pluginFiles, replacesExisting: exists }, null, 2));
91
96
  return;
92
97
  }
93
98
  fs.mkdirSync(path.dirname(directory), { recursive: true });
94
99
  const staging = fs.mkdtempSync(path.join(path.dirname(directory), `.${name}-`));
95
100
  let backup;
101
+ let completed = false;
96
102
  try {
97
103
  for (const relative of pkg.i3ComposerAgent.pluginFiles) {
98
104
  const source = path.join(root, relative);
@@ -113,10 +119,18 @@ function prepare() {
113
119
  }
114
120
  try { fs.renameSync(staging, directory); }
115
121
  catch (error) { if (backup) fs.renameSync(backup, directory); throw error; }
116
- } finally { if (fs.existsSync(staging)) fs.rmSync(staging, { recursive: true, force: true }); }
122
+ completed = true;
123
+ } finally {
124
+ if (fs.existsSync(staging)) fs.rmSync(staging, { recursive: true, force: true });
125
+ if (completed) cleanupBackups(path.dirname(directory), `${path.basename(directory)}.backup-`, previous => {
126
+ const manifest = path.join(previous, 'plugin.json');
127
+ try {
128
+ return !fs.lstatSync(manifest).isSymbolicLink() && JSON.parse(fs.readFileSync(manifest, 'utf8')).name === name;
129
+ } catch { return false; }
130
+ });
131
+ }
117
132
  console.log(identity);
118
133
  console.log(`Prepared ${name} at ${directory}`);
119
- if (backup) console.log(`Previous bundle preserved at ${backup}`);
120
134
  if (host === 'extract') return;
121
135
  console.log('\nRegister and enable the plugin with these native commands:');
122
136
  const selector = `${name}@${name}`;
@@ -142,7 +156,7 @@ async function main() {
142
156
  const options = { agents: [], projectDir: process.cwd() };
143
157
  for (let i = 0; i < args.length; i++) {
144
158
  const arg = args[i];
145
- if (['--codebuddy', '--codex', '--claude'].includes(arg)) options.agents.push(arg.slice(2));
159
+ if (['--codebuddy', '--workbuddy', '--codex', '--claude'].includes(arg)) options.agents.push(arg.slice(2));
146
160
  else if (['--agents', '--scope', '--project-dir'].includes(arg)) {
147
161
  if (!args[i + 1] || args[i + 1].startsWith('--')) throw new Error(`${arg} requires a value.`);
148
162
  const value = args[++i];
@@ -168,7 +182,7 @@ async function main() {
168
182
  }
169
183
  const plan = installer.planInstallation(options);
170
184
  if (options.dryRun) {
171
- console.log(JSON.stringify({ name, version: pkg.version, upstreamVersion: pkg.i3ComposerAgent.upstreamVersion, upstreamCommit: pkg.i3ComposerAgent.upstreamCommit, mode: plan.mode, scope: plan.scope, agents: plan.agents, targets: plan.targets, conflicts: plan.conflicts }, null, 2));
185
+ console.log(JSON.stringify({ name, version: pkg.version, mode: plan.mode, scope: plan.scope, agents: plan.agents, targets: plan.targets, conflicts: plan.conflicts, reused: plan.reused }, null, 2));
172
186
  return;
173
187
  }
174
188
  if (!options.yes) {
@@ -176,15 +190,16 @@ async function main() {
176
190
  if (!confirmed) { console.log('Installation cancelled. No files changed.'); return; }
177
191
  options.force = plan.conflicts.length > 0;
178
192
  }
179
- const backups = installer.executeInstallation(plan, { force: options.force });
193
+ installer.executeInstallation(plan, { force: options.force });
180
194
  console.log(identity);
195
+ if (plan.reused.length) console.log(`Reused ${plan.reused.length} unchanged assets from the same package version.`);
181
196
  for (const target of plan.targets) {
182
197
  console.log(`Installed ${target.agents.join(', ')} skills at ${target.skillsDirectory}`);
183
198
  if (target.commandsDirectory) console.log(`Commands: /i3-spec, /i3-plan, /i3-build, /i3-ship (all ${fs.readdirSync(target.commandsDirectory).filter(file => file.endsWith('.md')).length} workflows) at ${target.commandsDirectory}`);
184
199
  }
185
- for (const backup of backups) console.log(`Previous assets preserved at ${backup}`);
186
200
  console.log('Reload the IDE window or start a new host session to discover installed files.');
187
- if (plan.agents.some(id => !['codebuddy', 'claude-code'].includes(id))) console.log('These tools use the existing skill IDs; lifecycle slash-command support depends on the host.');
188
- console.log('Native skill installation does not enable plugin hooks. Use --prepare for complete plugin registration.');
201
+ if (plan.agents.some(id => !['codebuddy', 'workbuddy', 'claude-code'].includes(id))) console.log('These tools use the existing skill IDs; lifecycle slash-command support depends on the host.');
202
+ console.log('Native skill installation does not enable plugin hooks.');
203
+ if (plan.agents.some(id => ['codebuddy', 'codex', 'claude-code'].includes(id))) console.log('For CodeBuddy, Codex or Claude Code plugin registration, use --prepare with the matching host flag.');
189
204
  }
190
205
  main().catch(error => { console.error(`${name}: ${error.message}`); process.exitCode = 1; });
package/bin/install.cjs CHANGED
@@ -5,9 +5,12 @@ const path = require('node:path');
5
5
  const os = require('node:os');
6
6
  const crypto = require('node:crypto');
7
7
  const registry = require('./agent-targets.json');
8
- const upstream = require('../rebrand/upstream.json');
8
+ const { cleanupBackups } = require('./cleanup-backups.cjs');
9
+ const { nativeContent } = require('./native-content.cjs');
10
+ const { fingerprint } = require('./asset-fingerprint.cjs');
9
11
  const root = path.resolve(__dirname, '..');
10
12
  const name = 'i3-composer-agent';
13
+ const version = require('../package.json').version;
11
14
  const aliases = { claude: 'claude-code', gemini: 'gemini-cli', copilot: 'github-copilot' };
12
15
  function exists(file) {
13
16
  try { fs.lstatSync(file); return true; }
@@ -43,6 +46,10 @@ function checkDestination(file) {
43
46
  throw new Error('Installation destinations must be outside this package directory.');
44
47
  }
45
48
  }
49
+ function manifestContent(plan, asset) {
50
+ return JSON.stringify({ name, version, entryPrefix: 'i3-', scope: plan.scope, agents: asset.target.agents,
51
+ assets: plan.assets.filter(item => item.base === asset.base && item.kind !== 'legacy').map(item => path.relative(asset.base, item.destination)) }, null, 2) + '\n';
52
+ }
46
53
  function planInstallation({ agents, scope, projectDir = process.cwd(), home = os.homedir(), env = process.env }) {
47
54
  agents = selectAgents(agents);
48
55
  if (!agents.length) throw new Error('Choose at least one tool.');
@@ -55,7 +62,7 @@ function planInstallation({ agents, scope, projectDir = process.cwd(), home = os
55
62
  if (!targets.has(skillsDirectory)) targets.set(skillsDirectory, { agents: [], skillsDirectory, referencesDirectory: path.join(base, 'references'), base });
56
63
  const target = targets.get(skillsDirectory);
57
64
  target.agents.push(id);
58
- if (['codebuddy', 'claude-code'].includes(id)) {
65
+ if (['codebuddy', 'workbuddy', 'claude-code'].includes(id)) {
59
66
  target.commandsDirectory = path.join(base, 'commands');
60
67
  target.personasDirectory = path.join(base, 'agents');
61
68
  }
@@ -71,6 +78,20 @@ function planInstallation({ agents, scope, projectDir = process.cwd(), home = os
71
78
  }
72
79
  }
73
80
  for (const target of targets.values()) {
81
+ const manifestFile = path.join(target.base, `.${name}.json`);
82
+ const previous = exists(manifestFile) && !fs.lstatSync(manifestFile).isSymbolicLink()
83
+ ? JSON.parse(fs.readFileSync(manifestFile, 'utf8')) : undefined;
84
+ const owned = previous?.name === name && Array.isArray(previous.assets);
85
+ const sameVersion = owned && previous.version === version && previous.scope === scope && previous.entryPrefix === 'i3-';
86
+ if (owned && previous.scope === scope && Array.isArray(previous.agents)) {
87
+ const applicable = previous.agents.filter(id => {
88
+ const agent = registry.agents.find(item => item.id === id);
89
+ if (!agent || (scope === 'global' && !agent.globalSkillsDir)) return false;
90
+ const directory = scope === 'project' ? path.resolve(projectDir, agent.projectSkillsDir) : globalSkillsDir(agent, home, env);
91
+ return destination(directory) === target.skillsDirectory;
92
+ });
93
+ target.agents = [...new Set([...applicable, ...target.agents])];
94
+ }
74
95
  const start = assets.length;
75
96
  addDirectory('skills', target.skillsDirectory, 'skill');
76
97
  addDirectory('references', target.referencesDirectory, 'reference');
@@ -81,48 +102,59 @@ function planInstallation({ agents, scope, projectDir = process.cwd(), home = os
81
102
  if (exists(docs) && fs.lstatSync(docs).isSymbolicLink()) throw new Error(`Installation directory is a symlink: ${docs}.`);
82
103
  assets.push({ source: path.join(root, 'docs/agents.md'), destination: destination(path.join(target.base, 'docs/agents.md')), kind: 'documentation' });
83
104
  }
84
- assets.push({ source: path.join(root, 'LICENSE'), destination: destination(path.join(target.base, `${name}-LICENSE`)), kind: 'attribution' });
85
- assets.push({ source: path.join(root, 'NOTICE.md'), destination: destination(path.join(target.base, `${name}-NOTICE.md`)), kind: 'attribution' });
86
- const manifestFile = path.join(target.base, `.${name}.json`);
87
- if (exists(manifestFile)) {
88
- const previous = JSON.parse(fs.readFileSync(manifestFile, 'utf8'));
89
- if (previous.name === name && Array.isArray(previous.assets)) {
90
- const legacy = upstream.skills.map(id => `skills/${id}`);
91
- if (target.commandsDirectory) legacy.push(...upstream.commands.map(id => `commands/${id}.md`));
92
- for (const relative of legacy) {
93
- const file = destination(path.join(target.base, relative));
94
- if (previous.assets.includes(relative) && exists(file)) assets.push({ destination: file, kind: 'legacy' });
95
- }
105
+ const licenseDirectory = path.join(target.referencesDirectory, name);
106
+ if (exists(licenseDirectory) && fs.lstatSync(licenseDirectory).isSymbolicLink()) throw new Error(`Installation directory is a symlink: ${licenseDirectory}.`);
107
+ assets.push({ source: path.join(root, 'LICENSE'), destination: destination(path.join(licenseDirectory, 'LICENSE')), kind: 'attribution' });
108
+ if (owned) {
109
+ const legacy = fs.readdirSync(path.join(root, 'skills')).filter(id => id.startsWith('i3-')).map(id => `skills/${id.slice(3)}`);
110
+ if (target.commandsDirectory) legacy.push(...fs.readdirSync(path.join(root, '.claude/commands')).filter(file => file.startsWith('i3-') && file.endsWith('.md')).map(file => `commands/${file.slice(3)}`));
111
+ legacy.push(`${name}-LICENSE`, `${name}-NOTICE.md`);
112
+ for (const relative of legacy) {
113
+ const file = destination(path.join(target.base, relative));
114
+ if (previous.assets.includes(relative) && exists(file)) assets.push({ destination: file, kind: 'legacy' });
96
115
  }
97
116
  }
98
- assets.push({ target, destination: destination(manifestFile), kind: 'manifest' });
117
+ assets.push({ target, destination: destination(manifestFile), kind: 'manifest', mergeable: sameVersion });
99
118
  for (const asset of assets.slice(start)) {
100
119
  asset.base = target.base;
101
- asset.codebuddyCommand = asset.kind === 'command' && target.agents.includes('codebuddy');
120
+ asset.buddyCommand = asset.kind === 'command' && target.agents.some(id => ['codebuddy', 'workbuddy'].includes(id));
121
+ asset.scope = scope;
122
+ asset.personasDirectory = target.personasDirectory;
123
+ if (sameVersion && previous.assets.includes(path.relative(target.base, asset.destination)) && asset.source && exists(asset.destination)) {
124
+ asset.expectedFingerprint = fingerprint(asset.source, asset);
125
+ asset.reusable = fingerprint(asset.destination) === asset.expectedFingerprint;
126
+ }
102
127
  }
103
128
  }
104
129
  for (const asset of assets) { checkDestination(asset.destination); asset.existing = exists(asset.destination); }
105
- return { mode: 'install', scope, agents, targets: [...targets.values()], assets, conflicts: assets.filter(asset => asset.existing).map(asset => asset.destination) };
130
+ const plan = { mode: 'install', scope, agents, targets: [...targets.values()], assets };
131
+ for (const asset of assets.filter(item => item.kind === 'manifest' && item.mergeable)) {
132
+ asset.observedFingerprint = fingerprint(asset.destination);
133
+ asset.reusable = fs.readFileSync(asset.destination, 'utf8') === manifestContent(plan, asset);
134
+ if (asset.reusable) asset.expectedFingerprint = asset.observedFingerprint;
135
+ }
136
+ plan.conflicts = assets.filter(asset => asset.existing && !asset.reusable && !asset.mergeable).map(asset => asset.destination);
137
+ plan.reused = assets.filter(asset => asset.reusable).map(asset => asset.destination);
138
+ return plan;
106
139
  }
107
140
  function executeInstallation(plan, { force = false } = {}) {
108
- if (plan.conflicts.length && !force) throw new Error('Existing installation assets require confirmation or --force; previous files will be backed up.');
109
- const pkg = require('../package.json');
141
+ if (plan.conflicts.length && !force) throw new Error('Existing installation assets require confirmation or --force before replacement.');
110
142
  const contexts = new Map();
111
143
  const createdDirectories = [];
112
144
  const committed = [];
145
+ let completed = false;
146
+ let rolledBack = false;
113
147
  function mkdir(directory) {
114
148
  if (exists(directory)) return;
115
149
  mkdir(path.dirname(directory));
116
150
  fs.mkdirSync(directory);
117
151
  createdDirectories.push(directory);
118
152
  }
119
- function portable(file, markdown = false, codebuddyCommand = false) {
153
+ function portable(file, asset, markdown = false) {
120
154
  if (fs.statSync(file).isDirectory()) {
121
- for (const entry of fs.readdirSync(file)) portable(path.join(file, entry), false, codebuddyCommand);
155
+ for (const entry of fs.readdirSync(file)) portable(path.join(file, entry), asset);
122
156
  } else if (markdown || file.endsWith('.md')) {
123
- let content = fs.readFileSync(file, 'utf8').replaceAll('i3-composer-agent:', '').replaceAll('agent-skills:', '');
124
- if (codebuddyCommand) content = content.replaceAll('.claude/agents/', '.codebuddy/agents/');
125
- fs.writeFileSync(file, content);
157
+ fs.writeFileSync(file, nativeContent(fs.readFileSync(file, 'utf8'), asset));
126
158
  }
127
159
  }
128
160
  try {
@@ -136,20 +168,28 @@ function executeInstallation(plan, { force = false } = {}) {
136
168
  if (asset.kind === 'legacy') continue;
137
169
  asset.staged = path.join(context.staging, String(index));
138
170
  if (asset.kind === 'manifest') {
139
- fs.writeFileSync(asset.staged, JSON.stringify({ name, version: pkg.version, entryPrefix: 'i3-', upstreamVersion: pkg.i3ComposerAgent.upstreamVersion, upstreamCommit: pkg.i3ComposerAgent.upstreamCommit, scope: plan.scope, agents: asset.target.agents, assets: plan.assets.filter(item => item.base === asset.base && item.kind !== 'legacy').map(item => path.relative(asset.base, item.destination)) }, null, 2) + '\n');
171
+ fs.writeFileSync(asset.staged, manifestContent(plan, asset));
140
172
  } else {
141
173
  fs.cpSync(asset.source, asset.staged, { recursive: true, filter: file => {
142
174
  if (fs.lstatSync(file).isSymbolicLink()) throw new Error(`Package contains a symlink: ${file}`);
143
175
  return path.basename(file) !== '.DS_Store';
144
176
  } });
145
- portable(asset.staged, asset.source.endsWith('.md'), asset.codebuddyCommand);
177
+ portable(asset.staged, asset, asset.source.endsWith('.md'));
146
178
  }
147
179
  }
148
180
  for (const asset of plan.assets) {
149
181
  const context = contexts.get(asset.base);
150
182
  mkdir(path.dirname(asset.destination));
183
+ if (asset.reusable) {
184
+ const unchanged = fingerprint(asset.destination) === asset.expectedFingerprint
185
+ && fingerprint(asset.staged) === asset.expectedFingerprint;
186
+ if (unchanged) continue;
187
+ if (!force) throw new Error(`Destination changed during installation: ${asset.destination}. Retry with confirmed replacement.`);
188
+ } else if (asset.mergeable) {
189
+ if (fingerprint(asset.destination) !== asset.observedFingerprint && !force) throw new Error(`Manifest changed during installation: ${asset.destination}. Retry with confirmed replacement.`);
190
+ }
151
191
  // A destination may have appeared since planning; never replace it implicitly.
152
- if (exists(asset.destination) && !force) throw new Error(`Destination appeared during installation: ${asset.destination}. Retry with confirmed replacement.`);
192
+ if (exists(asset.destination) && !force && !asset.mergeable) throw new Error(`Destination appeared during installation: ${asset.destination}. Retry with confirmed replacement.`);
153
193
  const change = { destination: asset.destination, written: false };
154
194
  if (exists(asset.destination)) {
155
195
  change.backup = path.join(context.backup, path.relative(asset.base, asset.destination));
@@ -162,15 +202,21 @@ function executeInstallation(plan, { force = false } = {}) {
162
202
  change.written = true;
163
203
  }
164
204
  }
165
- return [...contexts.values()].map(context => context.backup).filter(exists);
205
+ completed = true;
206
+ return [];
166
207
  } catch (error) {
167
208
  for (const change of committed.reverse()) {
168
209
  if (change.written) fs.rmSync(change.destination, { recursive: true, force: true });
169
210
  if (change.backup) fs.renameSync(change.backup, change.destination);
170
211
  }
212
+ rolledBack = true;
171
213
  throw error;
172
214
  } finally {
173
215
  for (const context of contexts.values()) fs.rmSync(context.staging, { recursive: true, force: true });
216
+ for (const [base, context] of contexts) {
217
+ if (completed) cleanupBackups(base, `.${name}-backup-`);
218
+ else if (rolledBack) fs.rmSync(context.backup, { recursive: true, force: true });
219
+ }
174
220
  for (const directory of createdDirectories.reverse()) {
175
221
  try { fs.rmdirSync(directory); }
176
222
  catch (error) { if (!['ENOENT', 'ENOTEMPTY', 'EEXIST'].includes(error.code)) throw error; }
@@ -0,0 +1,29 @@
1
+ 'use strict';
2
+
3
+ // Project commands are identical for both Buddy clients, including when the
4
+ // other client is added later. Global commands use the selected profile path.
5
+ function nativeContent(content, asset) {
6
+ content = content.replaceAll('i3-composer-agent:', '').replaceAll('agent-skills:', '');
7
+ if (!asset.buddyCommand) return content;
8
+ const projectPersonas = '.codebuddy/agents/';
9
+ const userPersonas = asset.scope === 'project'
10
+ ? "the current host's user-level agents directory"
11
+ : `\`${asset.personasDirectory.replaceAll('\\', '/')}/\``;
12
+ content = content.replaceAll('CLAUDE.md', 'CODEBUDDY.md')
13
+ .replaceAll('`~/.claude/agents/`', userPersonas)
14
+ .replaceAll('.claude/agents/', projectPersonas);
15
+ if (!asset.source.endsWith('i3-ship.md')) return content;
16
+ return content
17
+ .replace('Spawn three subagents concurrently using the Agent tool. **Issue all three Agent tool calls in a single assistant turn so they execute in parallel** — sequential calls defeat the purpose of this command.',
18
+ 'Use the host\'s native subagent capability to run three specialist personas concurrently. Issue all three calls together when the host supports parallel execution.')
19
+ .replace("In Claude Code, each call passes `subagent_type` matching the persona's `name` field:",
20
+ 'Select the following persona names using the host\'s native subagent mechanism:')
21
+ .replace('In other harnesses without an Agent tool, invoke each persona\'s system prompt sequentially and treat their outputs as if returned in parallel — the merge phase still works.',
22
+ 'If native subagents are unavailable, read each persona prompt from the installed agents directory, perform the three reviews sequentially, and retain the same merge phase.')
23
+ .replace(/Constraints \(from Claude Code's subagent model\):\n[\s\S]*?\n\n\*\*Persona resolution\.\*\*[^\n]*/,
24
+ `Constraints:\n- Each specialist reviews independently and returns a report to this session.\n- Specialists do not delegate to one another.\n- Follow the host's execution and permission limits.\n\n**Persona resolution.** Read installed persona prompts from \`${asset.scope === 'project' ? projectPersonas : asset.personasDirectory.replaceAll('\\', '/') + '/'}\`. For project installations, check ${userPersonas} for the current host's user-defined personas, and follow its native precedence rules.`)
25
+ .replace('The three Phase A personas run in parallel — never sequentially.',
26
+ 'Run the three Phase A personas in parallel when native subagents are available; otherwise use the sequential fallback above.');
27
+ }
28
+
29
+ module.exports = { nativeContent };
package/bin/wizard.cjs CHANGED
@@ -56,7 +56,8 @@ async function confirm(plan) {
56
56
  console.log(` ${target.agents.join(', ')}: ${target.skillsDirectory}`);
57
57
  if (target.commandsDirectory) console.log(` Commands: ${target.commandsDirectory}`);
58
58
  }
59
- if (plan.conflicts.length) console.log(`${plan.conflicts.length} existing assets will be preserved in backups before replacement.`);
59
+ if (plan.conflicts.length) console.log(`${plan.conflicts.length} existing assets will be replaced. Previous files are removed after successful installation.`);
60
+ if (plan.reused.length) console.log(`${plan.reused.length} unchanged assets from the same version will be reused.`);
60
61
  console.log('Includes all skills and shared references. Plugin hooks require native plugin registration.');
61
62
  return session(async ask => {
62
63
  const answer = await ask('Install these files? [y/N]: ');
@@ -45,7 +45,7 @@ agy plugin list
45
45
 
46
46
  ## Lifecycle Workflows and Command Compatibility
47
47
 
48
- Antigravity's [migration tooling](https://www.agy.dev/docs/cli/gcli-migration/) reports the 9 legacy definitions in `commands/*.toml` as "converted to skills." In affected `agy` 1.1.x releases, validation succeeds but the converted wrappers do not appear in the slash-command or skill catalog. A successful `agy plugin validate` therefore confirms the files are well formed, not that `/i3-build` and the other short wrappers are available. This is tracked in [upstream agent-skills #445](https://github.com/addyosmani/agent-skills/issues/445) and upstream in [antigravity-cli #788](https://github.com/google-antigravity/antigravity-cli/issues/788).
48
+ Antigravity's [migration tooling](https://www.agy.dev/docs/cli/gcli-migration/) reports the 9 legacy definitions in `commands/*.toml` as "converted to skills." In affected `agy` 1.1.x releases, validation succeeds but the converted wrappers do not appear in the slash-command or skill catalog. A successful `agy plugin validate` therefore confirms the files are well formed, not that `/i3-build` and the other short wrappers are available. This is tracked in [antigravity-cli #788](https://github.com/google-antigravity/antigravity-cli/issues/788).
49
49
 
50
50
  Use the native plugin skills directly while that importer limitation applies:
51
51