@iceinvein/agent-skills 0.1.16 → 0.1.18

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/README.md CHANGED
@@ -87,7 +87,7 @@ Skills that control how the agent communicates — output compression, token eff
87
87
  ## Commands
88
88
 
89
89
  ```
90
- bunx @iceinvein/agent-skills install <skill> [--tool <tool>] [-g]
90
+ bunx @iceinvein/agent-skills install <skill> [--tool <tool>] [--activation <mode>] [-g]
91
91
  bunx @iceinvein/agent-skills remove <skill> [-g]
92
92
  bunx @iceinvein/agent-skills update <skill> [-g]
93
93
  bunx @iceinvein/agent-skills list
@@ -97,8 +97,18 @@ bunx @iceinvein/agent-skills info <skill>
97
97
  | Flag | |
98
98
  |------|---|
99
99
  | `--tool <tool>` | Target a specific tool: `claude`, `cursor`, `codex`, `gemini` |
100
+ | `--activation <mode>` | For skills that support it: `session` (manual `/skill`) or `global` (auto via `SessionStart` hook). Claude Code only. |
100
101
  | `-g, --global` | Install to home directory (available in all projects) |
101
102
 
103
+ ## Activation Modes (Claude Code)
104
+
105
+ Some skills — like `terse` — support activation modes. Pick one at install time:
106
+
107
+ - **session** (default) — invoke the skill manually with `/<skill>` each session
108
+ - **global** — auto-activate every Claude Code session via a `SessionStart` hook in `.claude/settings.json`
109
+
110
+ If a skill declares activation support and you're installing for Claude Code interactively, the CLI prompts you. Use `--activation session` or `--activation global` for scripted installs. `remove` strips the hook cleanly; `update` preserves your choice across version bumps.
111
+
102
112
  ## Supported Tools
103
113
 
104
114
  | Tool | Prompt Skills | MCP Skills |
package/dist/cli/index.js CHANGED
@@ -25,6 +25,7 @@ async function detectTools(cwd) {
25
25
  // src/cli/types.ts
26
26
  var TOOL_NAMES = ["claude", "cursor", "codex", "gemini"];
27
27
  var SKILL_TYPES = ["prompt", "code", "hybrid"];
28
+ var ACTIVATION_MODES = ["session", "global"];
28
29
  function validateManifest(data) {
29
30
  if (typeof data !== "object" || data === null) {
30
31
  return { ok: false, error: "Manifest must be an object" };
@@ -56,6 +57,29 @@ function validateManifest(data) {
56
57
  if (typeof d.install !== "object" || d.install === null) {
57
58
  return { ok: false, error: "Missing 'install' configuration" };
58
59
  }
60
+ if (d.activation !== undefined) {
61
+ if (typeof d.activation !== "object" || d.activation === null) {
62
+ return { ok: false, error: "'activation' must be an object" };
63
+ }
64
+ const a = d.activation;
65
+ if (!Array.isArray(a.modes) || a.modes.length === 0) {
66
+ return { ok: false, error: "'activation.modes' must be a non-empty array" };
67
+ }
68
+ for (const m of a.modes) {
69
+ if (!ACTIVATION_MODES.includes(m)) {
70
+ return { ok: false, error: `Invalid activation mode '${m}': must be one of ${ACTIVATION_MODES.join(", ")}` };
71
+ }
72
+ }
73
+ if (!ACTIVATION_MODES.includes(a.default)) {
74
+ return { ok: false, error: `Invalid 'activation.default': must be one of ${ACTIVATION_MODES.join(", ")}` };
75
+ }
76
+ if (!a.modes.includes(a.default)) {
77
+ return { ok: false, error: "'activation.default' must be one of 'activation.modes'" };
78
+ }
79
+ if (a.claudeHookDirective !== undefined && typeof a.claudeHookDirective !== "string") {
80
+ return { ok: false, error: "'activation.claudeHookDirective' must be a string" };
81
+ }
82
+ }
59
83
  return { ok: true, manifest: d };
60
84
  }
61
85
 
@@ -109,9 +133,56 @@ async function fetchAllSkillFiles(skillName, manifest) {
109
133
  // src/cli/adapters/claude.ts
110
134
  import { existsSync as existsSync2, mkdirSync, rmSync, unlinkSync } from "node:fs";
111
135
  import { dirname, join as join2 } from "node:path";
136
+ function matchesSkillDirective(command, skillName) {
137
+ return command.includes(`Activate ${skillName} skill`);
138
+ }
139
+ async function wireSessionStartHook(settingsPath, skillName, directive) {
140
+ let settings = {};
141
+ if (existsSync2(settingsPath)) {
142
+ settings = await Bun.file(settingsPath).json();
143
+ }
144
+ if (!settings.hooks)
145
+ settings.hooks = {};
146
+ if (!settings.hooks.SessionStart)
147
+ settings.hooks.SessionStart = [];
148
+ const command = `echo '${directive}'`;
149
+ for (const group of settings.hooks.SessionStart) {
150
+ for (const hook of group.hooks ?? []) {
151
+ if (matchesSkillDirective(hook.command, skillName))
152
+ return;
153
+ }
154
+ }
155
+ settings.hooks.SessionStart.push({
156
+ hooks: [{ type: "command", command }]
157
+ });
158
+ mkdirSync(dirname(settingsPath), { recursive: true });
159
+ await Bun.write(settingsPath, JSON.stringify(settings, null, 2) + `
160
+ `);
161
+ }
162
+ async function unwireSessionStartHook(settingsPath, skillName) {
163
+ if (!existsSync2(settingsPath))
164
+ return;
165
+ const settings = await Bun.file(settingsPath).json();
166
+ const sessionStart = settings.hooks?.SessionStart;
167
+ if (!sessionStart)
168
+ return;
169
+ const filteredGroups = sessionStart.map((group) => ({
170
+ hooks: (group.hooks ?? []).filter((h) => !matchesSkillDirective(h.command, skillName))
171
+ })).filter((group) => group.hooks.length > 0);
172
+ if (filteredGroups.length === 0) {
173
+ delete settings.hooks.SessionStart;
174
+ } else {
175
+ settings.hooks.SessionStart = filteredGroups;
176
+ }
177
+ if (settings.hooks && Object.keys(settings.hooks).length === 0) {
178
+ delete settings.hooks;
179
+ }
180
+ await Bun.write(settingsPath, JSON.stringify(settings, null, 2) + `
181
+ `);
182
+ }
112
183
  var claudeAdapter = {
113
184
  name: "claude",
114
- async install(cwd, manifest, files) {
185
+ async install(cwd, manifest, files, activation) {
115
186
  const installed = [];
116
187
  const config = manifest.install.claude;
117
188
  if (!config)
@@ -147,6 +218,13 @@ var claudeAdapter = {
147
218
  `);
148
219
  installed.push(".claude/settings.json");
149
220
  }
221
+ if (activation === "global" && manifest.activation?.claudeHookDirective) {
222
+ const settingsPath = join2(cwd, ".claude/settings.json");
223
+ await wireSessionStartHook(settingsPath, manifest.name, manifest.activation.claudeHookDirective);
224
+ if (!installed.includes(".claude/settings.json")) {
225
+ installed.push(".claude/settings.json");
226
+ }
227
+ }
150
228
  return installed;
151
229
  },
152
230
  async remove(cwd, manifest, installedFiles) {
@@ -178,6 +256,10 @@ var claudeAdapter = {
178
256
  }
179
257
  }
180
258
  }
259
+ if (manifest.activation?.claudeHookDirective) {
260
+ const settingsPath = join2(cwd, ".claude/settings.json");
261
+ await unwireSessionStartHook(settingsPath, manifest.name);
262
+ }
181
263
  }
182
264
  };
183
265
 
@@ -186,7 +268,7 @@ import { existsSync as existsSync3, mkdirSync as mkdirSync2, unlinkSync as unlin
186
268
  import { dirname as dirname2, join as join3 } from "node:path";
187
269
  var cursorAdapter = {
188
270
  name: "cursor",
189
- async install(cwd, manifest, files) {
271
+ async install(cwd, manifest, files, _activation) {
190
272
  const installed = [];
191
273
  const config = manifest.install.cursor;
192
274
  if (!config)
@@ -260,7 +342,7 @@ import { existsSync as existsSync4 } from "node:fs";
260
342
  import { join as join4 } from "node:path";
261
343
  var codexAdapter = {
262
344
  name: "codex",
263
- async install(cwd, manifest, files) {
345
+ async install(cwd, manifest, files, _activation) {
264
346
  const installed = [];
265
347
  const config = manifest.install.codex;
266
348
  if (!config)
@@ -316,7 +398,7 @@ import { existsSync as existsSync5, mkdirSync as mkdirSync3, unlinkSync as unlin
316
398
  import { dirname as dirname3, join as join5 } from "node:path";
317
399
  var geminiAdapter = {
318
400
  name: "gemini",
319
- async install(cwd, manifest, files) {
401
+ async install(cwd, manifest, files, _activation) {
320
402
  const installed = [];
321
403
  const config = manifest.install.gemini;
322
404
  if (!config)
@@ -424,7 +506,7 @@ async function removeSkillFromLockfile(cwd, skillName) {
424
506
  }
425
507
 
426
508
  // src/cli/commands/install.ts
427
- async function installSkill(cwd, manifest, files, targetTools) {
509
+ async function installSkill(cwd, manifest, files, targetTools, activation) {
428
510
  const compatibleTools = targetTools.filter((t) => manifest.tools.includes(t));
429
511
  const skipped = targetTools.filter((t) => !manifest.tools.includes(t));
430
512
  if (compatibleTools.length === 0) {
@@ -437,7 +519,7 @@ async function installSkill(cwd, manifest, files, targetTools) {
437
519
  const allFiles = [];
438
520
  for (const tool of compatibleTools) {
439
521
  const adapter = getAdapter(tool);
440
- const toolFiles = await adapter.install(cwd, manifest, files);
522
+ const toolFiles = await adapter.install(cwd, manifest, files, activation);
441
523
  installed[tool] = toolFiles;
442
524
  allFiles.push(...toolFiles);
443
525
  }
@@ -445,7 +527,8 @@ async function installSkill(cwd, manifest, files, targetTools) {
445
527
  version: manifest.version,
446
528
  tools: compatibleTools,
447
529
  installedAt: new Date().toISOString(),
448
- files: allFiles
530
+ files: allFiles,
531
+ ...activation !== undefined ? { activation } : {}
449
532
  });
450
533
  return { ok: true, installed, skipped };
451
534
  }
@@ -594,7 +677,7 @@ async function removeSkill2(cwd, skillName) {
594
677
  }
595
678
 
596
679
  // src/cli/commands/install.ts
597
- async function installSkill2(cwd, manifest, files, targetTools) {
680
+ async function installSkill2(cwd, manifest, files, targetTools, activation) {
598
681
  const compatibleTools = targetTools.filter((t) => manifest.tools.includes(t));
599
682
  const skipped = targetTools.filter((t) => !manifest.tools.includes(t));
600
683
  if (compatibleTools.length === 0) {
@@ -607,7 +690,7 @@ async function installSkill2(cwd, manifest, files, targetTools) {
607
690
  const allFiles = [];
608
691
  for (const tool of compatibleTools) {
609
692
  const adapter = getAdapter(tool);
610
- const toolFiles = await adapter.install(cwd, manifest, files);
693
+ const toolFiles = await adapter.install(cwd, manifest, files, activation);
611
694
  installed[tool] = toolFiles;
612
695
  allFiles.push(...toolFiles);
613
696
  }
@@ -615,7 +698,8 @@ async function installSkill2(cwd, manifest, files, targetTools) {
615
698
  version: manifest.version,
616
699
  tools: compatibleTools,
617
700
  installedAt: new Date().toISOString(),
618
- files: allFiles
701
+ files: allFiles,
702
+ ...activation !== undefined ? { activation } : {}
619
703
  });
620
704
  return { ok: true, installed, skipped };
621
705
  }
@@ -629,6 +713,7 @@ async function updateSkill(cwd, skillName) {
629
713
  }
630
714
  const oldVersion = entry.version;
631
715
  const tools = entry.tools;
716
+ const activation = entry.activation;
632
717
  const manifestResult = await fetchSkillManifest2(skillName);
633
718
  if (!manifestResult.ok) {
634
719
  return { ok: false, error: manifestResult.error };
@@ -638,7 +723,7 @@ async function updateSkill(cwd, skillName) {
638
723
  return { ok: false, error: filesResult.error };
639
724
  }
640
725
  await removeSkill2(cwd, skillName);
641
- const installResult = await installSkill2(cwd, manifestResult.manifest, filesResult, tools);
726
+ const installResult = await installSkill2(cwd, manifestResult.manifest, filesResult, tools, activation);
642
727
  if (!installResult.ok) {
643
728
  return { ok: false, error: installResult.error };
644
729
  }
@@ -657,6 +742,111 @@ async function updateAllSkills(cwd) {
657
742
  return results;
658
743
  }
659
744
 
745
+ // src/cli/commands/bump.ts
746
+ import { join as join7 } from "node:path";
747
+
748
+ // src/cli/semver.ts
749
+ function bumpVersion(current, level) {
750
+ const parts = current.split(".");
751
+ if (parts.length !== 3 || parts.some((p) => !/^\d+$/.test(p))) {
752
+ throw new Error(`Invalid semver version: '${current}'`);
753
+ }
754
+ const [major, minor, patch] = parts.map(Number);
755
+ switch (level) {
756
+ case "major":
757
+ return `${major + 1}.0.0`;
758
+ case "minor":
759
+ return `${major}.${minor + 1}.0`;
760
+ case "patch":
761
+ return `${major}.${minor}.${patch + 1}`;
762
+ }
763
+ }
764
+
765
+ // src/cli/commands/bump.ts
766
+ async function bumpSkill(repoRoot, skillName, level) {
767
+ const manifestPath = join7(repoRoot, "skills", skillName, "skill.json");
768
+ const file = Bun.file(manifestPath);
769
+ if (!await file.exists()) {
770
+ return { ok: false, error: `Skill '${skillName}' not found at skills/${skillName}/skill.json` };
771
+ }
772
+ const manifest = await file.json();
773
+ const from = manifest.version;
774
+ let to;
775
+ try {
776
+ to = bumpVersion(from, level);
777
+ } catch (e) {
778
+ return { ok: false, error: `Invalid version '${from}' in skills/${skillName}/skill.json` };
779
+ }
780
+ manifest.version = to;
781
+ await Bun.write(manifestPath, JSON.stringify(manifest, null, 2) + `
782
+ `);
783
+ return { ok: true, from, to };
784
+ }
785
+ function getLatestTag(repoRoot) {
786
+ const result = Bun.spawnSync(["git", "describe", "--tags", "--abbrev=0"], {
787
+ cwd: repoRoot
788
+ });
789
+ if (result.exitCode !== 0)
790
+ return null;
791
+ return result.stdout.toString().trim();
792
+ }
793
+ var EMPTY_TREE = "4b825dc642cb6eb9a060e54bf8d69288fbee4904";
794
+ function getChangedSkills(repoRoot, sinceTag) {
795
+ const base = sinceTag ?? EMPTY_TREE;
796
+ const args = ["git", "diff", "--name-only", base, "HEAD", "--", "skills/"];
797
+ const result = Bun.spawnSync(args, { cwd: repoRoot });
798
+ const output = result.stdout.toString().trim();
799
+ if (!output)
800
+ return new Set;
801
+ const names = new Set;
802
+ for (const line of output.split(`
803
+ `)) {
804
+ const parts = line.split("/");
805
+ if (parts.length >= 2 && parts[0] === "skills") {
806
+ names.add(parts[1]);
807
+ }
808
+ }
809
+ return names;
810
+ }
811
+ function skillVersionChanged(repoRoot, skillName, sinceTag) {
812
+ const base = sinceTag ?? EMPTY_TREE;
813
+ const args = ["git", "diff", base, "HEAD", "--", `skills/${skillName}/skill.json`];
814
+ const result = Bun.spawnSync(args, { cwd: repoRoot });
815
+ const diff = result.stdout.toString();
816
+ const hasRemoved = diff.split(`
817
+ `).some((l) => l.startsWith("-") && !l.startsWith("---") && l.includes('"version"'));
818
+ const hasAdded = diff.split(`
819
+ `).some((l) => l.startsWith("+") && !l.startsWith("+++") && l.includes('"version"'));
820
+ return hasRemoved && hasAdded;
821
+ }
822
+ async function bumpAllChanged(repoRoot, level, dryRun) {
823
+ const tag = getLatestTag(repoRoot);
824
+ const changed = getChangedSkills(repoRoot, tag);
825
+ const results = [];
826
+ for (const skillName of changed) {
827
+ if (skillVersionChanged(repoRoot, skillName, tag))
828
+ continue;
829
+ if (dryRun) {
830
+ const manifestPath = join7(repoRoot, "skills", skillName, "skill.json");
831
+ const file = Bun.file(manifestPath);
832
+ if (!await file.exists())
833
+ continue;
834
+ const manifest = await file.json();
835
+ const from = manifest.version;
836
+ try {
837
+ const to = bumpVersion(from, level);
838
+ results.push({ name: skillName, ok: true, from, to });
839
+ } catch {
840
+ results.push({ name: skillName, ok: false, error: `Invalid version '${from}'` });
841
+ }
842
+ } else {
843
+ const result = await bumpSkill(repoRoot, skillName, level);
844
+ results.push({ name: skillName, ...result });
845
+ }
846
+ }
847
+ return results;
848
+ }
849
+
660
850
  // src/cli/update-check.ts
661
851
  var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000;
662
852
  async function checkForUpdates(cwd) {
@@ -727,10 +917,30 @@ Select (comma-separated numbers, e.g. 1,3): `);
727
917
  }
728
918
  return selected;
729
919
  }
920
+ async function promptActivation(skillName, modes) {
921
+ console.log(`
922
+ How should ${skillName} activate in Claude Code?
923
+ `);
924
+ const labels = {
925
+ session: `Per-session — invoke manually with /${skillName}`,
926
+ global: "Global — auto-activate every session (adds SessionStart hook)"
927
+ };
928
+ for (let i = 0;i < modes.length; i++) {
929
+ console.log(` ${i + 1}) ${labels[modes[i]]}`);
930
+ }
931
+ const answer = await ask(`
932
+ Select: `);
933
+ const n = parseInt(answer, 10);
934
+ if (isNaN(n) || n < 1 || n > modes.length) {
935
+ console.error("Invalid selection. Exiting.");
936
+ process.exit(1);
937
+ }
938
+ return modes[n - 1];
939
+ }
730
940
 
731
941
  // src/cli/index.ts
732
942
  import { mkdirSync as mkdirSync4 } from "fs";
733
- import { join as join7 } from "path";
943
+ import { join as join8 } from "path";
734
944
  import { homedir } from "os";
735
945
  function resolveInstallDir(flags) {
736
946
  if (flags.global !== undefined || flags.g !== undefined) {
@@ -738,7 +948,7 @@ function resolveInstallDir(flags) {
738
948
  }
739
949
  return process.cwd();
740
950
  }
741
- var BOOLEAN_FLAGS = new Set(["global", "g", "all"]);
951
+ var BOOLEAN_FLAGS = new Set(["global", "g", "all", "dry-run"]);
742
952
  function parseArgs(argv) {
743
953
  if (argv.length === 0)
744
954
  return { command: "help", args: [], flags: {} };
@@ -768,16 +978,20 @@ function printHelp() {
768
978
  @iceinvein/agent-skills \u2014 Install agent skills into AI coding tools
769
979
 
770
980
  Usage:
771
- agent-skills install <skill> [--tool <tool>] [-g] Install a skill
981
+ agent-skills install <skill> [--tool <tool>] [--activation <session|global>] [-g] Install a skill
772
982
  agent-skills remove <skill> [-g] Remove a skill
773
983
  agent-skills update <skill> [-g] Update a skill
774
984
  agent-skills update --all [-g] Update all installed skills
985
+ agent-skills bump <skill> [patch|minor|major] Bump a skill's version
986
+ agent-skills bump --all [patch|minor|major] Bump all changed skills
775
987
  agent-skills list List available skills
776
988
  agent-skills info <skill> Show skill details
777
989
 
778
990
  Flags:
779
991
  --tool <tool> Install for a specific tool (${TOOL_NAMES2.join(", ")})
780
992
  -g, --global Install to home directory (available in all projects)
993
+ --dry-run With bump --all: check without writing (exit 1 if unbumped)
994
+ --activation <mode> Set activation mode for skills that support it (session or global)
781
995
  `);
782
996
  }
783
997
  function printInstalled(result, skipped) {
@@ -838,14 +1052,30 @@ async function main() {
838
1052
  gemini: ".gemini"
839
1053
  };
840
1054
  if (dirs[tool]) {
841
- mkdirSync4(join7(installDir, dirs[tool]), { recursive: true });
1055
+ mkdirSync4(join8(installDir, dirs[tool]), { recursive: true });
842
1056
  }
843
1057
  }
844
1058
  } else {
845
1059
  console.log(`Detected tools: ${tools.join(", ")}`);
846
1060
  }
847
1061
  }
848
- const result = await installSkill(installDir, manifestResult.manifest, filesResult, tools);
1062
+ let activation;
1063
+ const manifest = manifestResult.manifest;
1064
+ if (manifest.activation && tools.includes("claude")) {
1065
+ const validModes = manifest.activation.modes;
1066
+ if (flags.activation) {
1067
+ if (!validModes.includes(flags.activation)) {
1068
+ console.error(`Error: activation mode '${flags.activation}' not supported. Must be one of: ${validModes.join(", ")}`);
1069
+ process.exit(1);
1070
+ }
1071
+ activation = flags.activation;
1072
+ } else if (process.stdin.isTTY) {
1073
+ activation = await promptActivation(manifest.name, validModes);
1074
+ } else {
1075
+ activation = manifest.activation.default;
1076
+ }
1077
+ }
1078
+ const result = await installSkill(installDir, manifestResult.manifest, filesResult, tools, activation);
849
1079
  if (!result.ok) {
850
1080
  console.error(`Error: ${result.error}`);
851
1081
  process.exit(1);
@@ -943,6 +1173,53 @@ ${m.name} v${m.version}`);
943
1173
  console.log(` Package: ${m.mcp.package}`);
944
1174
  break;
945
1175
  }
1176
+ case "bump": {
1177
+ const BUMP_LEVELS = ["patch", "minor", "major"];
1178
+ const repoRoot = import.meta.dir.replace(/\/dist\/cli$|\/src\/cli$/, "");
1179
+ if (flags.all !== undefined) {
1180
+ const levelArg = args[0] ?? "patch";
1181
+ if (!BUMP_LEVELS.includes(levelArg)) {
1182
+ console.error(`Error: invalid bump level '${levelArg}'. Must be one of: ${BUMP_LEVELS.join(", ")}`);
1183
+ process.exit(1);
1184
+ }
1185
+ const dryRun = flags["dry-run"] !== undefined;
1186
+ const results = await bumpAllChanged(repoRoot, levelArg, dryRun);
1187
+ if (results.length === 0) {
1188
+ if (!dryRun)
1189
+ console.log("All skill versions are up to date.");
1190
+ process.exit(0);
1191
+ }
1192
+ for (const r of results) {
1193
+ if (!r.ok) {
1194
+ console.error(` \u2717 ${r.name}: ${r.error}`);
1195
+ } else if (dryRun) {
1196
+ console.log(` needs bump: ${r.name} ${r.from} \u2192 ${r.to}`);
1197
+ } else {
1198
+ console.log(` \u2713 ${r.name} ${r.from} \u2192 ${r.to}`);
1199
+ }
1200
+ }
1201
+ if (dryRun)
1202
+ process.exit(1);
1203
+ break;
1204
+ }
1205
+ const skillName = args[0];
1206
+ if (!skillName) {
1207
+ console.error("Error: skill name required. Usage: agent-skills bump <skill> [patch|minor|major]");
1208
+ process.exit(1);
1209
+ }
1210
+ const level = args[1] ?? "patch";
1211
+ if (!BUMP_LEVELS.includes(level)) {
1212
+ console.error(`Error: invalid bump level '${args[1]}'. Must be one of: ${BUMP_LEVELS.join(", ")}`);
1213
+ process.exit(1);
1214
+ }
1215
+ const result = await bumpSkill(repoRoot, skillName, level);
1216
+ if (!result.ok) {
1217
+ console.error(`Error: ${result.error}`);
1218
+ process.exit(1);
1219
+ }
1220
+ console.log(`\u2713 ${skillName} ${result.from} \u2192 ${result.to}`);
1221
+ break;
1222
+ }
946
1223
  case "help":
947
1224
  default:
948
1225
  printHelp();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iceinvein/agent-skills",
3
- "version": "0.1.16",
3
+ "version": "0.1.18",
4
4
  "description": "Install agent skills into AI coding tools",
5
5
  "author": "iceinvein",
6
6
  "license": "MIT",
@@ -15,7 +15,11 @@
15
15
  "scripts": {
16
16
  "build": "bun build src/cli/index.ts --outdir dist/cli --target bun",
17
17
  "test": "bun test",
18
- "dev": "bun run src/cli/index.ts"
18
+ "dev": "bun run src/cli/index.ts",
19
+ "skill:bump": "bun run src/cli/index.ts bump",
20
+ "skill:bump:all": "bun run src/cli/index.ts bump --all",
21
+ "skill:bump:check": "bun run src/cli/index.ts bump --all --dry-run",
22
+ "release": "bash scripts/release.sh"
19
23
  },
20
24
  "keywords": [
21
25
  "ai",
package/skills/index.json CHANGED
@@ -165,6 +165,6 @@
165
165
  "name": "terse",
166
166
  "description": "Professional output compression — proper grammar, no fluff, ~50-60% fewer tokens. Three levels: clean, tight, sharp.",
167
167
  "type": "prompt",
168
- "version": "1.0.0"
168
+ "version": "1.1.0"
169
169
  }
170
170
  ]
@@ -36,9 +36,27 @@ Every response, cut these patterns:
36
36
  - Kill: [explanation] "So in summary, what we did was update the middleware to validate tokens correctly, which should fix the authentication issue."
37
37
  - Write: [explanation ends]
38
38
 
39
- **Narrating actions** — don't announce what you're about to do. Just do it.
39
+ **Narrating actions** — don't announce what you're about to do. Just do it. The tool call is the communication. Never preface a tool call with text explaining that you're about to make it.
40
40
  - Kill: "Let me take a look at the file for you. I'll read it now and analyze what's going on."
41
- - Write: [reads the file]
41
+ - Kill: "Now let me fix that issue."
42
+ - Kill: "Let me check the tests."
43
+ - Kill: "I'll update the config next."
44
+ - Kill: "We need to update the schema first."
45
+ - Kill: "First, I'll read the file to understand the structure."
46
+ - Write: [tool call — no preamble]
47
+
48
+ **Banned action-narration openers** — these phrases before a tool call are always filler. Cut them 100% of the time:
49
+ - "Let me..." / "Now let me..." / "Now I'll..."
50
+ - "I'll..." / "I need to..." / "We need to..."
51
+ - "First, let me..." / "Next, I'll..."
52
+ - "Going to..." / "I'm going to..."
53
+ - "Time to..." / "Let's..."
54
+
55
+ If context is needed between tool calls, state the *finding* or *decision*, not the action:
56
+ - Kill: "Now let me update the handler to fix this."
57
+ - Write: "The handler is missing the null check." [edits file]
58
+ - Kill: "Let me run the tests to verify."
59
+ - Write: [runs tests]
42
60
 
43
61
  **Over-explaining the obvious** — don't describe trivial operations.
44
62
  - Kill: "I'll create a new file called `utils.ts`. This file will contain utility functions that we can reuse across the project."
@@ -1,10 +1,15 @@
1
1
  {
2
2
  "name": "terse",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "Professional output compression — proper grammar, no fluff, ~50-60% fewer tokens. Three levels: clean, tight, sharp.",
5
5
  "author": "iceinvein",
6
6
  "type": "prompt",
7
- "tools": ["claude", "cursor", "codex", "gemini"],
7
+ "tools": [
8
+ "claude",
9
+ "cursor",
10
+ "codex",
11
+ "gemini"
12
+ ],
8
13
  "files": {
9
14
  "prompt": "SKILL.md"
10
15
  },
@@ -22,5 +27,10 @@
22
27
  "gemini": {
23
28
  "prompt": ".gemini/skills/terse.md"
24
29
  }
30
+ },
31
+ "activation": {
32
+ "modes": ["session", "global"],
33
+ "default": "session",
34
+ "claudeHookDirective": "Activate terse skill at tight level for this session."
25
35
  }
26
36
  }