@laitszkin/apollo-toolkit 3.1.0 → 3.1.2

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/CHANGELOG.md CHANGED
@@ -7,6 +7,18 @@ All notable changes to this repository are documented in this file.
7
7
  ### Changed
8
8
  - None yet.
9
9
 
10
+ ## [v3.1.2] - 2026-04-23
11
+
12
+ ### Changed
13
+ - Tighten `commit-and-push` so emitted UI git directives such as `::git-stage`, `::git-commit`, and `::git-push` never count as evidence that staging, commit creation, or remote push actually happened.
14
+ - Tighten `version-release` so release flows require real git mutations for staging, commit/tag creation, and push verification instead of treating UI git directives as proof that the release commit or tag exists.
15
+
16
+ ## [v3.1.1] - 2026-04-22
17
+
18
+ ### Changed
19
+ - Fix Apollo Toolkit installers so `codex`-only skills stay scoped to Codex targets, while shared skills continue to install across the selected destinations.
20
+ - Align the CLI welcome/help text, non-interactive guidance, and README examples with the supported `agents` target and current installer behavior.
21
+
10
22
  ## [v3.1.0] - 2026-04-22
11
23
 
12
24
  ### Added
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Apollo Toolkit Skills
2
2
 
3
- A curated skill catalog for Codex, OpenClaw, Trae, and Claude Code with a managed installer that keeps the toolkit in `~/.apollo-toolkit` and copies each skill into the targets you choose.
3
+ A curated skill catalog for Codex, OpenClaw, Trae, Agents, and Claude Code with a managed installer that keeps the toolkit in `~/.apollo-toolkit` and copies each skill into the targets you choose.
4
4
 
5
5
  ## Included skills
6
6
 
@@ -63,7 +63,7 @@ npx @laitszkin/apollo-toolkit
63
63
  The interactive installer:
64
64
  - shows a branded `Apollo Toolkit` terminal welcome screen with a short staged reveal
65
65
  - installs a managed copy into `~/.apollo-toolkit`
66
- - lets you multi-select `codex`, `openclaw`, `trae`, `claude-code`, or `all`
66
+ - lets you multi-select `codex`, `openclaw`, `trae`, `agents`, `claude-code`, or `all`
67
67
  - copies `~/.apollo-toolkit/<skill>` into each selected target
68
68
  - removes stale previously installed skill directories that existed in the previous installed version but no longer exist in the current package skill list
69
69
  - replaces legacy symlink-based installs created by older Apollo Toolkit installers with real copied directories
@@ -91,6 +91,7 @@ apltk open-github-issue --help
91
91
 
92
92
  ```bash
93
93
  npx @laitszkin/apollo-toolkit codex
94
+ npx @laitszkin/apollo-toolkit agents
94
95
  npx @laitszkin/apollo-toolkit claude-code
95
96
  npx @laitszkin/apollo-toolkit codex openclaw
96
97
  npx @laitszkin/apollo-toolkit all
@@ -103,6 +104,7 @@ APOLLO_TOOLKIT_HOME=~/custom-toolkit npx @laitszkin/apollo-toolkit codex
103
104
  CODEX_SKILLS_DIR=~/custom-codex-skills npx @laitszkin/apollo-toolkit codex
104
105
  OPENCLAW_HOME=~/.openclaw npx @laitszkin/apollo-toolkit openclaw
105
106
  TRAE_SKILLS_DIR=~/.trae/skills npx @laitszkin/apollo-toolkit trae
107
+ AGENTS_SKILLS_DIR=~/.agents/skills npx @laitszkin/apollo-toolkit agents
106
108
  CLAUDE_CODE_SKILLS_DIR=~/.claude/skills npx @laitszkin/apollo-toolkit claude-code
107
109
  ```
108
110
 
@@ -120,12 +122,14 @@ Installers still live in `scripts/` for local repository usage and curl / iwr in
120
122
  ./scripts/install_skills.sh codex
121
123
  ./scripts/install_skills.sh openclaw
122
124
  ./scripts/install_skills.sh trae
125
+ ./scripts/install_skills.sh agents
123
126
  ./scripts/install_skills.sh all
124
127
  ```
125
128
 
126
129
  ```powershell
127
130
  ./scripts/install_skills.ps1
128
131
  ./scripts/install_skills.ps1 codex
132
+ ./scripts/install_skills.ps1 agents
129
133
  ./scripts/install_skills.ps1 all
130
134
  ```
131
135
 
@@ -15,7 +15,7 @@ description: "Guide the agent to submit local changes with commit and push only
15
15
  ## Standards
16
16
 
17
17
  - Evidence: Inspect git state and classify the change set before deciding which quality gates apply, then compare the actual pending diff against root `CHANGELOG.md` `Unreleased` before committing, while also distinguishing the staged surface from additional unstaged work before deciding commit scope.
18
- - Execution: Run the required quality-gate skills when applicable, and treat every conditional gate whose scenario is met as blocking before submission; hand the repository to `submission-readiness-check` for readiness classification, invoke `archive-specs` directly whenever completed plan sets should be converted or project docs need alignment, preserve staging intent, honor any explicit user-specified target branch, and when the worktree is already clean inspect local `HEAD`, upstream state, and the most recent relevant commit before deciding the request is a no-op; when worktree-based delivery is involved, verify where the authoritative target branch lives before moving history, re-validate on that target branch after replay or merge, and remove the temporary worktree only after the target branch is safely updated; when the user asks for multiple commits or a narrower staged subset, keep those commit boundaries explicit instead of broadening scope implicitly; then commit and push without release steps; run dependent git mutations sequentially and verify the remote branch actually contains the new local `HEAD` before reporting success.
18
+ - Execution: Run the required quality-gate skills when applicable, and treat every conditional gate whose scenario is met as blocking before submission; hand the repository to `submission-readiness-check` for readiness classification, invoke `archive-specs` directly whenever completed plan sets should be converted or project docs need alignment, preserve staging intent, honor any explicit user-specified target branch, and when the worktree is already clean inspect local `HEAD`, upstream state, and the most recent relevant commit before deciding the request is a no-op; when worktree-based delivery is involved, verify where the authoritative target branch lives before moving history, re-validate on that target branch after replay or merge, and remove the temporary worktree only after the target branch is safely updated; when the user asks for multiple commits or a narrower staged subset, keep those commit boundaries explicit instead of broadening scope implicitly; then commit and push without release steps; run dependent git mutations sequentially and verify the remote branch actually contains the new local `HEAD` before reporting success, and never treat UI directives such as `::git-stage`, `::git-commit`, or `::git-push` as substitutes for actual git commands or as evidence that submission already happened.
19
19
  - Quality: Re-run relevant validation for runtime changes, preserve unrelated local work safely when branch switching or post-push local sync is required, do not bypass blocking readiness findings such as missing/stale `Unreleased` bullets or unsynchronized project docs, and never collapse intentionally separated commit scopes just because related unstaged changes are present.
20
20
  - Output: Produce a concise Conventional Commit, push it to the intended branch, and report any temporary stash/restore, commit-scope separation, or local branch sync that was required.
21
21
 
@@ -71,6 +71,7 @@ Load only when needed:
71
71
  - Preserve user staging intent where possible.
72
72
  - If the user explicitly asks for separate commits, or the staged set is already a deliberate subset of the worktree, keep those scopes separated and do not auto-stage the remaining diff unless the user expands the requested scope.
73
73
  - If the user later broadens the requested scope, restate the new grouping, verify it against the actual staged/unstaged surfaces, and only then create the additional commit(s).
74
+ - Use actual `git add` / `git commit` operations; do not emit UI git directives as a stand-in for repository mutations.
74
75
  - Write a concise Conventional Commit message using `references/commit-messages.md`.
75
76
  7. Push
76
77
  - Push commit(s) to the intended branch.
@@ -79,6 +80,7 @@ Load only when needed:
79
80
  - If the push result is ambiguous, out of order, or the hashes do not match, rerun the missing git step sequentially and re-check before reporting success.
80
81
  - Confirm the local branch state matches the user's requested destination when post-push synchronization was requested.
81
82
  - When the user explicitly asks to merge work back from a temporary worktree and delete that worktree, do the final verification on the authoritative target branch first, then remove the temporary worktree and prune stale worktree records before reporting completion.
83
+ - Do not claim success based on emitted UI directives or optimistic status text alone; remote-hash verification is the required evidence.
82
84
 
83
85
  ## Notes
84
86
 
@@ -88,6 +90,7 @@ Load only when needed:
88
90
  - Never downgrade `discover-edge-cases` or `harden-app-security` to optional follow-up when the change risk says they apply.
89
91
  - Never claim the repository is ready to commit while root `CHANGELOG.md` `Unreleased` is missing the current change or still describes superseded work.
90
92
  - Never fabricate a commit/push result when the worktree is already clean; either identify the exact existing commit/upstream state that satisfies the user's request or say that no matching new submission exists.
93
+ - Never treat `::git-stage`, `::git-commit`, `::git-push`, or similar UI helpers as proof that repository history was mutated; rely on actual git command results plus local/remote hash checks.
91
94
  - Never delete a temporary worktree before the target branch has been updated, tested, and verified to contain the intended final content.
92
95
  - Never auto-stage or auto-merge unrelated unstaged changes into a commit when the user or current index state already defines narrower commit boundaries.
93
96
  - If release/version/tag work is requested, use `version-release` instead.
package/lib/cli.js CHANGED
@@ -3,6 +3,7 @@ const fs = require('node:fs');
3
3
  const path = require('node:path');
4
4
 
5
5
  const {
6
+ TARGET_DEFINITIONS,
6
7
  VALID_MODES,
7
8
  installLinks,
8
9
  normalizeModes,
@@ -15,11 +16,7 @@ const { checkForPackageUpdate } = require('./updater');
15
16
 
16
17
  const TARGET_OPTIONS = [
17
18
  { id: 'all', label: 'All', description: 'Install every supported target below' },
18
- { id: 'codex', label: 'Codex', description: '~/.codex/skills' },
19
- { id: 'openclaw', label: 'OpenClaw', description: '~/.openclaw/workspace*/skills' },
20
- { id: 'trae', label: 'Trae', description: '~/.trae/skills' },
21
- { id: 'agents', label: 'Agents', description: '~/.agents/skills' },
22
- { id: 'claude-code', label: 'Claude Code', description: '~/.claude/skills' },
19
+ ...TARGET_DEFINITIONS,
23
20
  ];
24
21
 
25
22
  const WORDMARK_LINES = [
@@ -64,6 +61,22 @@ function buildBanner({ version, colorEnabled }) {
64
61
  ].join('\n');
65
62
  }
66
63
 
64
+ function buildModeUsagePattern() {
65
+ return `${VALID_MODES.join('|')}|all`;
66
+ }
67
+
68
+ function buildInteractiveModeHint() {
69
+ const quotedModes = [...VALID_MODES, 'all'].map((mode) => `\`${mode}\``);
70
+ return `${quotedModes.slice(0, -1).join(', ')}, or ${quotedModes.at(-1)}`;
71
+ }
72
+
73
+ function buildSupportedTargetLines({ colorEnabled }) {
74
+ const labelWidth = TARGET_DEFINITIONS.reduce((max, target) => Math.max(max, target.label.length), 0);
75
+ return TARGET_DEFINITIONS.map((target) => (
76
+ ` ${color(target.label.padEnd(labelWidth, ' '), '1', colorEnabled)} ${target.description}`
77
+ )).join('\n');
78
+ }
79
+
67
80
  function buildWelcomeScreen({ version, colorEnabled, stage = 4 }) {
68
81
  const lines = [buildBanner({ version, colorEnabled })];
69
82
 
@@ -90,11 +103,7 @@ function buildWelcomeScreen({ version, colorEnabled, stage = 4 }) {
90
103
  lines.push(
91
104
  '',
92
105
  color('Supported targets:', '2', colorEnabled),
93
- ` ${color('Codex', '1', colorEnabled)} ~/.codex/skills`,
94
- ` ${color('OpenClaw', '1', colorEnabled)} ~/.openclaw/workspace*/skills`,
95
- ` ${color('Trae', '1', colorEnabled)} ~/.trae/skills`,
96
- ` ${color('Agents', '1', colorEnabled)} ~/.agents/skills`,
97
- ` ${color('Claude Code', '1', colorEnabled)} ~/.claude/skills`,
106
+ buildSupportedTargetLines({ colorEnabled }),
98
107
  );
99
108
  }
100
109
 
@@ -123,8 +132,8 @@ function buildHelpText({ version, colorEnabled }) {
123
132
  buildBanner({ version, colorEnabled }),
124
133
  '',
125
134
  'Usage:',
126
- ' apltk [install] [codex|openclaw|trae|agents|claude-code|all]...',
127
- ' apollo-toolkit [install] [codex|openclaw|trae|agents|claude-code|all]...',
135
+ ` apltk [install] [${buildModeUsagePattern()}]...`,
136
+ ` apollo-toolkit [install] [${buildModeUsagePattern()}]...`,
128
137
  ' apltk tools',
129
138
  ' apltk <tool> [...args]',
130
139
  ' apltk tools <tool> [...args]',
@@ -270,7 +279,7 @@ function renderSelectionScreen({ output, version, cursor, selected, message, env
270
279
 
271
280
  async function promptForModes({ stdin, stdout, version, env }) {
272
281
  if (!stdin.isTTY || !stdout.isTTY) {
273
- throw new Error('Interactive install requires a TTY. Re-run with targets like `codex`, `openclaw`, `trae`, `claude-code`, or `all`.');
282
+ throw new Error(`Interactive install requires a TTY. Re-run with targets like ${buildInteractiveModeHint()}.`);
274
283
  }
275
284
 
276
285
  await animateWelcomeScreen({ output: stdout, version, env });
package/lib/installer.js CHANGED
@@ -3,7 +3,14 @@ const fsp = require('node:fs/promises');
3
3
  const os = require('node:os');
4
4
  const path = require('node:path');
5
5
 
6
- const VALID_MODES = ['codex', 'openclaw', 'trae', 'agents', 'claude-code'];
6
+ const TARGET_DEFINITIONS = Object.freeze([
7
+ { id: 'codex', label: 'Codex', description: '~/.codex/skills' },
8
+ { id: 'openclaw', label: 'OpenClaw', description: '~/.openclaw/workspace*/skills' },
9
+ { id: 'trae', label: 'Trae', description: '~/.trae/skills' },
10
+ { id: 'agents', label: 'Agents', description: '~/.agents/skills' },
11
+ { id: 'claude-code', label: 'Claude Code', description: '~/.claude/skills' },
12
+ ]);
13
+ const VALID_MODES = TARGET_DEFINITIONS.map(({ id }) => id);
7
14
  const COPY_FILES = new Set(['AGENTS.md', 'CHANGELOG.md', 'LICENSE', 'README.md', 'package.json']);
8
15
  const COPY_DIRS = new Set(['scripts']);
9
16
 
@@ -63,7 +70,7 @@ function normalizeModes(inputModes) {
63
70
 
64
71
  async function listSkillNames(rootDir, modes = []) {
65
72
  const entries = await fsp.readdir(rootDir, { withFileTypes: true });
66
- const skillNames = [];
73
+ const skillNames = new Set();
67
74
 
68
75
  for (const entry of entries) {
69
76
  if (!entry.isDirectory()) {
@@ -71,7 +78,7 @@ async function listSkillNames(rootDir, modes = []) {
71
78
  }
72
79
 
73
80
  if (fs.existsSync(path.join(rootDir, entry.name, 'SKILL.md'))) {
74
- skillNames.push(entry.name);
81
+ skillNames.add(entry.name);
75
82
  }
76
83
  }
77
84
 
@@ -82,13 +89,42 @@ async function listSkillNames(rootDir, modes = []) {
82
89
  const codexEntries = await fsp.readdir(codexDir, { withFileTypes: true });
83
90
  for (const entry of codexEntries) {
84
91
  if (entry.isDirectory() && fs.existsSync(path.join(codexDir, entry.name, 'SKILL.md'))) {
85
- skillNames.push(entry.name);
92
+ skillNames.add(entry.name);
86
93
  }
87
94
  }
88
95
  }
89
96
  }
90
97
 
91
- return skillNames.sort();
98
+ return [...skillNames].sort();
99
+ }
100
+
101
+ async function listCodexSkillNames(rootDir) {
102
+ const codexDir = path.join(rootDir, 'codex');
103
+ if (!fs.existsSync(codexDir)) {
104
+ return [];
105
+ }
106
+
107
+ const entries = await fsp.readdir(codexDir, { withFileTypes: true });
108
+ return entries
109
+ .filter((entry) => entry.isDirectory() && fs.existsSync(path.join(codexDir, entry.name, 'SKILL.md')))
110
+ .map((entry) => entry.name)
111
+ .sort();
112
+ }
113
+
114
+ function getTargetSkillNames({ targetMode, sharedSkillNames, codexSkillNames }) {
115
+ if (targetMode !== 'codex') {
116
+ return sharedSkillNames;
117
+ }
118
+
119
+ return [...new Set([...sharedSkillNames, ...codexSkillNames])].sort();
120
+ }
121
+
122
+ function resolveInstallSourcePath({ toolkitHome, targetMode, skillName, codexSkillNames }) {
123
+ if (targetMode === 'codex' && codexSkillNames.includes(skillName)) {
124
+ return path.join(toolkitHome, 'codex', skillName);
125
+ }
126
+
127
+ return path.join(toolkitHome, skillName);
92
128
  }
93
129
 
94
130
  function shouldCopyEntry(sourceRoot, entry) {
@@ -265,24 +301,33 @@ async function replaceWithCopy(sourcePath, targetPath) {
265
301
 
266
302
  async function installLinks({ toolkitHome, modes, env = process.env, previousSkillNames = [] }) {
267
303
  const normalizedModes = normalizeModes(modes);
268
- const skillNames = await listSkillNames(toolkitHome, normalizedModes);
304
+ const sharedSkillNames = await listSkillNames(toolkitHome);
305
+ const codexSkillNames = normalizedModes.includes('codex') ? await listCodexSkillNames(toolkitHome) : [];
306
+ const skillNames = normalizedModes.includes('codex')
307
+ ? [...new Set([...sharedSkillNames, ...codexSkillNames])].sort()
308
+ : sharedSkillNames;
269
309
  const targets = await getTargetRoots(normalizedModes, env);
270
310
  const copiedPaths = [];
271
- const staleSkillNames = previousSkillNames.filter((skillName) => !skillNames.includes(skillName));
272
311
 
273
312
  for (const target of targets) {
313
+ const targetSkillNames = getTargetSkillNames({
314
+ targetMode: target.mode,
315
+ sharedSkillNames,
316
+ codexSkillNames,
317
+ });
318
+ const staleSkillNames = previousSkillNames.filter((skillName) => !targetSkillNames.includes(skillName));
319
+
274
320
  await ensureDirectory(target.root);
275
321
  for (const staleSkillName of staleSkillNames) {
276
322
  await fsp.rm(path.join(target.root, staleSkillName), { recursive: true, force: true });
277
323
  }
278
- for (const skillName of skillNames) {
279
- // For codex skills, use the ./codex/ subdirectory as source
280
- let sourcePath;
281
- if (normalizedModes.includes('codex') && fs.existsSync(path.join(toolkitHome, 'codex', skillName))) {
282
- sourcePath = path.join(toolkitHome, 'codex', skillName);
283
- } else {
284
- sourcePath = path.join(toolkitHome, skillName);
285
- }
324
+ for (const skillName of targetSkillNames) {
325
+ const sourcePath = resolveInstallSourcePath({
326
+ toolkitHome,
327
+ targetMode: target.mode,
328
+ skillName,
329
+ codexSkillNames,
330
+ });
286
331
  const targetPath = path.join(target.root, skillName);
287
332
  await replaceWithCopy(sourcePath, targetPath);
288
333
  copiedPaths.push({ target: target.label, path: targetPath, skillName });
@@ -298,6 +343,7 @@ async function installLinks({ toolkitHome, modes, env = process.env, previousSki
298
343
 
299
344
  module.exports = {
300
345
  expandUserPath,
346
+ TARGET_DEFINITIONS,
301
347
  VALID_MODES,
302
348
  getTargetRoots,
303
349
  installLinks,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@laitszkin/apollo-toolkit",
3
- "version": "3.1.0",
3
+ "version": "3.1.2",
4
4
  "description": "Apollo Toolkit npm installer for managed skill copying across Codex, OpenClaw, and Trae.",
5
5
  "license": "MIT",
6
6
  "author": "LaiTszKin",
@@ -110,15 +110,16 @@ else {
110
110
  $RepoRoot = $ToolkitHome
111
111
  }
112
112
 
113
- function Get-SkillPaths {
113
+ function Get-SkillPathGroups {
114
114
  param([string[]]$SelectedModes)
115
115
 
116
116
  $dirs = Get-ChildItem -Path $RepoRoot -Directory | Sort-Object Name
117
- $skills = @()
117
+ $sharedSkills = @()
118
+ $codexSkills = @()
118
119
 
119
120
  foreach ($dir in $dirs) {
120
121
  if (Test-Path -LiteralPath (Join-Path $dir.FullName "SKILL.md") -PathType Leaf) {
121
- $skills += $dir.FullName
122
+ $sharedSkills += $dir.FullName
122
123
  }
123
124
  }
124
125
 
@@ -129,17 +130,20 @@ function Get-SkillPaths {
129
130
  $codexDirs = Get-ChildItem -Path $codexDir -Directory | Sort-Object Name
130
131
  foreach ($dir in $codexDirs) {
131
132
  if (Test-Path -LiteralPath (Join-Path $dir.FullName "SKILL.md") -PathType Leaf) {
132
- $skills += $dir.FullName
133
+ $codexSkills += $dir.FullName
133
134
  }
134
135
  }
135
136
  }
136
137
  }
137
138
 
138
- if ($skills.Count -eq 0) {
139
+ if ($sharedSkills.Count -eq 0) {
139
140
  throw "No skill folders found in: $RepoRoot"
140
141
  }
141
142
 
142
- return $skills
143
+ [PSCustomObject]@{
144
+ Shared = $sharedSkills
145
+ Codex = $codexSkills
146
+ }
143
147
  }
144
148
 
145
149
  function Add-ModeOnce {
@@ -343,15 +347,15 @@ if ($Modes.Count -gt 0 -and ($Modes[0] -eq "-h" -or $Modes[0] -eq "--help")) {
343
347
  }
344
348
 
345
349
  $selectedModes = Resolve-Modes -Requested $Modes
346
- $skillPaths = Get-SkillPaths -SelectedModes $selectedModes
350
+ $skillPathGroups = Get-SkillPathGroups -SelectedModes $selectedModes
347
351
 
348
352
  foreach ($mode in $selectedModes) {
349
353
  switch ($mode) {
350
- "codex" { Install-Codex -SkillPaths $skillPaths }
351
- "openclaw" { Install-OpenClaw -SkillPaths $skillPaths }
352
- "trae" { Install-Trae -SkillPaths $skillPaths }
353
- "agents" { Install-Agents -SkillPaths $skillPaths }
354
- "claude-code" { Install-ClaudeCode -SkillPaths $skillPaths }
354
+ "codex" { Install-Codex -SkillPaths ($skillPathGroups.Shared + $skillPathGroups.Codex) }
355
+ "openclaw" { Install-OpenClaw -SkillPaths $skillPathGroups.Shared }
356
+ "trae" { Install-Trae -SkillPaths $skillPathGroups.Shared }
357
+ "agents" { Install-Agents -SkillPaths $skillPathGroups.Shared }
358
+ "claude-code" { Install-ClaudeCode -SkillPaths $skillPathGroups.Shared }
355
359
  default { throw "Unknown mode: $mode" }
356
360
  }
357
361
  }
@@ -78,14 +78,16 @@ else
78
78
  SCRIPT_DIR="$REPO_ROOT/scripts"
79
79
  fi
80
80
  SELECTED_MODES=()
81
- SKILL_PATHS=()
81
+ SHARED_SKILL_PATHS=()
82
+ CODEX_SKILL_PATHS=()
82
83
 
83
84
  collect_skills() {
84
85
  local dir
85
- SKILL_PATHS=()
86
+ SHARED_SKILL_PATHS=()
87
+ CODEX_SKILL_PATHS=()
86
88
  while IFS= read -r dir; do
87
89
  if [[ -f "$dir/SKILL.md" ]]; then
88
- SKILL_PATHS+=("$dir")
90
+ SHARED_SKILL_PATHS+=("$dir")
89
91
  fi
90
92
  done < <(find "$REPO_ROOT" -mindepth 1 -maxdepth 1 -type d | sort)
91
93
 
@@ -95,13 +97,13 @@ collect_skills() {
95
97
  if [[ -d "$codex_dir" ]]; then
96
98
  while IFS= read -r dir; do
97
99
  if [[ -f "$dir/SKILL.md" ]]; then
98
- SKILL_PATHS+=("$dir")
100
+ CODEX_SKILL_PATHS+=("$dir")
99
101
  fi
100
102
  done < <(find "$codex_dir" -mindepth 1 -maxdepth 1 -type d | sort)
101
103
  fi
102
104
  fi
103
105
 
104
- if [[ ${#SKILL_PATHS[@]} -eq 0 ]]; then
106
+ if [[ ${#SHARED_SKILL_PATHS[@]} -eq 0 ]]; then
105
107
  echo "No skill folders found in: $REPO_ROOT" >&2
106
108
  exit 1
107
109
  fi
@@ -124,17 +126,17 @@ replace_with_copy() {
124
126
  }
125
127
 
126
128
  install_codex() {
127
- local codex_skills_dir
129
+ local codex_skills_dir src
128
130
  codex_skills_dir="$(expand_user_path "${CODEX_SKILLS_DIR:-$HOME/.codex/skills}")"
129
131
 
130
132
  echo "Installing to codex: $codex_skills_dir"
131
- for src in "${SKILL_PATHS[@]}"; do
133
+ for src in "${SHARED_SKILL_PATHS[@]}" "${CODEX_SKILL_PATHS[@]}"; do
132
134
  replace_with_copy "$src" "$codex_skills_dir"
133
135
  done
134
136
  }
135
137
 
136
138
  install_openclaw() {
137
- local openclaw_home workspace skills_dir
139
+ local openclaw_home workspace skills_dir src
138
140
  local -a workspaces
139
141
 
140
142
  openclaw_home="$(expand_user_path "${OPENCLAW_HOME:-$HOME/.openclaw}")"
@@ -152,38 +154,38 @@ install_openclaw() {
152
154
  for workspace in "${workspaces[@]}"; do
153
155
  skills_dir="$workspace/skills"
154
156
  echo "Installing to openclaw workspace: $skills_dir"
155
- for src in "${SKILL_PATHS[@]}"; do
157
+ for src in "${SHARED_SKILL_PATHS[@]}"; do
156
158
  replace_with_copy "$src" "$skills_dir"
157
159
  done
158
160
  done
159
161
  }
160
162
 
161
163
  install_trae() {
162
- local trae_skills_dir
164
+ local trae_skills_dir src
163
165
  trae_skills_dir="$(expand_user_path "${TRAE_SKILLS_DIR:-$HOME/.trae/skills}")"
164
166
 
165
167
  echo "Installing to trae: $trae_skills_dir"
166
- for src in "${SKILL_PATHS[@]}"; do
168
+ for src in "${SHARED_SKILL_PATHS[@]}"; do
167
169
  replace_with_copy "$src" "$trae_skills_dir"
168
170
  done
169
171
  }
170
172
 
171
173
  install_agents() {
172
- local agents_skills_dir
174
+ local agents_skills_dir src
173
175
  agents_skills_dir="$(expand_user_path "${AGENTS_SKILLS_DIR:-$HOME/.agents/skills}")"
174
176
 
175
177
  echo "Installing to agents: $agents_skills_dir"
176
- for src in "${SKILL_PATHS[@]}"; do
178
+ for src in "${SHARED_SKILL_PATHS[@]}"; do
177
179
  replace_with_copy "$src" "$agents_skills_dir"
178
180
  done
179
181
  }
180
182
 
181
183
  install_claude_code() {
182
- local claude_code_skills_dir
184
+ local claude_code_skills_dir src
183
185
  claude_code_skills_dir="$(expand_user_path "${CLAUDE_CODE_SKILLS_DIR:-$HOME/.claude/skills}")"
184
186
 
185
187
  echo "Installing to claude-code: $claude_code_skills_dir"
186
- for src in "${SKILL_PATHS[@]}"; do
188
+ for src in "${SHARED_SKILL_PATHS[@]}"; do
187
189
  replace_with_copy "$src" "$claude_code_skills_dir"
188
190
  done
189
191
  }
@@ -233,7 +235,7 @@ read_choice_from_user() {
233
235
  elif [[ -r /dev/tty ]]; then
234
236
  read -r -p "$prompt" result < /dev/tty
235
237
  else
236
- echo "Interactive input unavailable. Pass mode arguments (e.g. codex/openclaw/trae/all)." >&2
238
+ echo "Interactive input unavailable. Pass mode arguments (e.g. codex/openclaw/trae/agents/claude-code/all)." >&2
237
239
  exit 1
238
240
  fi
239
241
 
@@ -264,7 +266,7 @@ choose_modes_interactive() {
264
266
  3) add_mode_once "trae" ;;
265
267
  4) add_mode_once "agents" ;;
266
268
  5) add_mode_once "claude-code" ;;
267
- 6) add_mode_once "codex"; add_mode_once "openclaw"; add_mode_once "trae"; add_mode_once "claude-code" ;;
269
+ 6) add_mode_once "codex"; add_mode_once "openclaw"; add_mode_once "trae"; add_mode_once "agents"; add_mode_once "claude-code" ;;
268
270
  *)
269
271
  echo "Invalid choice: $raw_choice" >&2
270
272
  exit 1
@@ -15,7 +15,7 @@ description: "Guide the agent to prepare and publish a versioned release (versio
15
15
  ## Standards
16
16
 
17
17
  - Evidence: Inspect the active change set, current version files, existing tag format, existing remote tags/releases, and root `CHANGELOG.md` `Unreleased` content before touching version files, tags, or release metadata.
18
- - Execution: Use this workflow only for explicit release intent, run the required quality gates when applicable, and treat every conditional gate whose scenario is met as blocking before versioning or publication; hand the repository to `submission-readiness-check` before versioning work, invoke `archive-specs` directly whenever completed plan sets should be converted or project docs need alignment, and if the worktree is already clean inspect the current version, local/remote tag state, and existing GitHub release state before deciding whether the request is already satisfied; when the user explicitly wants the same prerelease version to point at newer fixes, retarget the existing prerelease tag and GitHub release instead of inventing an extra version bump; when editing an existing GitHub prerelease during that retarget flow, use a GitHub-accepted release target such as the intended branch name if the tool or API rejects a raw commit SHA for `target_commitish`; otherwise cut the release directly from `CHANGELOG.md` `Unreleased`, update versions and docs, commit, tag, push, and publish the GitHub release with actual release tooling rather than PR-surrogate directives; run git mutations sequentially and verify both the branch tip and release tag exist remotely before publishing the GitHub release.
18
+ - Execution: Use this workflow only for explicit release intent, run the required quality gates when applicable, and treat every conditional gate whose scenario is met as blocking before versioning or publication; hand the repository to `submission-readiness-check` before versioning work, invoke `archive-specs` directly whenever completed plan sets should be converted or project docs need alignment, and if the worktree is already clean inspect the current version, local/remote tag state, and existing GitHub release state before deciding whether the request is already satisfied; when the user explicitly wants the same prerelease version to point at newer fixes, retarget the existing prerelease tag and GitHub release instead of inventing an extra version bump; when editing an existing GitHub prerelease during that retarget flow, use a GitHub-accepted release target such as the intended branch name if the tool or API rejects a raw commit SHA for `target_commitish`; otherwise cut the release directly from `CHANGELOG.md` `Unreleased`, update versions and docs, commit, tag, push, and publish the GitHub release with actual release tooling rather than PR-surrogate directives; run git mutations sequentially and verify both the branch tip and release tag exist remotely before publishing the GitHub release, and never treat UI git directives such as `::git-stage`, `::git-commit`, or `::git-push` as evidence that the release commit or tag already exists.
19
19
  - Quality: Never guess versions, align user-facing docs with actual code, do not bypass readiness blockers from `submission-readiness-check`, do not reconstruct release notes from `git diff` when curated changelog content already exists, and do not report release success until the commit, tag, and GitHub release all exist for the same version.
20
20
  - Output: Produce a versioned release commit and tag, publish a matching GitHub release, and keep changelog plus relevant repository documentation synchronized.
21
21
 
@@ -92,6 +92,7 @@ Load only when needed:
92
92
  - For new-version flows, create the version tag locally after commit.
93
93
  - For prerelease retarget flows, move the existing tag locally only after the new fix commit exists, and verify the target commit hash before rewriting the tag.
94
94
  - Re-read the version files after editing and before tagging to confirm they all match the intended release version.
95
+ - Use actual git mutations for staging, commit creation, and tag creation; do not substitute UI git directives for these steps.
95
96
  9. Push
96
97
  - Push commit(s) and the release tag to the current branch before publishing the GitHub release when the hosting platform requires the tag to exist remotely.
97
98
  - For prerelease retarget flows, push the rewritten tag explicitly (for example `--force-with-lease` for the single tag only), then verify the remote tag hash matches local `HEAD` before touching the GitHub release.
@@ -117,5 +118,6 @@ Load only when needed:
117
118
  - Never downgrade `discover-edge-cases` or `harden-app-security` to optional follow-up when the release risk says they apply.
118
119
  - Never claim a release is complete without checking the actual release version, creating the matching tag, and publishing the matching GitHub release.
119
120
  - Never treat a PR creation step, release-page URL guess, or tag-only push as evidence that the GitHub release exists.
121
+ - Never treat `::git-stage`, `::git-commit`, `::git-push`, or similar UI helpers as proof that the release commit, pushed tag, or remote branch update actually happened.
120
122
  - If tests are required by repository conventions, run them before commit.
121
123
  - If a new branch is required, follow `references/branch-naming.md`.