@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.
Files changed (53) hide show
  1. package/.agents/plugins/marketplace.json +3 -2
  2. package/.claude-plugin/marketplace.json +2 -1
  3. package/.claude-plugin/plugin.json +3 -1
  4. package/.codex-plugin/plugin.json +3 -1
  5. package/CHANGELOG.md +34 -0
  6. package/NOTICE.md +6 -1
  7. package/README.md +116 -138
  8. package/bin/agent-targets.json +726 -0
  9. package/bin/i3-composer-agent.cjs +89 -18
  10. package/bin/install.cjs +164 -0
  11. package/bin/skills-registry.LICENSE +21 -0
  12. package/bin/wizard.cjs +66 -0
  13. package/docs/antigravity-setup.md +1 -1
  14. package/docs/codebuddy-setup.md +55 -8
  15. package/docs/codex-setup.md +13 -2
  16. package/docs/comparison.md +1 -1
  17. package/hooks/sdd-cache-post.sh +0 -0
  18. package/hooks/sdd-cache-pre.sh +0 -0
  19. package/package.json +75 -17
  20. package/plugin.json +4 -2
  21. package/rebrand/INSTALLATION-SPEC.md +46 -0
  22. package/rebrand/MAINTENANCE.md +93 -31
  23. package/rebrand/NOTICE.md +14 -0
  24. package/rebrand/PR-WORKFLOW.md +34 -0
  25. package/rebrand/UNIFICATION-SPEC.md +33 -0
  26. package/rebrand/VALIDATION.md +32 -0
  27. package/rebrand/VERSIONING.md +33 -0
  28. package/rebrand/apply.cjs +80 -7
  29. package/rebrand/brand.json +6 -2
  30. package/rebrand/catalog.cjs +56 -0
  31. package/rebrand/fork-patches.json +12 -0
  32. package/rebrand/overlay/.github/workflows/test-plugin-install.yml +177 -0
  33. package/rebrand/overlay/CHANGELOG.md +34 -0
  34. package/rebrand/overlay/bin/agent-targets.json +726 -0
  35. package/rebrand/overlay/bin/i3-composer-agent.cjs +190 -0
  36. package/rebrand/overlay/bin/install.cjs +164 -0
  37. package/rebrand/overlay/bin/skills-registry.LICENSE +21 -0
  38. package/rebrand/overlay/bin/wizard.cjs +66 -0
  39. package/rebrand/overlay/scripts/validate-brand.cjs +44 -0
  40. package/rebrand/overlay/tests/bundle.test.cjs +85 -0
  41. package/rebrand/overlay/tests/installer.test.cjs +193 -0
  42. package/rebrand/package.template.json +82 -0
  43. package/rebrand/rebrand.sh +4 -0
  44. package/rebrand/record-upstream.cjs +37 -0
  45. package/rebrand/templates/README.md +83 -137
  46. package/rebrand/templates/codebuddy-setup.md +55 -8
  47. package/rebrand/templates/codex-setup.md +14 -3
  48. package/rebrand/tests/pipeline.test.cjs +185 -0
  49. package/rebrand/upstream.json +171 -0
  50. package/scripts/validate-brand.cjs +11 -3
  51. package/skills/idea-refine/scripts/idea-refine.sh +0 -0
  52. package/tests/bundle.test.cjs +11 -5
  53. package/tests/installer.test.cjs +193 -0
@@ -1,12 +1,60 @@
1
1
  # Using i3 Composer Agent with CodeBuddy
2
2
 
3
- Prepare the complete plugin inside the project where you want to use it:
3
+ ## Desktop IDE installation
4
+
5
+ Run inside your business project:
4
6
 
5
7
  ```bash
6
8
  npx @givolt/i3-composer-agent --codebuddy
7
9
  ```
8
10
 
9
- In the CodeBuddy chat, register the prepared directory and install the plugin:
11
+ The terminal wizard preselects CodeBuddy, still allows multiple tools, and asks
12
+ for project or global scope before installing. Project scope writes these paths:
13
+
14
+ - `.codebuddy/skills/` — all {{SKILL_COUNT}} skills with 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 bundle includes all skills and shared `references/`. Installing individual
37
- skills is a different distribution method and does not install the command
38
- wrappers or persona definitions.
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
- The CLI prepares files and prints registration commands. Actual host discovery
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
- Prepare the complete plugin inside the project where you want to use it:
3
+ For the multi-tool native skill wizard, run in your project:
4
4
 
5
5
  ```bash
6
6
  npx @givolt/i3-composer-agent --codex
7
7
  ```
8
8
 
9
- The CLI copies a persistent `./i3-composer-agent/` bundle and prints these
9
+ Choose project or global scope. Native installation uses `.agents/skills/`
10
+ or `~/.agents/skills/`, plus the sibling `references/` directory. It 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 25 existing skills keep their
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, 25, 'brand conversion must preserve the 25-skill collection');
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, 9, 'brand conversion must preserve the nine commands');
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, 25 skills, nine commands, and upstream attribution are consistent.');
44
+ console.log('Brand identity, package entrypoint, reviewed upstream catalog, and attribution are consistent.');
File without changes
@@ -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
- assert.match(run(['--help']).stdout, /@givolt\/i3-composer-agent/);
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, 25);
35
- assert.equal(fs.readdirSync(path.join(target, '.claude/commands')).length, 9);
36
- assert.equal(fs.readdirSync(path.join(target, 'agents')).filter(name => name.endsWith('.md')).length, 4);
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, 25);
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);