@youtyan/code-viewer 0.1.38 → 0.1.39

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
@@ -151,17 +151,18 @@ to target a specific one.
151
151
 
152
152
  ### Agent Skill
153
153
 
154
- The package bundles an [Agent Skill](https://code.claude.com/docs/en/skills)
155
- that teaches AI coding agents when and how to use `annotate`. Install it
156
- into the current project (`.claude/skills/`):
154
+ The package bundles an [Agent Skill](https://agentskills.io) (the SKILL.md
155
+ open standard) that teaches AI coding agents when and how to use
156
+ `annotate`. Install it into the current project:
157
157
 
158
158
  ```sh
159
- npx -y @youtyan/code-viewer skill install
159
+ npx -y @youtyan/code-viewer skill install # Claude Code (.claude/skills/)
160
+ npx -y @youtyan/code-viewer skill install --agent codex,gemini # other agents
161
+ npx -y @youtyan/code-viewer skill install --agent all # claude, codex, gemini, cursor, .agents
160
162
  ```
161
163
 
162
- Or install it once for all projects with `--global`
163
- (`~/.claude/skills/`). Running the same command again updates an existing
164
- installation.
164
+ Or install it once for all projects with `--global` (`~/.claude/skills/`
165
+ etc). Running the same command again updates an existing installation.
165
166
 
166
167
  ## Development
167
168
 
@@ -1652,11 +1652,28 @@ __export(exports_skill_cli, {
1652
1652
  runSkillCli: () => runSkillCli,
1653
1653
  parseSkillArgs: () => parseSkillArgs,
1654
1654
  installSkill: () => installSkill,
1655
- SKILL_HELP: () => SKILL_HELP
1655
+ SKILL_HELP: () => SKILL_HELP,
1656
+ AGENT_SKILL_DIRS: () => AGENT_SKILL_DIRS
1656
1657
  });
1657
1658
  import { cpSync, existsSync as existsSync5, mkdirSync as mkdirSync3 } from "node:fs";
1658
1659
  import { homedir as homedir2 } from "node:os";
1659
1660
  import { join as join5, resolve } from "node:path";
1661
+ function parseAgentList(value) {
1662
+ if (value === "all")
1663
+ return [...AGENT_NAMES];
1664
+ const names = value.split(",").map((name) => name.trim()).filter(Boolean);
1665
+ if (names.length === 0)
1666
+ return null;
1667
+ const result = [];
1668
+ for (const name of names) {
1669
+ if (!(name in AGENT_SKILL_DIRS))
1670
+ return null;
1671
+ const agent = name;
1672
+ if (!result.includes(agent))
1673
+ result.push(agent);
1674
+ }
1675
+ return result;
1676
+ }
1660
1677
  function parseSkillArgs(argv) {
1661
1678
  if (argv.length === 0 || argv.includes("--help") || argv[0] === "help") {
1662
1679
  return { ok: true, args: { kind: "help" } };
@@ -1667,6 +1684,7 @@ function parseSkillArgs(argv) {
1667
1684
  }
1668
1685
  let global = false;
1669
1686
  let cwd;
1687
+ let agents = ["claude"];
1670
1688
  for (let i = 0;i < rest.length; i++) {
1671
1689
  const arg = rest[i];
1672
1690
  if (arg === "--global") {
@@ -1675,11 +1693,23 @@ function parseSkillArgs(argv) {
1675
1693
  cwd = rest[++i];
1676
1694
  if (!cwd)
1677
1695
  return { ok: false, error: "--cwd requires a directory" };
1696
+ } else if (arg === "--agent") {
1697
+ const value = rest[++i];
1698
+ if (!value)
1699
+ return { ok: false, error: "--agent requires a list" };
1700
+ const parsed = parseAgentList(value);
1701
+ if (!parsed) {
1702
+ return {
1703
+ ok: false,
1704
+ error: `unknown agent in "${value}" (valid: ${AGENT_NAMES.join(", ")}, all)`
1705
+ };
1706
+ }
1707
+ agents = parsed;
1678
1708
  } else {
1679
1709
  return { ok: false, error: `unknown option: ${arg}` };
1680
1710
  }
1681
1711
  }
1682
- return { ok: true, args: { kind: "install", global, cwd } };
1712
+ return { ok: true, args: { kind: "install", agents, global, cwd } };
1683
1713
  }
1684
1714
  function installSkill(args, deps) {
1685
1715
  if (!existsSync5(join5(deps.sourceDir, "SKILL.md"))) {
@@ -1689,15 +1719,19 @@ function installSkill(args, deps) {
1689
1719
  };
1690
1720
  }
1691
1721
  const base = args.global ? deps.homeDir : resolve(args.cwd ?? deps.projectDir);
1692
- const target = join5(base, ".claude", "skills", SKILL_NAME);
1693
- const action = existsSync5(target) ? "updated" : "installed";
1694
- try {
1695
- mkdirSync3(target, { recursive: true });
1696
- cpSync(deps.sourceDir, target, { recursive: true });
1697
- } catch (error) {
1698
- return { ok: false, error: String(error) };
1722
+ const results = [];
1723
+ for (const agent of args.agents) {
1724
+ const target = join5(base, AGENT_SKILL_DIRS[agent], "skills", SKILL_NAME);
1725
+ const action = existsSync5(target) ? "updated" : "installed";
1726
+ try {
1727
+ mkdirSync3(target, { recursive: true });
1728
+ cpSync(deps.sourceDir, target, { recursive: true });
1729
+ } catch (error) {
1730
+ return { ok: false, error: String(error) };
1731
+ }
1732
+ results.push({ agent, action, target });
1699
1733
  }
1700
- return { ok: true, action, target };
1734
+ return { ok: true, results };
1701
1735
  }
1702
1736
  function runSkillCli(argv) {
1703
1737
  const parsed = parseSkillArgs(argv);
@@ -1719,27 +1753,44 @@ function runSkillCli(argv) {
1719
1753
  console.error(result.error);
1720
1754
  process.exit(1);
1721
1755
  }
1722
- console.log(`${result.action}: ${result.target}`);
1723
- if (result.action === "installed") {
1756
+ for (const entry of result.results) {
1757
+ console.log(`${entry.action} (${entry.agent}): ${entry.target}`);
1758
+ }
1759
+ if (result.results.some((entry) => entry.action === "installed")) {
1724
1760
  console.log("Re-run the same command anytime to update the skill.");
1725
1761
  }
1726
1762
  }
1727
- var SKILL_NAME = "code-viewer-annotate", SKILL_HELP;
1763
+ var SKILL_NAME = "code-viewer-annotate", AGENT_SKILL_DIRS, AGENT_NAMES, SKILL_HELP;
1728
1764
  var init_skill_cli = __esm(() => {
1729
1765
  init_root();
1766
+ AGENT_SKILL_DIRS = {
1767
+ claude: ".claude",
1768
+ codex: ".codex",
1769
+ gemini: ".gemini",
1770
+ cursor: ".cursor",
1771
+ agents: ".agents"
1772
+ };
1773
+ AGENT_NAMES = Object.keys(AGENT_SKILL_DIRS);
1730
1774
  SKILL_HELP = `code-viewer skill — manage the bundled agent skill
1731
1775
 
1732
1776
  Usage:
1733
- code-viewer skill install [--global] [--cwd <dir>]
1777
+ code-viewer skill install [--agent <list>] [--global] [--cwd <dir>]
1734
1778
 
1735
- Installs the ${SKILL_NAME} skill (SKILL.md for AI coding agents) into
1736
- .claude/skills/ of the current project, or into ~/.claude/skills/ with
1737
- --global. Running install again overwrites the files, so the same command
1738
- also updates an existing installation.
1779
+ Installs the ${SKILL_NAME} skill (SKILL.md for AI coding agents) into the
1780
+ skills directory of each selected agent in the current project, or into the
1781
+ home directory equivalents with --global. Running install again overwrites
1782
+ the files, so the same command also updates an existing installation.
1739
1783
 
1740
1784
  Options:
1741
- --global install into ~/.claude/skills/ instead of the project
1742
- --cwd <dir> project directory to install into (ignored with --global)
1785
+ --agent <list> comma separated agents: ${AGENT_NAMES.join(", ")}, or all
1786
+ (default: claude)
1787
+ --global install into the home directory (~/.claude/skills/ etc)
1788
+ --cwd <dir> project directory to install into (ignored with --global)
1789
+
1790
+ Examples:
1791
+ code-viewer skill install
1792
+ code-viewer skill install --agent claude,codex,gemini
1793
+ code-viewer skill install --agent all --global
1743
1794
  `;
1744
1795
  });
1745
1796
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@youtyan/code-viewer",
3
- "version": "0.1.38",
3
+ "version": "0.1.39",
4
4
  "description": "Local browser-based code and git diff viewer",
5
5
  "type": "module",
6
6
  "bin": {
package/web/app.js CHANGED
@@ -246,6 +246,8 @@
246
246
  allowPaletteOpen: true
247
247
  },
248
248
  { action: "focus-file-filter", key: "/" },
249
+ { action: "annotation-next", key: "]" },
250
+ { action: "annotation-previous", key: "[" },
249
251
  { action: "focus-sidebar", key: "h", ctrl: true },
250
252
  { action: "focus-main", key: "l", ctrl: true },
251
253
  {
@@ -7339,6 +7341,13 @@ ${frontmatter.yaml}
7339
7341
  sessionEl.className = "annotation-session";
7340
7342
  sessionEl.dataset.sessionId = session.id;
7341
7343
  sessionEl.classList.toggle("active", session.id === activeSessionId);
7344
+ sessionEl.addEventListener("click", (event) => {
7345
+ const target = event.target;
7346
+ if (target.closest("button, a, input"))
7347
+ return;
7348
+ if (session.id !== activeSessionId)
7349
+ setActiveSession(session.id);
7350
+ });
7342
7351
  const head = document.createElement("div");
7343
7352
  head.className = "annotation-session-head";
7344
7353
  const title = document.createElement("button");
@@ -7572,14 +7581,18 @@ ${frontmatter.yaml}
7572
7581
  deps.scrollDiffElementIntoView(inlineRow, "center");
7573
7582
  }
7574
7583
  function stepAnnotation(direction) {
7575
- if (!activeAnnotationId)
7584
+ const found = activeAnnotationId ? findAnnotation(activeAnnotationId) : null;
7585
+ if (found && (!activeSessionId || found.session.id === activeSessionId)) {
7586
+ const next = found.session.entries[found.index + direction];
7587
+ if (next)
7588
+ openAnnotationEntry(next.id);
7576
7589
  return;
7577
- const found = findAnnotation(activeAnnotationId);
7578
- if (!found)
7579
- return;
7580
- const next = found.session.entries[found.index + direction];
7581
- if (next)
7582
- openAnnotationEntry(next.id);
7590
+ }
7591
+ const session = ANNOTATIONS.sessions.find((s2) => s2.id === activeSessionId) ?? ANNOTATIONS.sessions[0];
7592
+ const entries = session?.entries ?? [];
7593
+ const entry = direction === 1 ? entries[0] : entries[entries.length - 1];
7594
+ if (entry)
7595
+ openAnnotationEntry(entry.id);
7583
7596
  }
7584
7597
  function handleSse(raw) {
7585
7598
  let event = null;
@@ -7650,7 +7663,8 @@ ${frontmatter.yaml}
7650
7663
  },
7651
7664
  getActiveAnnotationId() {
7652
7665
  return activeAnnotationId;
7653
- }
7666
+ },
7667
+ stepAnnotation
7654
7668
  };
7655
7669
  }
7656
7670
 
@@ -8794,7 +8808,8 @@ ${frontmatter.yaml}
8794
8808
  ["Ctrl+K", "Open file palette"],
8795
8809
  ["Ctrl+G", "Open grep palette"],
8796
8810
  ["/", "Focus file filter"],
8797
- ["t", "Toggle theme"]
8811
+ ["t", "Toggle theme"],
8812
+ ["[ / ]", "Previous / next annotation"]
8798
8813
  ]
8799
8814
  },
8800
8815
  {
@@ -8842,7 +8857,8 @@ ${frontmatter.yaml}
8842
8857
  ["Ctrl+K", "ファイルパレットを開く"],
8843
8858
  ["Ctrl+G", "grep パレットを開く"],
8844
8859
  ["/", "ファイルフィルターへフォーカス"],
8845
- ["t", "テーマ切り替え"]
8860
+ ["t", "テーマ切り替え"],
8861
+ ["[ / ]", "前 / 次の注釈へ移動"]
8846
8862
  ]
8847
8863
  },
8848
8864
  {
@@ -15631,6 +15647,10 @@ ${frontmatter.yaml}
15631
15647
  if (action === "tab-preview" || action === "tab-code") {
15632
15648
  return switchSourceTab(action === "tab-preview" ? "preview" : "code");
15633
15649
  }
15650
+ if (action === "annotation-next" || action === "annotation-previous") {
15651
+ ANNOTATIONS_UI?.stepAnnotation(action === "annotation-next" ? 1 : -1);
15652
+ return true;
15653
+ }
15634
15654
  if (action === "start-g-sequence") {
15635
15655
  PENDING_G_SCOPE = scope;
15636
15656
  PENDING_G_UNTIL = performance.now() + 900;
package/web/style.css CHANGED
@@ -1132,7 +1132,8 @@ body.gdp-resizing * { user-select: none !important; }
1132
1132
  top: calc(var(--global-header-h) + 8px);
1133
1133
  width: min(460px, calc(100vw - 32px));
1134
1134
  max-width: calc(100vw - 32px);
1135
- z-index: 40;
1135
+ /* Transient popover: must sit above the annotation panel (45). */
1136
+ z-index: 70;
1136
1137
  padding: 12px;
1137
1138
  border: 1px solid var(--border);
1138
1139
  border-radius: 8px;