@givolt/i3-composer-agent 0.6.12 → 1.0.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 +3 -2
- package/.claude-plugin/marketplace.json +2 -1
- package/.claude-plugin/plugin.json +3 -1
- package/.codex-plugin/plugin.json +3 -1
- package/CHANGELOG.md +34 -0
- package/NOTICE.md +6 -1
- package/README.md +116 -138
- package/bin/agent-targets.json +726 -0
- package/bin/i3-composer-agent.cjs +89 -18
- package/bin/install.cjs +164 -0
- package/bin/skills-registry.LICENSE +21 -0
- package/bin/wizard.cjs +66 -0
- package/docs/antigravity-setup.md +1 -1
- package/docs/codebuddy-setup.md +55 -8
- package/docs/codex-setup.md +13 -2
- package/docs/comparison.md +1 -1
- package/hooks/sdd-cache-post.sh +0 -0
- package/hooks/sdd-cache-pre.sh +0 -0
- package/package.json +75 -17
- package/plugin.json +4 -2
- package/rebrand/INSTALLATION-SPEC.md +46 -0
- package/rebrand/MAINTENANCE.md +93 -31
- package/rebrand/NOTICE.md +14 -0
- package/rebrand/PR-WORKFLOW.md +34 -0
- package/rebrand/UNIFICATION-SPEC.md +33 -0
- package/rebrand/VALIDATION.md +32 -0
- package/rebrand/VERSIONING.md +33 -0
- package/rebrand/apply.cjs +80 -7
- package/rebrand/brand.json +6 -2
- package/rebrand/catalog.cjs +56 -0
- package/rebrand/fork-patches.json +12 -0
- package/rebrand/overlay/.github/workflows/test-plugin-install.yml +177 -0
- package/rebrand/overlay/CHANGELOG.md +34 -0
- package/rebrand/overlay/bin/agent-targets.json +726 -0
- package/rebrand/overlay/bin/i3-composer-agent.cjs +190 -0
- package/rebrand/overlay/bin/install.cjs +164 -0
- package/rebrand/overlay/bin/skills-registry.LICENSE +21 -0
- package/rebrand/overlay/bin/wizard.cjs +66 -0
- package/rebrand/overlay/scripts/validate-brand.cjs +44 -0
- package/rebrand/overlay/tests/bundle.test.cjs +85 -0
- package/rebrand/overlay/tests/installer.test.cjs +193 -0
- package/rebrand/package.template.json +82 -0
- package/rebrand/rebrand.sh +4 -0
- package/rebrand/record-upstream.cjs +37 -0
- package/rebrand/templates/README.md +83 -137
- package/rebrand/templates/codebuddy-setup.md +55 -8
- package/rebrand/templates/codex-setup.md +14 -3
- package/rebrand/tests/pipeline.test.cjs +185 -0
- package/rebrand/upstream.json +171 -0
- package/scripts/validate-brand.cjs +11 -3
- package/skills/idea-refine/scripts/idea-refine.sh +0 -0
- package/tests/bundle.test.cjs +11 -5
- package/tests/installer.test.cjs +193 -0
|
@@ -1,12 +1,60 @@
|
|
|
1
1
|
# Using i3 Composer Agent with CodeBuddy
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
## Desktop IDE installation
|
|
4
|
+
|
|
5
|
+
Run inside your business project:
|
|
4
6
|
|
|
5
7
|
```bash
|
|
6
8
|
npx @givolt/i3-composer-agent --codebuddy
|
|
7
9
|
```
|
|
8
10
|
|
|
9
|
-
|
|
11
|
+
The terminal wizard preselects CodeBuddy, still allows multiple tools, and asks
|
|
12
|
+
for project or global scope before installing. Project scope writes these paths:
|
|
13
|
+
|
|
14
|
+
- `.codebuddy/skills/` — all {{SKILL_COUNT}} skills with their original IDs.
|
|
15
|
+
- `.codebuddy/references/` — shared checklists used by skill-relative links.
|
|
16
|
+
- `.codebuddy/commands/` — all {{COMMAND_COUNT}} existing lifecycle workflows.
|
|
17
|
+
- `.codebuddy/agents/` — all {{PERSONA_COUNT}} persona definitions.
|
|
18
|
+
|
|
19
|
+
Global scope uses the same layout under `~/.codebuddy/`. Existing assets require
|
|
20
|
+
confirmed replacement and are preserved in backup directories. Settings are
|
|
21
|
+
not replaced. Reload the CodeBuddy window or start a new chat, then inspect
|
|
22
|
+
the Skills list and type `/` to inspect the command menu.
|
|
23
|
+
|
|
24
|
+
```text
|
|
25
|
+
/spec
|
|
26
|
+
/plan
|
|
27
|
+
/build
|
|
28
|
+
/build auto
|
|
29
|
+
/review
|
|
30
|
+
/ship
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
The command wrappers reference installed skill IDs without the plugin namespace.
|
|
34
|
+
Their workflow content and approval gates are retained. File installation does
|
|
35
|
+
not itself prove that the IDE has discovered or executed every workflow.
|
|
36
|
+
|
|
37
|
+
For multiple tools or a noninteractive installation:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npx @givolt/i3-composer-agent --agents codebuddy,codex --scope project --yes
|
|
41
|
+
npx @givolt/i3-composer-agent --codebuddy --scope global --yes
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
CodeBuddy documents [IDE skills](https://www.codebuddy.cn/docs/ide/Features/Skills)
|
|
45
|
+
and [IDE custom commands](https://www.codebuddy.cn/docs/ide/User-guide/Slash-Commands).
|
|
46
|
+
The directory layout follows its [configuration directory reference](https://www.codebuddy.cn/docs/cli/codebuddy-dir).
|
|
47
|
+
|
|
48
|
+
## CodeBuddy Code native plugin registration
|
|
49
|
+
|
|
50
|
+
For the terminal CodeBuddy Code plugin manager, explicitly prepare the full
|
|
51
|
+
plugin instead of native skill installation:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
npx @givolt/i3-composer-agent --prepare --codebuddy
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
In CodeBuddy Code, register the prepared directory and install the plugin:
|
|
10
58
|
|
|
11
59
|
```text
|
|
12
60
|
/plugin marketplace add ./i3-composer-agent
|
|
@@ -14,10 +62,10 @@ In the CodeBuddy chat, register the prepared directory and install the plugin:
|
|
|
14
62
|
```
|
|
15
63
|
|
|
16
64
|
Use the absolute directory printed by the CLI if CodeBuddy has a different
|
|
17
|
-
working directory. Choose the intended installation scope in CodeBuddy's native
|
|
65
|
+
working directory. Choose the intended installation scope in CodeBuddy Code's native
|
|
18
66
|
plugin manager. Reload plugins or start a new session after installation.
|
|
19
67
|
|
|
20
|
-
CodeBuddy supports the existing `.claude-plugin/plugin.json` compatibility
|
|
68
|
+
CodeBuddy Code supports the existing `.claude-plugin/plugin.json` compatibility
|
|
21
69
|
manifest. It declares `.claude/commands/` and `commands/`, preserving the nine
|
|
22
70
|
original lifecycle commands and their workflow content.
|
|
23
71
|
|
|
@@ -33,9 +81,8 @@ original lifecycle commands and their workflow content.
|
|
|
33
81
|
Skill IDs, persona names, artifact paths, and workflow gates retain their
|
|
34
82
|
upstream behavior. The plugin namespace changes to `i3-composer-agent`.
|
|
35
83
|
|
|
36
|
-
The
|
|
37
|
-
|
|
38
|
-
wrappers or persona definitions.
|
|
84
|
+
The prepared plugin includes all skills, personas, commands, hooks and shared
|
|
85
|
+
`references/`. Native skill installation above does not enable plugin hooks.
|
|
39
86
|
|
|
40
|
-
|
|
87
|
+
In this explicit mode the CLI prepares files and prints registration commands. Actual host discovery
|
|
41
88
|
and model execution should be verified after registering the plugin.
|
|
@@ -1,12 +1,23 @@
|
|
|
1
1
|
# Using i3 Composer Agent with Codex
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
For the multi-tool native skill wizard, run in your project:
|
|
4
4
|
|
|
5
5
|
```bash
|
|
6
6
|
npx @givolt/i3-composer-agent --codex
|
|
7
7
|
```
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
Choose project or global scope. Native installation uses `.agents/skills/`
|
|
10
|
+
or `~/.agents/skills/`, plus the sibling `references/` directory. It retains
|
|
11
|
+
the {{SKILL_COUNT}} original skill IDs. This mode does not add short lifecycle
|
|
12
|
+
slash commands or enable plugin hooks.
|
|
13
|
+
|
|
14
|
+
For complete plugin registration, prepare a persistent bundle explicitly:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npx @givolt/i3-composer-agent --prepare --codex
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
This mode copies a persistent `./i3-composer-agent/` bundle and prints these
|
|
10
21
|
native registration commands. Run them to enable the plugin:
|
|
11
22
|
|
|
12
23
|
```bash
|
|
@@ -14,7 +25,7 @@ codex plugin marketplace add ./i3-composer-agent
|
|
|
14
25
|
codex plugin add i3-composer-agent@i3-composer-agent
|
|
15
26
|
```
|
|
16
27
|
|
|
17
|
-
Start a new Codex session after registration. All
|
|
28
|
+
Start a new Codex session after registration. All {{SKILL_COUNT}} existing skills keep their
|
|
18
29
|
original IDs. In CLI/IDE, use `/skills` or `$spec-driven-development`; in chat,
|
|
19
30
|
explicitly request the relevant skill from i3 Composer Agent.
|
|
20
31
|
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const test = require('node:test');
|
|
4
|
+
const assert = require('node:assert/strict');
|
|
5
|
+
const fs = require('node:fs');
|
|
6
|
+
const os = require('node:os');
|
|
7
|
+
const path = require('node:path');
|
|
8
|
+
const { spawnSync } = require('node:child_process');
|
|
9
|
+
const root = path.resolve(__dirname, '../..');
|
|
10
|
+
const baselineVersion = require('../upstream.json').upstreamVersion;
|
|
11
|
+
|
|
12
|
+
function run(directory, executable, args) {
|
|
13
|
+
return spawnSync(executable, args, { cwd: directory, encoding: 'utf8' });
|
|
14
|
+
}
|
|
15
|
+
function git(directory, args) {
|
|
16
|
+
const result = run(directory, 'git', args);
|
|
17
|
+
assert.equal(result.status, 0, result.stderr);
|
|
18
|
+
return result.stdout.trim();
|
|
19
|
+
}
|
|
20
|
+
function node(directory, file, args = []) { return run(directory, process.execPath, [file, ...args]); }
|
|
21
|
+
function fixture(t, branch = 'release/test-candidate') {
|
|
22
|
+
const directory = fs.mkdtempSync(path.join(os.tmpdir(), 'i3-agent-replay-'));
|
|
23
|
+
t.after(() => fs.rmSync(directory, { recursive: true, force: true }));
|
|
24
|
+
for (const name of ['skills', 'references', 'agents', 'commands', '.claude', '.gemini', '.claude-plugin', '.codex-plugin', '.agents', 'hooks', 'docs', 'scripts', 'evals', 'rebrand', 'LICENSE', 'plugin.json', 'README.md']) {
|
|
25
|
+
fs.cpSync(path.join(root, name), path.join(directory, name), { recursive: true, filter: file => !file.includes(`${path.sep}results${path.sep}`) });
|
|
26
|
+
}
|
|
27
|
+
// Model an upstream source checkout, including when this suite runs in a packed branded bundle.
|
|
28
|
+
for (const name of ['plugin.json', '.claude-plugin/plugin.json', '.codex-plugin/plugin.json']) {
|
|
29
|
+
const file = path.join(directory, name);
|
|
30
|
+
const data = JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
31
|
+
data.name = 'agent-skills';
|
|
32
|
+
data.version = baselineVersion;
|
|
33
|
+
fs.writeFileSync(file, JSON.stringify(data, null, 2) + '\n');
|
|
34
|
+
}
|
|
35
|
+
git(directory, ['init', '--initial-branch', branch]);
|
|
36
|
+
git(directory, ['config', 'user.name', 'Pipeline Test']);
|
|
37
|
+
git(directory, ['config', 'user.email', 'pipeline@example.test']);
|
|
38
|
+
git(directory, ['add', '.']);
|
|
39
|
+
git(directory, ['commit', '-m', 'upstream fixture']);
|
|
40
|
+
return directory;
|
|
41
|
+
}
|
|
42
|
+
function record(directory) {
|
|
43
|
+
const result = node(directory, 'rebrand/record-upstream.cjs', ['HEAD']);
|
|
44
|
+
assert.equal(result.status, 0, result.stderr);
|
|
45
|
+
}
|
|
46
|
+
function apply(directory) {
|
|
47
|
+
const result = node(directory, 'rebrand/apply.cjs', ['--apply']);
|
|
48
|
+
assert.equal(result.status, 0, result.stderr);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
test('a source checkout generates a complete, repeatable branded distribution', t => {
|
|
52
|
+
const directory = fixture(t);
|
|
53
|
+
record(directory);
|
|
54
|
+
apply(directory);
|
|
55
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(directory, 'package.json'), 'utf8'));
|
|
56
|
+
assert.equal(pkg.name, '@givolt/i3-composer-agent');
|
|
57
|
+
const brand = JSON.parse(fs.readFileSync(path.join(directory, 'rebrand/brand.json'), 'utf8'));
|
|
58
|
+
assert.equal(pkg.version, brand.releaseVersion);
|
|
59
|
+
assert.equal(fs.existsSync(path.join(directory, 'bin/i3-composer-agent.cjs')), true);
|
|
60
|
+
assert.equal(node(directory, 'scripts/validate-brand.cjs').status, 0);
|
|
61
|
+
const check = node(directory, 'rebrand/apply.cjs', ['--check']);
|
|
62
|
+
assert.equal(check.status, 0, check.stdout + check.stderr);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
test('brand fixes advance independently while preserving upstream provenance', t => {
|
|
66
|
+
const directory = fixture(t);
|
|
67
|
+
record(directory);
|
|
68
|
+
const upstreamFile = path.join(directory, 'rebrand/upstream.json');
|
|
69
|
+
const originalUpstream = fs.readFileSync(upstreamFile, 'utf8');
|
|
70
|
+
const upstream = JSON.parse(originalUpstream);
|
|
71
|
+
const brandFile = path.join(directory, 'rebrand/brand.json');
|
|
72
|
+
const brand = JSON.parse(fs.readFileSync(brandFile, 'utf8'));
|
|
73
|
+
const releaseVersion = `${Number(upstream.upstreamVersion.split('.')[0]) + 1}.0.1`;
|
|
74
|
+
brand.releaseVersion = releaseVersion;
|
|
75
|
+
fs.writeFileSync(brandFile, JSON.stringify(brand, null, 2) + '\n');
|
|
76
|
+
apply(directory);
|
|
77
|
+
const packageFile = path.join(directory, 'package.json');
|
|
78
|
+
const originalPackage = fs.readFileSync(packageFile, 'utf8');
|
|
79
|
+
const pkg = JSON.parse(originalPackage);
|
|
80
|
+
assert.equal(pkg.version, releaseVersion);
|
|
81
|
+
assert.equal(pkg.i3ComposerAgent.upstreamVersion, upstream.upstreamVersion);
|
|
82
|
+
assert.equal(pkg.i3ComposerAgent.upstreamCommit, upstream.upstreamCommit);
|
|
83
|
+
assert.equal(fs.readFileSync(upstreamFile, 'utf8'), originalUpstream);
|
|
84
|
+
const releaseLabel = `i3 Composer Agent v${releaseVersion}`;
|
|
85
|
+
const upstreamLabel = `Based on agent-skills v${upstream.upstreamVersion}`;
|
|
86
|
+
for (const output of [fs.readFileSync(path.join(directory, 'README.md'), 'utf8'), node(directory, 'bin/i3-composer-agent.cjs', ['--help']).stdout]) {
|
|
87
|
+
assert.ok(output.includes(releaseLabel), output);
|
|
88
|
+
assert.ok(output.includes(upstreamLabel), output);
|
|
89
|
+
}
|
|
90
|
+
assert.equal(node(directory, 'bin/i3-composer-agent.cjs', ['--version']).stdout.trim(), releaseVersion);
|
|
91
|
+
const dryRun = node(directory, 'bin/i3-composer-agent.cjs', ['--extract', '--dry-run', '--dir', directory + '-prepared']);
|
|
92
|
+
assert.equal(dryRun.status, 0, dryRun.stderr);
|
|
93
|
+
assert.equal(JSON.parse(dryRun.stdout).upstreamVersion, upstream.upstreamVersion);
|
|
94
|
+
assert.equal(node(directory, 'scripts/validate-brand.cjs').status, 0);
|
|
95
|
+
pkg.i3ComposerAgent.upstreamVersion = releaseVersion;
|
|
96
|
+
fs.writeFileSync(packageFile, JSON.stringify(pkg));
|
|
97
|
+
assert.notEqual(node(directory, 'scripts/validate-brand.cjs').status, 0);
|
|
98
|
+
fs.writeFileSync(packageFile, originalPackage);
|
|
99
|
+
assert.equal(node(directory, 'rebrand/apply.cjs', ['--check']).status, 0);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
test('writing a brand transform on the protected source branch changes nothing', t => {
|
|
103
|
+
const directory = fixture(t, 'agent/source');
|
|
104
|
+
const before = fs.readFileSync(path.join(directory, 'plugin.json'));
|
|
105
|
+
const result = node(directory, 'rebrand/apply.cjs', ['--apply']);
|
|
106
|
+
assert.notEqual(result.status, 0);
|
|
107
|
+
assert.match(result.stderr, /source branch/i);
|
|
108
|
+
assert.deepEqual(fs.readFileSync(path.join(directory, 'plugin.json')), before);
|
|
109
|
+
assert.equal(fs.existsSync(path.join(directory, 'package.json')), false);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
test('a reviewed upstream catalog can grow without losing its new skill or command', t => {
|
|
113
|
+
const directory = fixture(t);
|
|
114
|
+
const skill = path.join(directory, 'skills/upstream-new-skill');
|
|
115
|
+
fs.mkdirSync(skill);
|
|
116
|
+
fs.writeFileSync(path.join(skill, 'SKILL.md'), '---\nname: upstream-new-skill\ndescription: New upstream capability.\n---\n# Upstream capability\n');
|
|
117
|
+
fs.writeFileSync(path.join(directory, '.claude/commands/upstream-new-command.md'), '---\ndescription: Invoke the new upstream capability.\n---\nUse agent-skills:upstream-new-skill.\n');
|
|
118
|
+
git(directory, ['add', 'skills', '.claude/commands']);
|
|
119
|
+
git(directory, ['commit', '-m', 'new upstream capability']);
|
|
120
|
+
record(directory);
|
|
121
|
+
apply(directory);
|
|
122
|
+
const result = node(directory, 'scripts/validate-brand.cjs');
|
|
123
|
+
assert.equal(result.status, 0, result.stderr);
|
|
124
|
+
const description = JSON.parse(fs.readFileSync(path.join(directory, '.codex-plugin/plugin.json'), 'utf8')).interface.longDescription;
|
|
125
|
+
assert.match(description, /26 engineering skills/);
|
|
126
|
+
const readme = fs.readFileSync(path.join(directory, 'README.md'), 'utf8');
|
|
127
|
+
assert.match(readme, /upstream-new-skill/);
|
|
128
|
+
assert.match(readme, /upstream-new-command/);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
test('missing files and altered skill identifiers fail preservation validation', t => {
|
|
132
|
+
const directory = fixture(t);
|
|
133
|
+
record(directory);
|
|
134
|
+
apply(directory);
|
|
135
|
+
const file = path.join(directory, 'skills/using-agent-skills/SKILL.md');
|
|
136
|
+
const original = fs.readFileSync(file, 'utf8');
|
|
137
|
+
fs.writeFileSync(file, original.replace('name: using-agent-skills', 'name: renamed-meta-skill'));
|
|
138
|
+
assert.notEqual(node(directory, 'scripts/validate-brand.cjs').status, 0);
|
|
139
|
+
fs.writeFileSync(file, original);
|
|
140
|
+
fs.rmSync(file);
|
|
141
|
+
assert.notEqual(node(directory, 'scripts/validate-brand.cjs').status, 0);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
test('checkout line endings do not masquerade as an upstream skill change', t => {
|
|
145
|
+
const directory = fixture(t);
|
|
146
|
+
record(directory);
|
|
147
|
+
const file = path.join(directory, 'skills/using-agent-skills/SKILL.md');
|
|
148
|
+
fs.writeFileSync(file, fs.readFileSync(file, 'utf8').replace(/\r?\n/g, '\r\n'));
|
|
149
|
+
const script = path.join(directory, 'scripts/validate-versions.js');
|
|
150
|
+
fs.writeFileSync(script, fs.readFileSync(script, 'utf8').replace(/\r?\n/g, '\r\n'));
|
|
151
|
+
apply(directory);
|
|
152
|
+
assert.equal(node(directory, 'scripts/validate-brand.cjs').status, 0);
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
test('a new upstream package manifest requires an explicit distribution adaptation', t => {
|
|
156
|
+
const directory = fixture(t);
|
|
157
|
+
record(directory);
|
|
158
|
+
fs.writeFileSync(path.join(directory, 'package.json'), '{"name":"agent-skills","dependencies":{"upstream-runtime":"1.0.0"}}\n');
|
|
159
|
+
const before = fs.readFileSync(path.join(directory, 'plugin.json'));
|
|
160
|
+
const result = node(directory, 'rebrand/apply.cjs', ['--apply']);
|
|
161
|
+
assert.notEqual(result.status, 0);
|
|
162
|
+
assert.match(result.stderr, /package\.json/);
|
|
163
|
+
assert.deepEqual(fs.readFileSync(path.join(directory, 'plugin.json')), before);
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
test('a distribution without repository CI files remains unchanged by a replay check', t => {
|
|
167
|
+
const directory = fixture(t);
|
|
168
|
+
record(directory);
|
|
169
|
+
apply(directory);
|
|
170
|
+
fs.rmSync(path.join(directory, '.github'), { recursive: true, force: true });
|
|
171
|
+
const result = node(directory, 'rebrand/apply.cjs', ['--check']);
|
|
172
|
+
assert.equal(result.status, 0, result.stdout + result.stderr);
|
|
173
|
+
assert.equal(fs.existsSync(path.join(directory, '.github')), false);
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
test('Finder metadata does not masquerade as an upstream runtime file', t => {
|
|
177
|
+
const directory = fixture(t);
|
|
178
|
+
record(directory);
|
|
179
|
+
fs.writeFileSync(path.join(directory, 'skills/.DS_Store'), 'Finder metadata');
|
|
180
|
+
fs.writeFileSync(path.join(directory, 'skills/spec-driven-development/.DS_Store'), 'Finder metadata');
|
|
181
|
+
apply(directory);
|
|
182
|
+
assert.equal(node(directory, 'scripts/validate-brand.cjs').status, 0);
|
|
183
|
+
const result = node(directory, 'rebrand/apply.cjs', ['--check']);
|
|
184
|
+
assert.equal(result.status, 0, result.stdout + result.stderr);
|
|
185
|
+
});
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
{
|
|
2
|
+
"upstreamCommit": "1401c8b8030e023baeebb31781a6653fe8e93026",
|
|
3
|
+
"upstreamVersion": "0.6.12",
|
|
4
|
+
"skills": [
|
|
5
|
+
"api-and-interface-design",
|
|
6
|
+
"browser-testing-with-devtools",
|
|
7
|
+
"ci-cd-and-automation",
|
|
8
|
+
"code-review-and-quality",
|
|
9
|
+
"code-simplification",
|
|
10
|
+
"constraint-driven-development",
|
|
11
|
+
"context-engineering",
|
|
12
|
+
"debugging-and-error-recovery",
|
|
13
|
+
"deprecation-and-migration",
|
|
14
|
+
"documentation-and-adrs",
|
|
15
|
+
"doubt-driven-development",
|
|
16
|
+
"frontend-ui-engineering",
|
|
17
|
+
"git-workflow-and-versioning",
|
|
18
|
+
"idea-refine",
|
|
19
|
+
"incremental-implementation",
|
|
20
|
+
"interview-me",
|
|
21
|
+
"observability-and-instrumentation",
|
|
22
|
+
"performance-optimization",
|
|
23
|
+
"planning-and-task-breakdown",
|
|
24
|
+
"security-and-hardening",
|
|
25
|
+
"shipping-and-launch",
|
|
26
|
+
"source-driven-development",
|
|
27
|
+
"spec-driven-development",
|
|
28
|
+
"test-driven-development",
|
|
29
|
+
"using-agent-skills"
|
|
30
|
+
],
|
|
31
|
+
"commands": [
|
|
32
|
+
"build",
|
|
33
|
+
"code-simplify",
|
|
34
|
+
"constraints",
|
|
35
|
+
"plan",
|
|
36
|
+
"review",
|
|
37
|
+
"ship",
|
|
38
|
+
"spec",
|
|
39
|
+
"test",
|
|
40
|
+
"webperf"
|
|
41
|
+
],
|
|
42
|
+
"personas": [
|
|
43
|
+
"code-reviewer",
|
|
44
|
+
"security-auditor",
|
|
45
|
+
"test-engineer",
|
|
46
|
+
"web-performance-auditor"
|
|
47
|
+
],
|
|
48
|
+
"references": [
|
|
49
|
+
"references/accessibility-checklist.md",
|
|
50
|
+
"references/definition-of-done.md",
|
|
51
|
+
"references/observability-checklist.md",
|
|
52
|
+
"references/orchestration-patterns.md",
|
|
53
|
+
"references/performance-checklist.md",
|
|
54
|
+
"references/security-checklist.md",
|
|
55
|
+
"references/testing-patterns.md"
|
|
56
|
+
],
|
|
57
|
+
"runtimeFiles": [
|
|
58
|
+
".agents/plugins/marketplace.json",
|
|
59
|
+
".claude-plugin/marketplace.json",
|
|
60
|
+
".claude-plugin/plugin.json",
|
|
61
|
+
".claude/commands/build.md",
|
|
62
|
+
".claude/commands/code-simplify.md",
|
|
63
|
+
".claude/commands/constraints.md",
|
|
64
|
+
".claude/commands/plan.md",
|
|
65
|
+
".claude/commands/review.md",
|
|
66
|
+
".claude/commands/ship.md",
|
|
67
|
+
".claude/commands/spec.md",
|
|
68
|
+
".claude/commands/test.md",
|
|
69
|
+
".claude/commands/webperf.md",
|
|
70
|
+
".codex-plugin/plugin.json",
|
|
71
|
+
".gemini/commands/build.toml",
|
|
72
|
+
".gemini/commands/code-simplify.toml",
|
|
73
|
+
".gemini/commands/constraints.toml",
|
|
74
|
+
".gemini/commands/planning.toml",
|
|
75
|
+
".gemini/commands/review.toml",
|
|
76
|
+
".gemini/commands/ship.toml",
|
|
77
|
+
".gemini/commands/spec.toml",
|
|
78
|
+
".gemini/commands/test.toml",
|
|
79
|
+
".gemini/commands/webperf.toml",
|
|
80
|
+
"LICENSE",
|
|
81
|
+
"agents/code-reviewer.md",
|
|
82
|
+
"agents/security-auditor.md",
|
|
83
|
+
"agents/test-engineer.md",
|
|
84
|
+
"agents/web-performance-auditor.md",
|
|
85
|
+
"commands/build.toml",
|
|
86
|
+
"commands/code-simplify.toml",
|
|
87
|
+
"commands/constraints.toml",
|
|
88
|
+
"commands/planning.toml",
|
|
89
|
+
"commands/review.toml",
|
|
90
|
+
"commands/ship.toml",
|
|
91
|
+
"commands/spec.toml",
|
|
92
|
+
"commands/test.toml",
|
|
93
|
+
"commands/webperf.toml",
|
|
94
|
+
"hooks/SDD-CACHE.md",
|
|
95
|
+
"hooks/SIMPLIFY-IGNORE.md",
|
|
96
|
+
"hooks/sdd-cache-post.sh",
|
|
97
|
+
"hooks/sdd-cache-pre.sh",
|
|
98
|
+
"hooks/sdd-cache-test.sh",
|
|
99
|
+
"hooks/session-start-test.sh",
|
|
100
|
+
"hooks/session-start.sh",
|
|
101
|
+
"hooks/simplify-ignore-test.sh",
|
|
102
|
+
"hooks/simplify-ignore.sh",
|
|
103
|
+
"plugin.json",
|
|
104
|
+
"references/accessibility-checklist.md",
|
|
105
|
+
"references/definition-of-done.md",
|
|
106
|
+
"references/observability-checklist.md",
|
|
107
|
+
"references/orchestration-patterns.md",
|
|
108
|
+
"references/performance-checklist.md",
|
|
109
|
+
"references/security-checklist.md",
|
|
110
|
+
"references/testing-patterns.md",
|
|
111
|
+
"skills/api-and-interface-design/SKILL.md",
|
|
112
|
+
"skills/browser-testing-with-devtools/SKILL.md",
|
|
113
|
+
"skills/ci-cd-and-automation/SKILL.md",
|
|
114
|
+
"skills/code-review-and-quality/SKILL.md",
|
|
115
|
+
"skills/code-simplification/SKILL.md",
|
|
116
|
+
"skills/constraint-driven-development/SKILL.md",
|
|
117
|
+
"skills/constraint-driven-development/references/floor-guard.md",
|
|
118
|
+
"skills/context-engineering/SKILL.md",
|
|
119
|
+
"skills/debugging-and-error-recovery/SKILL.md",
|
|
120
|
+
"skills/deprecation-and-migration/SKILL.md",
|
|
121
|
+
"skills/documentation-and-adrs/SKILL.md",
|
|
122
|
+
"skills/doubt-driven-development/SKILL.md",
|
|
123
|
+
"skills/frontend-ui-engineering/SKILL.md",
|
|
124
|
+
"skills/git-workflow-and-versioning/SKILL.md",
|
|
125
|
+
"skills/idea-refine/SKILL.md",
|
|
126
|
+
"skills/idea-refine/examples.md",
|
|
127
|
+
"skills/idea-refine/frameworks.md",
|
|
128
|
+
"skills/idea-refine/refinement-criteria.md",
|
|
129
|
+
"skills/idea-refine/scripts/idea-refine.sh",
|
|
130
|
+
"skills/incremental-implementation/SKILL.md",
|
|
131
|
+
"skills/interview-me/SKILL.md",
|
|
132
|
+
"skills/observability-and-instrumentation/SKILL.md",
|
|
133
|
+
"skills/performance-optimization/SKILL.md",
|
|
134
|
+
"skills/performance-optimization/references/optimization-patterns.md",
|
|
135
|
+
"skills/planning-and-task-breakdown/SKILL.md",
|
|
136
|
+
"skills/security-and-hardening/SKILL.md",
|
|
137
|
+
"skills/security-and-hardening/references/hardening-patterns.md",
|
|
138
|
+
"skills/shipping-and-launch/SKILL.md",
|
|
139
|
+
"skills/source-driven-development/SKILL.md",
|
|
140
|
+
"skills/spec-driven-development/SKILL.md",
|
|
141
|
+
"skills/test-driven-development/SKILL.md",
|
|
142
|
+
"skills/using-agent-skills/SKILL.md"
|
|
143
|
+
],
|
|
144
|
+
"skillFrontmatter": {
|
|
145
|
+
"api-and-interface-design": "44f904d462977e9514f439ac7c057b8691613ba8160360ad9d28b830d3a24001",
|
|
146
|
+
"browser-testing-with-devtools": "e235631718d18a0527d00eb718ecece2218bbf205d742632f8197b30c052e96b",
|
|
147
|
+
"ci-cd-and-automation": "dd73253ec445a9af27ebeab74404ee7a770919e40ec9db0b34af4fa9ec36bf7c",
|
|
148
|
+
"code-review-and-quality": "bf3dda5e08190fcf00175a5053f53550bca91ca32b0a06e4b97cd33e046e8eb7",
|
|
149
|
+
"code-simplification": "cee4dc87b4bc95d77fe646d4ab9e66c9a422dd081a833d657d618aaf2967b5a2",
|
|
150
|
+
"constraint-driven-development": "0da347bd34b155ab79cad1e0ee80238f3b4b91b1a17ca0fc2f68460c02224194",
|
|
151
|
+
"context-engineering": "f4f18514e5eeb162ef9f925dea85af2c72ba79f9b157783a06c39c0bde102d3f",
|
|
152
|
+
"debugging-and-error-recovery": "658d96f63d56946214a7ec87be0347c78d6024a18f6481dc9f7310638f403629",
|
|
153
|
+
"deprecation-and-migration": "388d5e7e549f1b728213f0f50d91e9ca96210e0cb23fd9fccd30755268dd01f9",
|
|
154
|
+
"documentation-and-adrs": "6b2a9d19ebbb81570022a89f09b4810eeb0643a48c698989ee27a224f90bc026",
|
|
155
|
+
"doubt-driven-development": "df8954091f08c14b0e91bf3bf330f43d5a8408c1efe697591b7b0e8448251c71",
|
|
156
|
+
"frontend-ui-engineering": "323624fe7ec44bdb4fad3c9488e55993119912625fffa20ee5787389da2b600d",
|
|
157
|
+
"git-workflow-and-versioning": "dd28469b0f294865dbd20d622a9fee5f05ef87ab1599e973fec6d15a16f76e15",
|
|
158
|
+
"idea-refine": "07eedcfcba98c6c8f6985917830c4b3d93d4e17af05a9b2ca1b8cb54226bc1b9",
|
|
159
|
+
"incremental-implementation": "d31e04a0d7b07fc7d01e0176aafbba5607f1cfe7a29a634498305d95c2b3bd3b",
|
|
160
|
+
"interview-me": "62700902b592a4fa28f6f71f2581d4e1dee412ff288eb156ed97fac3db8b4295",
|
|
161
|
+
"observability-and-instrumentation": "652b9724e431bd7cfd4481bbab31bb079eeab2b5f70ebc04cf66743e37028721",
|
|
162
|
+
"performance-optimization": "76befb0806caad12322de8fe372d2e984f6e07c393fd8d3658537c92c7e285cf",
|
|
163
|
+
"planning-and-task-breakdown": "c3bc139dfa7af82e2d11c7cf461bbf923add7d6494d669da98925f77a7671641",
|
|
164
|
+
"security-and-hardening": "981142e38769394e6e7760250f2dd599dff21a370040f3f141c42507f04ea540",
|
|
165
|
+
"shipping-and-launch": "02cc76557e581957cb4987a53e03a8d1aa04c72dc735390d52ae4eed3ddeddf9",
|
|
166
|
+
"source-driven-development": "233bf9f16f5fe0960c988a5feb2efc475b9b24f9e145d960f8c63e44f4f34fde",
|
|
167
|
+
"spec-driven-development": "e21f25e534ffa3e2de9ac08c40f8d1d90cef17ad55702f83301cbc2a297c2dcb",
|
|
168
|
+
"test-driven-development": "38f1489687eaa60761522a8e3efaa926b52786b0e1b3c57947a6050c0da340de",
|
|
169
|
+
"using-agent-skills": "df5d4f61855ac46da3371bad8c05edb8bc9375ba191acc82b0cca257cfec946c"
|
|
170
|
+
}
|
|
171
|
+
}
|
|
@@ -7,8 +7,16 @@ const path = require('node:path');
|
|
|
7
7
|
const root = path.resolve(__dirname, '..');
|
|
8
8
|
const brand = require('../rebrand/brand.json');
|
|
9
9
|
const pkg = require('../package.json');
|
|
10
|
+
const upstream = require('../rebrand/upstream.json');
|
|
11
|
+
const { validateCatalog } = require('../rebrand/catalog.cjs');
|
|
12
|
+
validateCatalog(root, upstream);
|
|
10
13
|
function json(relative) { return JSON.parse(fs.readFileSync(path.join(root, relative), 'utf8')); }
|
|
11
14
|
assert.equal(pkg.name, brand.npmName);
|
|
15
|
+
assert.equal(pkg.version, brand.releaseVersion);
|
|
16
|
+
assert.equal(brand.upstreamCommit, upstream.upstreamCommit);
|
|
17
|
+
assert.equal(pkg.i3ComposerAgent.upstreamVersion, upstream.upstreamVersion);
|
|
18
|
+
assert.equal(pkg.i3ComposerAgent.upstreamCommit, upstream.upstreamCommit);
|
|
19
|
+
assert.equal(pkg.i3ComposerAgent.upstreamRepository, brand.upstream);
|
|
12
20
|
assert.equal(Object.keys(pkg.bin).length, 1, 'npx must resolve one executable');
|
|
13
21
|
assert.ok(fs.existsSync(path.join(root, pkg.bin[brand.name])));
|
|
14
22
|
for (const relative of ['plugin.json', '.claude-plugin/plugin.json', '.codex-plugin/plugin.json']) {
|
|
@@ -22,10 +30,10 @@ for (const relative of ['.claude-plugin/marketplace.json', '.agents/plugins/mark
|
|
|
22
30
|
}
|
|
23
31
|
assert.ok(json('.codex-plugin/plugin.json').interface.shortDescription.length <= 30);
|
|
24
32
|
const skills = fs.readdirSync(path.join(root, 'skills')).filter(name => fs.existsSync(path.join(root, 'skills', name, 'SKILL.md')));
|
|
25
|
-
assert.equal(skills.length,
|
|
33
|
+
assert.equal(skills.length, upstream.skills.length, 'brand conversion must preserve the reviewed upstream skills');
|
|
26
34
|
assert.ok(skills.includes('using-agent-skills'), 'meta-skill ID must remain stable');
|
|
27
35
|
const commands = fs.readdirSync(path.join(root, '.claude/commands')).filter(name => name.endsWith('.md'));
|
|
28
|
-
assert.equal(commands.length,
|
|
36
|
+
assert.equal(commands.length, upstream.commands.length, 'brand conversion must preserve the reviewed upstream commands');
|
|
29
37
|
for (const command of commands) {
|
|
30
38
|
const body = fs.readFileSync(path.join(root, '.claude/commands', command), 'utf8');
|
|
31
39
|
assert.ok(!body.includes('agent-skills:'), `${command}: stale plugin namespace`);
|
|
@@ -33,4 +41,4 @@ for (const command of commands) {
|
|
|
33
41
|
}
|
|
34
42
|
for (const relative of pkg.i3ComposerAgent.pluginFiles) assert.ok(fs.existsSync(path.join(root, relative)), `bundle is missing ${relative}`);
|
|
35
43
|
assert.match(fs.readFileSync(path.join(root, 'LICENSE'), 'utf8'), /Copyright \(c\) 2025 Addy Osmani/);
|
|
36
|
-
console.log('Brand identity, package entrypoint,
|
|
44
|
+
console.log('Brand identity, package entrypoint, reviewed upstream catalog, and attribution are consistent.');
|
|
File without changes
|
package/tests/bundle.test.cjs
CHANGED
|
@@ -7,6 +7,7 @@ const os = require('node:os');
|
|
|
7
7
|
const path = require('node:path');
|
|
8
8
|
const { spawnSync } = require('node:child_process');
|
|
9
9
|
const root = path.resolve(__dirname, '..');
|
|
10
|
+
const upstream = require('../rebrand/upstream.json');
|
|
10
11
|
const cli = path.join(root, 'bin/i3-composer-agent.cjs');
|
|
11
12
|
function run(args) { return spawnSync(process.execPath, [cli, ...args], { encoding: 'utf8' }); }
|
|
12
13
|
function workspace(t) {
|
|
@@ -15,7 +16,10 @@ function workspace(t) {
|
|
|
15
16
|
return directory;
|
|
16
17
|
}
|
|
17
18
|
test('help and version identify the package without preparing files', () => {
|
|
18
|
-
|
|
19
|
+
const help = run(['--help']).stdout;
|
|
20
|
+
assert.match(help, /@givolt\/i3-composer-agent/);
|
|
21
|
+
assert.ok(help.includes(`i3 Composer Agent v${require('../package.json').version}`));
|
|
22
|
+
assert.ok(help.includes(`Based on agent-skills v${upstream.upstreamVersion}`));
|
|
19
23
|
assert.equal(run(['--version']).stdout.trim(), require('../package.json').version);
|
|
20
24
|
});
|
|
21
25
|
test('dry run and invalid arguments leave the target untouched', t => {
|
|
@@ -30,10 +34,12 @@ test('complete bundle preserves reference links and all host assets at a path wi
|
|
|
30
34
|
const target = path.join(workspace(t), 'plugin with spaces');
|
|
31
35
|
const result = run(['--codebuddy', '--dir', target]);
|
|
32
36
|
assert.equal(result.status, 0, result.stderr);
|
|
37
|
+
assert.ok(result.stdout.includes(`i3 Composer Agent v${require('../package.json').version}`));
|
|
38
|
+
assert.ok(result.stdout.includes(`Based on agent-skills v${upstream.upstreamVersion}`));
|
|
33
39
|
assert.match(result.stdout, /\/plugin install i3-composer-agent@i3-composer-agent/);
|
|
34
|
-
assert.equal(fs.readdirSync(path.join(target, 'skills')).length,
|
|
35
|
-
assert.equal(fs.readdirSync(path.join(target, '.claude/commands')).length,
|
|
36
|
-
assert.equal(fs.readdirSync(path.join(target, 'agents')).filter(name => name.endsWith('.md')).length,
|
|
40
|
+
assert.equal(fs.readdirSync(path.join(target, 'skills')).length, upstream.skills.length);
|
|
41
|
+
assert.equal(fs.readdirSync(path.join(target, '.claude/commands')).length, upstream.commands.length);
|
|
42
|
+
assert.equal(fs.readdirSync(path.join(target, 'agents')).filter(name => name.endsWith('.md')).length, upstream.personas.length);
|
|
37
43
|
assert.equal(JSON.parse(fs.readFileSync(path.join(target, '.codex-plugin/plugin.json'), 'utf8')).name, 'i3-composer-agent');
|
|
38
44
|
const check = spawnSync(process.execPath, [path.join(target, 'scripts/validate-reference-links.js')], { cwd: target, encoding: 'utf8' });
|
|
39
45
|
assert.equal(check.status, 0, check.stdout + check.stderr);
|
|
@@ -57,7 +63,7 @@ test('installed packages beneath node_modules remain fully extractable', t => {
|
|
|
57
63
|
const result = spawnSync(process.execPath, [path.join(installed, 'bin/i3-composer-agent.cjs'), '--extract', '--dir', target], { encoding: 'utf8' });
|
|
58
64
|
assert.equal(result.status, 0, result.stderr);
|
|
59
65
|
assert.equal(JSON.parse(fs.readFileSync(path.join(target, 'package.json'), 'utf8')).name, '@givolt/i3-composer-agent');
|
|
60
|
-
assert.equal(fs.readdirSync(path.join(target, 'skills')).length,
|
|
66
|
+
assert.equal(fs.readdirSync(path.join(target, 'skills')).length, upstream.skills.length);
|
|
61
67
|
});
|
|
62
68
|
test('replacement preserves the complete previous bundle in a backup', t => {
|
|
63
69
|
const parent = workspace(t);
|