@givolt/i3-composer-agent 2.0.0 → 2.1.1
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.
- package/.agents/plugins/marketplace.json +1 -1
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/README.md +37 -33
- package/bin/agent-targets.json +11 -0
- package/bin/asset-fingerprint.cjs +38 -0
- package/bin/cleanup-backups.cjs +16 -0
- package/bin/i3-composer-agent.cjs +28 -12
- package/bin/install.cjs +74 -28
- package/bin/native-content.cjs +29 -0
- package/bin/wizard.cjs +3 -1
- package/docs/antigravity-setup.md +1 -1
- package/docs/codebuddy-setup.md +16 -3
- package/docs/cursor-setup.md +2 -2
- package/docs/getting-started.md +0 -2
- package/docs/opencode-setup.md +4 -4
- package/docs/workbuddy-setup.md +106 -0
- package/package.json +36 -20
- package/plugin.json +1 -1
- package/CHANGELOG.md +0 -51
- package/NOTICE.md +0 -15
- package/docs/advanced-per-agent-configuration.md +0 -70
- package/docs/comparison.md +0 -131
- package/docs/developer-onboarding.md +0 -116
- package/docs/skill-anatomy.md +0 -203
- package/evals/README.md +0 -101
- package/evals/cases/i3-api-and-interface-design.json +0 -45
- package/evals/cases/i3-browser-testing-with-devtools.json +0 -44
- package/evals/cases/i3-ci-cd-and-automation.json +0 -45
- package/evals/cases/i3-code-review-and-quality.json +0 -49
- package/evals/cases/i3-code-simplification.json +0 -45
- package/evals/cases/i3-constraint-driven-development.json +0 -79
- package/evals/cases/i3-context-engineering.json +0 -44
- package/evals/cases/i3-debugging-and-error-recovery.json +0 -58
- package/evals/cases/i3-deprecation-and-migration.json +0 -52
- package/evals/cases/i3-documentation-and-adrs.json +0 -44
- package/evals/cases/i3-doubt-driven-development.json +0 -43
- package/evals/cases/i3-frontend-ui-engineering.json +0 -52
- package/evals/cases/i3-git-workflow-and-versioning.json +0 -47
- package/evals/cases/i3-idea-refine.json +0 -43
- package/evals/cases/i3-incremental-implementation.json +0 -57
- package/evals/cases/i3-interview-me.json +0 -42
- package/evals/cases/i3-observability-and-instrumentation.json +0 -44
- package/evals/cases/i3-performance-optimization.json +0 -53
- package/evals/cases/i3-planning-and-task-breakdown.json +0 -45
- package/evals/cases/i3-security-and-hardening.json +0 -53
- package/evals/cases/i3-shipping-and-launch.json +0 -56
- package/evals/cases/i3-source-driven-development.json +0 -44
- package/evals/cases/i3-spec-driven-development.json +0 -72
- package/evals/cases/i3-test-driven-development.json +0 -73
- package/evals/cases/i3-using-agent-skills.json +0 -44
- package/evals/fixtures/i3-api-and-interface-design/service-brief.md +0 -19
- package/evals/fixtures/i3-browser-testing-with-devtools/README.md +0 -5
- package/evals/fixtures/i3-browser-testing-with-devtools/index.html +0 -24
- package/evals/fixtures/i3-browser-testing-with-devtools/server.js +0 -15
- package/evals/fixtures/i3-ci-cd-and-automation/package.json +0 -8
- package/evals/fixtures/i3-ci-cd-and-automation/src/slug.js +0 -3
- package/evals/fixtures/i3-ci-cd-and-automation/test/slug.test.js +0 -9
- package/evals/fixtures/i3-code-review-and-quality/user-search.diff +0 -16
- package/evals/fixtures/i3-code-simplification/config-parser.js +0 -46
- package/evals/fixtures/i3-code-simplification/config-parser.test.js +0 -15
- package/evals/fixtures/i3-context-engineering/context-audit.md +0 -15
- package/evals/fixtures/i3-debugging-and-error-recovery/pagination.js +0 -8
- package/evals/fixtures/i3-debugging-and-error-recovery/pagination.test.js +0 -9
- package/evals/fixtures/i3-debugging-and-error-recovery/time-pressure.md +0 -6
- package/evals/fixtures/i3-deprecation-and-migration/api-inventory.md +0 -9
- package/evals/fixtures/i3-documentation-and-adrs/decision-context.md +0 -16
- package/evals/fixtures/i3-doubt-driven-development/migration-plan.md +0 -19
- package/evals/fixtures/i3-frontend-ui-engineering/Button.tsx +0 -7
- package/evals/fixtures/i3-frontend-ui-engineering/design-system.md +0 -11
- package/evals/fixtures/i3-git-workflow-and-versioning/.eval/working-tree.patch +0 -21
- package/evals/fixtures/i3-git-workflow-and-versioning/app.js +0 -7
- package/evals/fixtures/i3-git-workflow-and-versioning/app.test.js +0 -9
- package/evals/fixtures/i3-incremental-implementation/reports.js +0 -7
- package/evals/fixtures/i3-incremental-implementation/reports.test.js +0 -12
- package/evals/fixtures/i3-incremental-implementation/tasks/plan.md +0 -8
- package/evals/fixtures/i3-observability-and-instrumentation/operations.md +0 -11
- package/evals/fixtures/i3-observability-and-instrumentation/payment-retry.js +0 -14
- package/evals/fixtures/i3-performance-optimization/benchmark.js +0 -15
- package/evals/fixtures/i3-performance-optimization/products.js +0 -14
- package/evals/fixtures/i3-planning-and-task-breakdown/notifications-spec.md +0 -18
- package/evals/fixtures/i3-security-and-hardening/webhook.js +0 -11
- package/evals/fixtures/i3-security-and-hardening/webhook.test.js +0 -13
- package/evals/fixtures/i3-shipping-and-launch/authority-pressure.md +0 -6
- package/evals/fixtures/i3-shipping-and-launch/launch-status.md +0 -11
- package/evals/fixtures/i3-source-driven-development/framework-task.md +0 -10
- package/evals/fixtures/i3-spec-driven-development/billing-brief.md +0 -16
- package/evals/fixtures/i3-test-driven-development/BUG.md +0 -10
- package/evals/fixtures/i3-test-driven-development/README.md +0 -28
- package/evals/fixtures/i3-test-driven-development/package.json +0 -9
- package/evals/fixtures/i3-test-driven-development/src/split.js +0 -8
- package/evals/fixtures/i3-test-driven-development/test/split.test.js +0 -13
- package/evals/fixtures/i3-using-agent-skills/incident.md +0 -6
- package/evals/fixtures/incremental-implementation-pressure/draft-export.js +0 -17
- package/evals/fixtures/incremental-implementation-pressure/scenario.md +0 -9
- package/evals/fixtures/spec-driven-development-decomposition/portal-brief.md +0 -22
- package/evals/fixtures/test-driven-development-ecosystem/README.md +0 -9
- package/evals/fixtures/test-driven-development-ecosystem/ledger.py +0 -15
- package/evals/fixtures/test-driven-development-ecosystem/test_ledger.py +0 -19
- package/evals/plugin/code-review-fires/graders/off-by-one.md +0 -7
- package/evals/plugin/code-review-fires/graders/severity-labels.md +0 -4
- package/evals/plugin/code-review-fires/graders/skill-fired.md +0 -5
- package/evals/plugin/code-review-fires/prompt.md +0 -31
- package/evals/plugin/code-review-stays-quiet/graders/not-fired.md +0 -8
- package/evals/plugin/code-review-stays-quiet/graders/tdd-fired.md +0 -6
- package/evals/plugin/code-review-stays-quiet/prompt.md +0 -8
- package/evals/plugin/code-review-stays-quiet-on-commit-message/graders/not-fired.md +0 -8
- package/evals/plugin/code-review-stays-quiet-on-commit-message/prompt.md +0 -25
- package/evals/skill-impact.md +0 -6
- package/rebrand/INSTALLATION-SPEC.md +0 -47
- package/rebrand/MAINTENANCE.md +0 -114
- package/rebrand/NOTICE.md +0 -15
- package/rebrand/PR-WORKFLOW.md +0 -34
- package/rebrand/PREFIX-SPEC.md +0 -16
- package/rebrand/UNIFICATION-SPEC.md +0 -33
- package/rebrand/VALIDATION.md +0 -32
- package/rebrand/VERSIONING.md +0 -35
- package/rebrand/apply.cjs +0 -217
- package/rebrand/brand.json +0 -13
- package/rebrand/catalog.cjs +0 -70
- package/rebrand/fork-patches.json +0 -27
- package/rebrand/identifiers.cjs +0 -41
- package/rebrand/overlay/.github/workflows/test-plugin-install.yml +0 -177
- package/rebrand/overlay/CHANGELOG.md +0 -51
- package/rebrand/overlay/bin/agent-targets.json +0 -726
- package/rebrand/overlay/bin/i3-composer-agent.cjs +0 -190
- package/rebrand/overlay/bin/install.cjs +0 -180
- package/rebrand/overlay/bin/skills-registry.LICENSE +0 -21
- package/rebrand/overlay/bin/wizard.cjs +0 -66
- package/rebrand/overlay/scripts/validate-brand.cjs +0 -44
- package/rebrand/overlay/tests/bundle.test.cjs +0 -85
- package/rebrand/overlay/tests/installer.test.cjs +0 -241
- package/rebrand/package.template.json +0 -82
- package/rebrand/rebrand.sh +0 -4
- package/rebrand/record-upstream.cjs +0 -37
- package/rebrand/templates/README.md +0 -130
- package/rebrand/templates/codebuddy-setup.md +0 -89
- package/rebrand/templates/codex-setup.md +0 -45
- package/rebrand/tests/pipeline.test.cjs +0 -253
- package/rebrand/upstream.json +0 -171
- package/scripts/floor-guard-reference-test.js +0 -291
- package/scripts/lib/skill-lint-test.js +0 -650
- package/scripts/lib/skill-lint.js +0 -586
- package/scripts/run-evals-test.js +0 -623
- package/scripts/run-evals.js +0 -638
- package/scripts/validate-artifact-paths-test.js +0 -179
- package/scripts/validate-artifact-paths.js +0 -130
- package/scripts/validate-brand.cjs +0 -44
- package/scripts/validate-commands-test.js +0 -216
- package/scripts/validate-commands.js +0 -223
- package/scripts/validate-reference-links-test.js +0 -495
- package/scripts/validate-reference-links.js +0 -187
- package/scripts/validate-skills.js +0 -69
- package/scripts/validate-versions-test.js +0 -32
- package/scripts/validate-versions.js +0 -35
- package/tests/bundle.test.cjs +0 -85
- package/tests/installer.test.cjs +0 -241
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"plugins": [
|
|
9
9
|
{
|
|
10
10
|
"name": "i3-composer-agent",
|
|
11
|
-
"version": "2.
|
|
11
|
+
"version": "2.1.1",
|
|
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",
|
package/README.md
CHANGED
|
@@ -1,13 +1,7 @@
|
|
|
1
|
-
# i3 Composer Agent v2.
|
|
2
|
-
|
|
3
|
-
**Based on agent-skills v0.6.12**
|
|
1
|
+
# i3 Composer Agent v2.1.1
|
|
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,60 @@ 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
|
+
# WorkBuddy desktop: use global scope for Skills discovery:
|
|
17
|
+
npx @givolt/i3-composer-agent --workbuddy --scope global
|
|
22
18
|
```
|
|
23
19
|
|
|
24
20
|
The interactive terminal wizard offers multiple tools, project or global scope,
|
|
25
|
-
an installation summary, and confirmation.
|
|
26
|
-
|
|
21
|
+
an installation summary, and confirmation. It offers 80 directory
|
|
22
|
+
presets: the pinned [Vercel Skills CLI registry](https://github.com/vercel-labs/skills/blob/48dc9e8eb8aa19040e91cb90ba0b642c9cbad57e/src/agents.ts)
|
|
23
|
+
plus a native WorkBuddy preset.
|
|
27
24
|
Choose by tool ID or comma-separated menu numbers. Use `--list-agents` to list
|
|
28
25
|
the choices. Directory presets are not an execution test of every host.
|
|
29
26
|
|
|
30
27
|
Every selected tool receives all 25 skills and shared references.
|
|
31
|
-
CodeBuddy and Claude Code also receive 9 short command workflows
|
|
32
|
-
and 4
|
|
28
|
+
CodeBuddy, WorkBuddy and Claude Code also receive 9 short command workflows
|
|
29
|
+
and 4 Agent role definitions. Other tools use their native skill support;
|
|
33
30
|
short lifecycle commands depend on the host. Shared destinations are installed
|
|
34
|
-
once.
|
|
31
|
+
once. A standard MIT license accompanies the shared references.
|
|
35
32
|
Reload the IDE window or start a new session after installation. See
|
|
36
|
-
[CodeBuddy setup](docs/codebuddy-setup.md)
|
|
33
|
+
[CodeBuddy setup](docs/codebuddy-setup.md), [WorkBuddy setup](docs/workbuddy-setup.md)
|
|
34
|
+
and [Codex setup](docs/codex-setup.md).
|
|
37
35
|
|
|
38
36
|
For an explicit installation without prompts:
|
|
39
37
|
|
|
40
38
|
```bash
|
|
41
39
|
npx @givolt/i3-composer-agent --agents codebuddy,codex --scope project --yes
|
|
40
|
+
npx @givolt/i3-composer-agent --workbuddy --scope global --yes
|
|
41
|
+
npx @givolt/i3-composer-agent --agents codebuddy,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
|
-
|
|
47
|
-
|
|
48
|
-
|
|
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
|
+
**WorkBuddy desktop: global installation is recommended.** In WorkBuddy 5.7.7,
|
|
51
|
+
project Commands are discoverable, but the desktop Skills list scans
|
|
52
|
+
`.workbuddy/skills/` rather than the shared `.codebuddy/skills/` destination.
|
|
53
|
+
Use `--workbuddy --scope global` for Skills list and input completion.
|
|
54
|
+
For both clients, you can install CodeBuddy at project scope and WorkBuddy at
|
|
55
|
+
global scope, or install both globally. See [WorkBuddy setup](docs/workbuddy-setup.md).
|
|
56
|
+
|
|
57
|
+
Unchanged manifest-owned assets from the same version and scope are reused;
|
|
58
|
+
adding a client merges its ID into the shared installation manifest. Modified
|
|
59
|
+
files, unowned collisions and version upgrades require confirmation; use
|
|
60
|
+
`--force` with noninteractive installs after reviewing the dry run.
|
|
61
|
+
After successful installation, replaced files and installer-owned historical
|
|
62
|
+
backups are removed. A failed installation restores the previous files.
|
|
49
63
|
`npx -y` accepts npm's package download prompt; the package's own `--yes` flag
|
|
50
64
|
accepts the explicit installation plan.
|
|
51
65
|
|
|
52
66
|
Earlier native installations migrate their unprefixed Skill and command paths
|
|
53
67
|
when those paths belong to this package's previous installation manifest.
|
|
54
|
-
The migration
|
|
55
|
-
|
|
68
|
+
The migration removes owned legacy paths after successful installation. Use
|
|
69
|
+
`/i3-spec` in CodeBuddy or WorkBuddy, or `$i3-spec-driven-development`
|
|
56
70
|
in Codex after upgrading.
|
|
57
71
|
|
|
58
72
|
## Prepare the complete plugin
|
|
@@ -90,7 +104,7 @@ is maintained separately.
|
|
|
90
104
|
|
|
91
105
|
## Commands
|
|
92
106
|
|
|
93
|
-
Native CodeBuddy and Claude Code installations use short filenames such as
|
|
107
|
+
Native CodeBuddy, WorkBuddy and Claude Code installations use short filenames such as
|
|
94
108
|
`/i3-spec`, `/i3-plan`, `/i3-build` and `/i3-ship`. Hosts supporting Claude-compatible plugin
|
|
95
109
|
commands load the same workflows under the plugin namespace:
|
|
96
110
|
|
|
@@ -106,7 +120,8 @@ commands load the same workflows under the plugin namespace:
|
|
|
106
120
|
| /i3-composer-agent:i3-test | Run TDD workflow — write failing tests, implement, verify. For bugs, use the Prove-It pattern. |
|
|
107
121
|
| /i3-composer-agent:i3-webperf | Run a web performance audit via the web-performance-auditor persona |
|
|
108
122
|
|
|
109
|
-
`/i3-
|
|
123
|
+
`/i3-build auto` runs the existing approved-plan workflow in native installations;
|
|
124
|
+
plugin installations use `/i3-composer-agent:i3-build auto`.
|
|
110
125
|
|
|
111
126
|
## Skills
|
|
112
127
|
|
|
@@ -146,17 +161,6 @@ npx @givolt/i3-composer-agent --codebuddy --dir /path/to/plugin --dry-run
|
|
|
146
161
|
npx @givolt/i3-composer-agent --codebuddy --dir /path/to/plugin --force
|
|
147
162
|
```
|
|
148
163
|
|
|
149
|
-
Explicit `--dir` retains the
|
|
150
|
-
|
|
164
|
+
Explicit `--dir` retains the plugin preparation behavior. Successful replacement
|
|
165
|
+
removes the previous bundle and this plugin's historical backups. Repository-scoped
|
|
151
166
|
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).
|
package/bin/agent-targets.json
CHANGED
|
@@ -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}
|
|
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 --scope global
|
|
22
|
+
npx ${pkg.name} --agents codebuddy,workbuddy --scope global --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 (global scope recommended)
|
|
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,13 @@ 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
|
|
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
|
|
45
|
+
CodeBuddy, WorkBuddy and Claude Code also receive short commands and Agent roles.
|
|
46
|
+
WorkBuddy desktop: use global scope for Skills list and input completion.
|
|
42
47
|
Other tools receive skills and references; command availability is host-specific.
|
|
43
48
|
Use --prepare for complete plugins, including hooks and host registration.
|
|
44
49
|
`;
|
|
@@ -63,6 +68,7 @@ function prepare() {
|
|
|
63
68
|
for (let i = 0; i < args.length; i++) {
|
|
64
69
|
const arg = args[i];
|
|
65
70
|
if (arg === '--prepare') continue;
|
|
71
|
+
if (arg === '--workbuddy') throw new Error('For native WorkBuddy installation, use --workbuddy --scope project|global --yes without --prepare or --dir.');
|
|
66
72
|
if (['--codebuddy', '--codex', '--claude', '--extract'].includes(arg)) {
|
|
67
73
|
if (host) throw new Error('Choose exactly one host flag or --extract.');
|
|
68
74
|
host = arg.slice(2);
|
|
@@ -87,12 +93,13 @@ function prepare() {
|
|
|
87
93
|
if (manifest.name !== name) throw new Error('Refusing to replace a directory belonging to another plugin.');
|
|
88
94
|
}
|
|
89
95
|
if (dryRun) {
|
|
90
|
-
console.log(JSON.stringify({ name, version: pkg.version,
|
|
96
|
+
console.log(JSON.stringify({ name, version: pkg.version, directory, host, files: pkg.i3ComposerAgent.pluginFiles, replacesExisting: exists }, null, 2));
|
|
91
97
|
return;
|
|
92
98
|
}
|
|
93
99
|
fs.mkdirSync(path.dirname(directory), { recursive: true });
|
|
94
100
|
const staging = fs.mkdtempSync(path.join(path.dirname(directory), `.${name}-`));
|
|
95
101
|
let backup;
|
|
102
|
+
let completed = false;
|
|
96
103
|
try {
|
|
97
104
|
for (const relative of pkg.i3ComposerAgent.pluginFiles) {
|
|
98
105
|
const source = path.join(root, relative);
|
|
@@ -113,10 +120,18 @@ function prepare() {
|
|
|
113
120
|
}
|
|
114
121
|
try { fs.renameSync(staging, directory); }
|
|
115
122
|
catch (error) { if (backup) fs.renameSync(backup, directory); throw error; }
|
|
116
|
-
|
|
123
|
+
completed = true;
|
|
124
|
+
} finally {
|
|
125
|
+
if (fs.existsSync(staging)) fs.rmSync(staging, { recursive: true, force: true });
|
|
126
|
+
if (completed) cleanupBackups(path.dirname(directory), `${path.basename(directory)}.backup-`, previous => {
|
|
127
|
+
const manifest = path.join(previous, 'plugin.json');
|
|
128
|
+
try {
|
|
129
|
+
return !fs.lstatSync(manifest).isSymbolicLink() && JSON.parse(fs.readFileSync(manifest, 'utf8')).name === name;
|
|
130
|
+
} catch { return false; }
|
|
131
|
+
});
|
|
132
|
+
}
|
|
117
133
|
console.log(identity);
|
|
118
134
|
console.log(`Prepared ${name} at ${directory}`);
|
|
119
|
-
if (backup) console.log(`Previous bundle preserved at ${backup}`);
|
|
120
135
|
if (host === 'extract') return;
|
|
121
136
|
console.log('\nRegister and enable the plugin with these native commands:');
|
|
122
137
|
const selector = `${name}@${name}`;
|
|
@@ -142,7 +157,7 @@ async function main() {
|
|
|
142
157
|
const options = { agents: [], projectDir: process.cwd() };
|
|
143
158
|
for (let i = 0; i < args.length; i++) {
|
|
144
159
|
const arg = args[i];
|
|
145
|
-
if (['--codebuddy', '--codex', '--claude'].includes(arg)) options.agents.push(arg.slice(2));
|
|
160
|
+
if (['--codebuddy', '--workbuddy', '--codex', '--claude'].includes(arg)) options.agents.push(arg.slice(2));
|
|
146
161
|
else if (['--agents', '--scope', '--project-dir'].includes(arg)) {
|
|
147
162
|
if (!args[i + 1] || args[i + 1].startsWith('--')) throw new Error(`${arg} requires a value.`);
|
|
148
163
|
const value = args[++i];
|
|
@@ -168,7 +183,7 @@ async function main() {
|
|
|
168
183
|
}
|
|
169
184
|
const plan = installer.planInstallation(options);
|
|
170
185
|
if (options.dryRun) {
|
|
171
|
-
console.log(JSON.stringify({ name, version: pkg.version,
|
|
186
|
+
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
187
|
return;
|
|
173
188
|
}
|
|
174
189
|
if (!options.yes) {
|
|
@@ -176,15 +191,16 @@ async function main() {
|
|
|
176
191
|
if (!confirmed) { console.log('Installation cancelled. No files changed.'); return; }
|
|
177
192
|
options.force = plan.conflicts.length > 0;
|
|
178
193
|
}
|
|
179
|
-
|
|
194
|
+
installer.executeInstallation(plan, { force: options.force });
|
|
180
195
|
console.log(identity);
|
|
196
|
+
if (plan.reused.length) console.log(`Reused ${plan.reused.length} unchanged assets from the same package version.`);
|
|
181
197
|
for (const target of plan.targets) {
|
|
182
198
|
console.log(`Installed ${target.agents.join(', ')} skills at ${target.skillsDirectory}`);
|
|
183
199
|
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
200
|
}
|
|
185
|
-
for (const backup of backups) console.log(`Previous assets preserved at ${backup}`);
|
|
186
201
|
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.
|
|
202
|
+
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.');
|
|
203
|
+
console.log('Native skill installation does not enable plugin hooks.');
|
|
204
|
+
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
205
|
}
|
|
190
206
|
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
|
|
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
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
if (
|
|
88
|
-
const
|
|
89
|
-
if (
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
|
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,
|
|
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),
|
|
155
|
+
for (const entry of fs.readdirSync(file)) portable(path.join(file, entry), asset);
|
|
122
156
|
} else if (markdown || file.endsWith('.md')) {
|
|
123
|
-
|
|
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,
|
|
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')
|
|
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
|
-
|
|
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
|
@@ -39,6 +39,7 @@ async function choose(options, identity) {
|
|
|
39
39
|
if (!agents.length) { agents = undefined; console.log('Choose at least one tool.'); }
|
|
40
40
|
} catch (error) { console.log(error.message); }
|
|
41
41
|
}
|
|
42
|
+
if (agents.includes('workbuddy')) console.log('WorkBuddy desktop: global installation is recommended for Skills list and input completion. Project Skills may be absent from the Skills list.');
|
|
42
43
|
let scope = options.scope;
|
|
43
44
|
while (!scope) {
|
|
44
45
|
const input = await ask('Installation scope: 1. Project (current project), 2. Global (all projects) [1] (q cancels): ');
|
|
@@ -56,7 +57,8 @@ async function confirm(plan) {
|
|
|
56
57
|
console.log(` ${target.agents.join(', ')}: ${target.skillsDirectory}`);
|
|
57
58
|
if (target.commandsDirectory) console.log(` Commands: ${target.commandsDirectory}`);
|
|
58
59
|
}
|
|
59
|
-
if (plan.conflicts.length) console.log(`${plan.conflicts.length} existing assets will be
|
|
60
|
+
if (plan.conflicts.length) console.log(`${plan.conflicts.length} existing assets will be replaced. Previous files are removed after successful installation.`);
|
|
61
|
+
if (plan.reused.length) console.log(`${plan.reused.length} unchanged assets from the same version will be reused.`);
|
|
60
62
|
console.log('Includes all skills and shared references. Plugin hooks require native plugin registration.');
|
|
61
63
|
return session(async ask => {
|
|
62
64
|
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 [
|
|
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
|
|