@clipit-ai/cli 0.2.2 → 0.2.3

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 (2) hide show
  1. package/bin/clipit.mjs +45 -9
  2. package/package.json +1 -1
package/bin/clipit.mjs CHANGED
@@ -9,7 +9,7 @@ import path from 'node:path';
9
9
  import process from 'node:process';
10
10
  import { fileURLToPath } from 'node:url';
11
11
 
12
- const VERSION = '0.2.2';
12
+ const VERSION = '0.2.3';
13
13
  const DEFAULT_BASE_URL = 'https://clipit.dev';
14
14
  const DEFAULT_SCOPES = [
15
15
  'clippy_agent',
@@ -1825,25 +1825,61 @@ async function jobs(config, options, action, args) {
1825
1825
  }
1826
1826
  }
1827
1827
 
1828
- function appUrl(config, options, kind, id) {
1828
+ async function appUrl(config, options, kind, id) {
1829
1829
  const baseUrl = getBaseUrl(config, options);
1830
1830
  if (!kind || kind === 'home') return baseUrl;
1831
1831
  if (kind === 'settings') return `${baseUrl}/settings?tab=${encodeURIComponent(options.tab || 'api-keys')}`;
1832
1832
  if (kind === 'dashboard') return `${baseUrl}/dashboard`;
1833
1833
  if (kind === 'library') return `${baseUrl}/clips`;
1834
- if (kind === 'editor') return `${baseUrl}/editor`;
1834
+ if (kind === 'editor') {
1835
+ // The editor reads ?project=, ?video=, ?clip= (VideoEditorPage). Thread any
1836
+ // provided context so `open editor --video <id>` lands on real content rather
1837
+ // than the empty "select a video" state.
1838
+ const params = new URLSearchParams();
1839
+ const project = id || options.project || null;
1840
+ if (project) params.set('project', project);
1841
+ if (options.video || options.videoId) params.set('video', options.video || options.videoId);
1842
+ if (options.clip || options.clipId) params.set('clip', options.clip || options.clipId);
1843
+ const qs = params.toString();
1844
+ return `${baseUrl}/editor${qs ? `?${qs}` : ''}`;
1845
+ }
1835
1846
  if (kind === 'pricing') return `${baseUrl}/pricing`;
1836
1847
  if (kind === 'credits') return `${baseUrl}/settings/credits`;
1837
- if (kind === 'clip') return `${baseUrl}/clips/review${id ? `?clipId=${encodeURIComponent(id)}` : ''}`;
1838
- if (kind === 'video') return `${baseUrl}/clips${id ? `?videoId=${encodeURIComponent(id)}` : ''}`;
1839
- if (kind === 'project') return `${baseUrl}/editor/projects${id ? `?projectId=${encodeURIComponent(id)}` : ''}`;
1840
- if (kind === 'sequence') return `${baseUrl}/editor/projects${id ? `?sequenceId=${encodeURIComponent(id)}` : ''}`;
1848
+ if (kind === 'clip') {
1849
+ // A clip lives inside a video. The Clips Review page keys off ?video=<videoId>
1850
+ // without it the page renders "No video selected", so a bare clip link
1851
+ // dead-ends. Resolve the clip's parent video so the link lands on the clip,
1852
+ // selected. ?clip=<clipId> focuses it (the page reads `clip`, not `clipId`).
1853
+ if (!id) return `${baseUrl}/clips/review`;
1854
+ let videoId = options.video || options.videoId || null;
1855
+ if (!videoId) {
1856
+ try {
1857
+ const clip = await apiFetch(config, options, 'GET', `/api/v1/clips/${encodeURIComponent(id)}`);
1858
+ videoId = clip?.videoId || clip?.video?.id || null;
1859
+ } catch {
1860
+ // Network/auth/not-found — fall through to a clip-only link below.
1861
+ }
1862
+ }
1863
+ const params = new URLSearchParams();
1864
+ if (videoId) params.set('video', videoId);
1865
+ params.set('clip', id);
1866
+ return `${baseUrl}/clips/review?${params.toString()}`;
1867
+ }
1868
+ // A video link should open that video's clips in the Review page (which keys
1869
+ // off ?video=), not the generic /clips library list which has no selection.
1870
+ if (kind === 'video') return `${baseUrl}/clips/review${id ? `?video=${encodeURIComponent(id)}` : ''}`;
1871
+ // The editor lives at /editor and reads ?project= (NOT /editor/projects, which
1872
+ // redirects to /clips and drops the query — the same dead-end class as the
1873
+ // clip/video link bug). There is no surface that consumes a raw sequenceId, so
1874
+ // a sequence link just opens the editor.
1875
+ if (kind === 'project') return `${baseUrl}/editor${id ? `?project=${encodeURIComponent(id)}` : ''}`;
1876
+ if (kind === 'sequence') return `${baseUrl}/editor`;
1841
1877
  if (kind === 'route') return `${baseUrl}/${String(id || '').replace(/^\/+/, '')}`;
1842
1878
  return baseUrl;
1843
1879
  }
1844
1880
 
1845
1881
  async function openCommand(config, options, kind, id) {
1846
- const url = appUrl(config, options, kind, id);
1882
+ const url = await appUrl(config, options, kind, id);
1847
1883
  if (options.print) {
1848
1884
  output(url, options);
1849
1885
  return;
@@ -1856,7 +1892,7 @@ async function links(config, options, kind, id) {
1856
1892
  const result = {
1857
1893
  kind: kind || 'home',
1858
1894
  id: id || null,
1859
- appUrl: appUrl(config, options, kind, id),
1895
+ appUrl: await appUrl(config, options, kind, id),
1860
1896
  };
1861
1897
  if (kind === 'clip' && id && boolOption(options.download)) {
1862
1898
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clipit-ai/cli",
3
- "version": "0.2.2",
3
+ "version": "0.2.3",
4
4
  "description": "ClipIt CLI for connecting shell-capable agents to ClipIt.",
5
5
  "type": "module",
6
6
  "bin": {