@stacknet/rackutils 0.1.0
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 +107 -0
- package/dist/components/index.cjs +10 -0
- package/dist/components/index.d.cts +19 -0
- package/dist/components/index.d.ts +19 -0
- package/dist/components/index.js +10 -0
- package/dist/hooks/index.cjs +1 -0
- package/dist/hooks/index.d.cts +54 -0
- package/dist/hooks/index.d.ts +54 -0
- package/dist/hooks/index.js +1 -0
- package/dist/index.cjs +10 -0
- package/dist/index.d.cts +5 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +10 -0
- package/dist/types/index.cjs +1 -0
- package/dist/types/index.d.cts +62 -0
- package/dist/types/index.d.ts +62 -0
- package/dist/types/index.js +0 -0
- package/package.json +59 -0
package/README.md
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# @stacknet/rackutils
|
|
2
|
+
|
|
3
|
+
React hooks and components for reading and writing StackNet Racks — a decentralized VCS backed by IPFS.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add @stacknet/rackutils
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Peer dependencies: `react >= 18`, `react-dom >= 18`
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
```tsx
|
|
16
|
+
import { RackBrowser } from '@stacknet/rackutils/components';
|
|
17
|
+
|
|
18
|
+
<RackBrowser
|
|
19
|
+
config={{ apiBaseUrl: '' }}
|
|
20
|
+
className="h-[600px]"
|
|
21
|
+
/>
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Hooks
|
|
25
|
+
|
|
26
|
+
```tsx
|
|
27
|
+
import { useRepos, useRepoTree, useRepoPush, useRackClient } from '@stacknet/rackutils/hooks';
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### `useRepos(config)`
|
|
31
|
+
List repositories.
|
|
32
|
+
|
|
33
|
+
```tsx
|
|
34
|
+
const { repos, loading, error, refresh } = useRepos({ apiBaseUrl: '' });
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### `useRepoTree(config, repoId, ref?)`
|
|
38
|
+
Get the file tree for a repo at a given ref (branch/commit).
|
|
39
|
+
|
|
40
|
+
```tsx
|
|
41
|
+
const { entries, loading, getFileContent } = useRepoTree(config, repoId, 'main');
|
|
42
|
+
// entries: TreeEntry[] — { path, mode, cid, isDir }
|
|
43
|
+
// getFileContent(cid) → Promise<string>
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### `useRepoPush(config)`
|
|
47
|
+
Push files to a repository.
|
|
48
|
+
|
|
49
|
+
```tsx
|
|
50
|
+
const { push, pushing, error } = useRepoPush(config);
|
|
51
|
+
|
|
52
|
+
await push(repoId, [
|
|
53
|
+
{ path: 'SKILL.md', content: '# My Skill\n...' },
|
|
54
|
+
{ path: 'agent.yaml', content: 'name: my-agent\n...' },
|
|
55
|
+
], 'Update skill definition');
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### `useRackClient(config)`
|
|
59
|
+
Low-level client with all Rack API operations.
|
|
60
|
+
|
|
61
|
+
```tsx
|
|
62
|
+
const client = useRackClient(config);
|
|
63
|
+
await client.initRepo({ name: 'my-skill', is_gitagent: true });
|
|
64
|
+
await client.getBranches(repoId);
|
|
65
|
+
await client.getDiff(repoId, 'main', 'feature');
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Components
|
|
69
|
+
|
|
70
|
+
### `RackBrowser`
|
|
71
|
+
Full file browser with repo list, file tree, and content viewer.
|
|
72
|
+
|
|
73
|
+
```tsx
|
|
74
|
+
<RackBrowser
|
|
75
|
+
config={{
|
|
76
|
+
apiBaseUrl: '', // same-origin proxy
|
|
77
|
+
ownerMid: 'mid-123', // filter by owner
|
|
78
|
+
authorMid: 'mid-123', // for write operations
|
|
79
|
+
}}
|
|
80
|
+
category="skills" // optional category filter
|
|
81
|
+
className="h-[600px]"
|
|
82
|
+
/>
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## API Proxy
|
|
86
|
+
|
|
87
|
+
The hooks expect a proxy at `/api/rack/*` that forwards to StackNet's `/cpx/rack/*`:
|
|
88
|
+
|
|
89
|
+
| Widget Route | StackNet Route |
|
|
90
|
+
|-------------|----------------|
|
|
91
|
+
| `/api/rack/repos` | `/cpx/rack/repos` |
|
|
92
|
+
| `/api/rack/init` | `/cpx/rack/init` |
|
|
93
|
+
| `/api/rack/:id/push` | `/cpx/rack/:id/push` |
|
|
94
|
+
| `/api/rack/:id/tree/:ref` | `/cpx/rack/:id/tree/:ref` |
|
|
95
|
+
| `/api/rack/:id/blob/:cid` | `/cpx/rack/:id/blob/:cid` |
|
|
96
|
+
| `/api/rack/:id/log` | `/cpx/rack/:id/log` |
|
|
97
|
+
| `/api/rack/:id/branches` | `/cpx/rack/:id/branches` |
|
|
98
|
+
|
|
99
|
+
## Types
|
|
100
|
+
|
|
101
|
+
```tsx
|
|
102
|
+
import type { RepoInfo, RepoCommit, RepoTree, TreeEntry, RepoFile, RackConfig } from '@stacknet/rackutils/types';
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## License
|
|
106
|
+
|
|
107
|
+
MIT
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
'use strict';var react=require('react'),lucideReact=require('lucide-react'),clsx=require('clsx'),tailwindMerge=require('tailwind-merge'),jsxRuntime=require('react/jsx-runtime');function R(...n){return tailwindMerge.twMerge(clsx.clsx(n))}async function T(n,e,s){let r=await fetch(`${n}${e}`,{...s,headers:{"Content-Type":"application/json",...s?.headers}});if(!r.ok){let o=`HTTP ${r.status}`;try{let a=await r.json();a.error&&(o=a.error);}catch{}throw new Error(o)}return r.json()}function S(n){let e=n.apiBaseUrl,s=n.authorMid,r=n.ownerMid;return react.useMemo(()=>({async listRepos(o){let a=o||r?`?owner=${encodeURIComponent(o||r)}`:"";return (await T(e,`/api/rack/repos${a}`)).repos||[]},async initRepo(o){return T(e,"/api/rack/init",{method:"POST",body:JSON.stringify({...o,owner_mid:r})})},async push(o,a){return T(e,`/api/rack/${o}/push`,{method:"POST",body:JSON.stringify({...a,author_mid:s})})},async getTree(o,a="main"){let i=await T(e,`/api/rack/${o}/tree/${a}`);return {tree:i.tree,commit_cid:i.commit_cid}},async getBlob(o,a){return (await T(e,`/api/rack/${o}/blob/${a}`)).content},async getLog(o,a,i){let l=new URLSearchParams;a&&l.set("ref",a),i&&l.set("max_count",String(i));let m=l.toString()?`?${l}`:"";return (await T(e,`/api/rack/${o}/log${m}`)).commits||[]},async getBranches(o){return (await T(e,`/api/rack/${o}/branches`)).branches||[]},async getDiff(o,a,i){return (await T(e,`/api/rack/${o}/diff/${a}/${i}`)).diff?.entries||[]}}),[e,s,r])}function Z(n){let e=S(n),s=react.useRef(e);s.current=e;let[r,o]=react.useState([]),[a,i]=react.useState(true),[l,m]=react.useState(null),p=react.useRef(true),f=react.useRef(null),x=react.useCallback(async()=>{f.current?.abort();let u=new AbortController;f.current=u;try{p.current&&(i(!0),m(null));let d=await s.current.listRepos();p.current&&!u.signal.aborted&&o(d);}catch(d){p.current&&!u.signal.aborted&&m(d instanceof Error?d.message:"Failed to load repos");}finally{p.current&&!u.signal.aborted&&i(false);}},[]);return react.useEffect(()=>(p.current=true,x(),()=>{p.current=false,f.current?.abort();}),[x]),{repos:r,loading:a,error:l,refresh:x}}function fe(n){return Object.entries(n).map(([e,s])=>{let r=s.indexOf(":"),o=r>0?s.slice(0,r):"100644",a=r>0?s.slice(r+1):s;return {path:e,mode:o,cid:a,isDir:o==="040000"}}).sort((e,s)=>e.isDir!==s.isDir?e.isDir?-1:1:e.path.localeCompare(s.path))}function J(n,e,s="main"){let r=S(n),[o,a]=react.useState([]),[i,l]=react.useState(false),[m,p]=react.useState(null),f=react.useRef(true),x=react.useCallback(async()=>{if(e)try{f.current&&(l(!0),p(null));let{tree:d}=await r.getTree(e,s);f.current&&a(fe(d.entries));}catch(d){f.current&&p(d instanceof Error?d.message:"Failed to load tree");}finally{f.current&&l(false);}},[r,e,s]);react.useEffect(()=>(f.current=true,x(),()=>{f.current=false;}),[x]);let u=react.useCallback(async d=>{if(!e)throw new Error("No repo selected");return r.getBlob(e,d)},[r,e]);return {entries:o,loading:i,error:m,refresh:x,getFileContent:u}}var pe=/^(https?:\/\/|mailto:|\/[^/])/i;function ge(n){let e=n.trim();return pe.test(e)?e:null}function I(n){let e=[],s=/(`[^`]+`)|(\*\*(.+?)\*\*)|(\*(.+?)\*)|(_(.+?)_)|(\[([^\]]+)\]\(([^)]+)\))/g,r=0,o,a=0;for(;(o=s.exec(n))!==null;){o.index>r&&e.push(n.slice(r,o.index));let i=`i${a++}`;if(o[1])e.push(jsxRuntime.jsx("code",{className:"rounded bg-muted px-1.5 py-0.5 text-[0.85em] font-mono text-pink-400",children:o[1].slice(1,-1)},i));else if(o[2])e.push(jsxRuntime.jsx("strong",{children:o[3]},i));else if(o[4])e.push(jsxRuntime.jsx("em",{children:o[5]},i));else if(o[6])e.push(jsxRuntime.jsx("em",{children:o[7]},i));else if(o[8]){let l=ge(o[10]);l?e.push(jsxRuntime.jsx("a",{href:l,className:"text-blue-400 underline hover:text-blue-300",target:"_blank",rel:"noopener noreferrer",children:o[9]},i)):e.push(o[9]);}r=o.index+o[0].length;}return r<n.length&&e.push(n.slice(r)),e.length>0?e:[n]}function he(n){let e=n.split(`
|
|
2
|
+
`),s=[],r=0;for(;r<e.length;){let o=e[r];if(o.trim()===""){r++;continue}if(/^(-{3,}|\*{3,}|_{3,})$/.test(o.trim())){s.push({type:"hr"}),r++;continue}let a=o.match(/^(#{1,6})\s+(.+)/);if(a){s.push({type:"heading",level:a[1].length,content:a[2]}),r++;continue}if(o.trim().startsWith("```")){let l=o.trim().slice(3).trim(),m=[];for(r++;r<e.length&&!e[r].trim().startsWith("```");)m.push(e[r]),r++;s.push({type:"code",content:m.join(`
|
|
3
|
+
`),lang:l||void 0}),r++;continue}if(/^\s*[-*+]\s/.test(o)){let l=[];for(;r<e.length&&/^\s*[-*+]\s/.test(e[r]);)l.push(e[r].replace(/^\s*[-*+]\s+/,"")),r++;s.push({type:"ul",items:l});continue}if(/^\s*\d+[.)]\s/.test(o)){let l=[];for(;r<e.length&&/^\s*\d+[.)]\s/.test(e[r]);)l.push(e[r].replace(/^\s*\d+[.)]\s+/,"")),r++;s.push({type:"ol",items:l});continue}let i=[];for(;r<e.length&&e[r].trim()!==""&&!e[r].match(/^#{1,6}\s/)&&!e[r].trim().startsWith("```")&&!/^\s*[-*+]\s/.test(e[r])&&!/^\s*\d+[.)]\s/.test(e[r]);)i.push(e[r]),r++;i.length>0&&s.push({type:"paragraph",content:i.join(" ")});}return s}var xe={1:"text-2xl font-bold mt-6 mb-3",2:"text-xl font-bold mt-5 mb-2",3:"text-lg font-semibold mt-4 mb-2",4:"text-base font-semibold mt-3 mb-1",5:"text-sm font-semibold mt-2 mb-1",6:"text-sm font-medium mt-2 mb-1"};function ve(n,e){switch(n.type){case "hr":return jsxRuntime.jsx("hr",{className:"my-4 border-border"},`b${e}`);case "heading":{let s=Math.min(Math.max(n.level||1,1),6),r=`h${s}`;return jsxRuntime.jsx(r,{className:R("text-foreground",xe[s]),children:I(n.content||"")},`b${e}`)}case "paragraph":return jsxRuntime.jsx("p",{className:"mb-3 leading-relaxed text-foreground",children:I(n.content||"")},`b${e}`);case "code":return jsxRuntime.jsx("pre",{className:"mb-3 overflow-x-auto rounded-lg bg-muted p-4 text-sm font-mono leading-relaxed text-foreground",children:jsxRuntime.jsx("code",{children:n.content})},`b${e}`);case "ul":return jsxRuntime.jsx("ul",{className:"mb-3 ml-5 list-disc space-y-1 text-foreground",children:n.items?.map((s,r)=>jsxRuntime.jsx("li",{className:"leading-relaxed",children:I(s)},`li${e}-${r}`))},`b${e}`);case "ol":return jsxRuntime.jsx("ol",{className:"mb-3 ml-5 list-decimal space-y-1 text-foreground",children:n.items?.map((s,r)=>jsxRuntime.jsx("li",{className:"leading-relaxed",children:I(s)},`li${e}-${r}`))},`b${e}`);default:return null}}function B({content:n,className:e}){let s=he(n);return jsxRuntime.jsx("div",{className:R("text-sm",e),children:s.map((r,o)=>ve(r,o))})}function Q({open:n,className:e}){return jsxRuntime.jsx("svg",{width:"16",height:"16",viewBox:"0 0 20 20",fill:"currentColor",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",className:R("shrink-0 transition-transform duration-150",n?"rotate-0":"-rotate-90",e),children:jsxRuntime.jsx("path",{d:"M16.134 6.16a.5.5 0 1 1 .732.68l-6.5 7-.077.068a.5.5 0 0 1-.655-.068l-6.5-7-.062-.08a.5.5 0 0 1 .718-.667l.076.067L10 12.767z"})})}function q({size:n=20,className:e}){return jsxRuntime.jsx("svg",{width:n,height:n,viewBox:"0 0 20 20",fill:"currentColor",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",className:e,children:jsxRuntime.jsx("path",{d:"M8.5 2a6.5 6.5 0 0 1 4.935 10.728l4.419 4.419.064.078a.5.5 0 0 1-.693.693l-.079-.064-4.419-4.42A6.5 6.5 0 1 1 8.5 2m0 1a5.5 5.5 0 1 0 0 11 5.5 5.5 0 0 0 0-11"})})}function D({size:n=20,className:e}){return jsxRuntime.jsx("svg",{width:n,height:n,viewBox:"0 0 20 20",fill:"currentColor",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",className:e,children:jsxRuntime.jsx("path",{d:"M15.147 4.146a.5.5 0 0 1 .707.707L10.707 10l5.147 5.147a.5.5 0 0 1-.63.771l-.078-.064L10 10.707l-5.146 5.147a.5.5 0 0 1-.708-.707L9.293 10 4.146 4.853a.5.5 0 0 1 .708-.707L10 9.293z"})})}function Y({size:n=20,className:e}){return jsxRuntime.jsx("svg",{width:n,height:n,viewBox:"0 0 20 20",fill:"currentColor",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",className:e,children:jsxRuntime.jsx("path",{d:"M10 3a.5.5 0 0 1 .5.5v6h6l.1.01a.5.5 0 0 1 0 .98l-.1.01h-6v6a.5.5 0 0 1-1 0v-6h-6a.5.5 0 0 1 0-1h6v-6A.5.5 0 0 1 10 3"})})}function ye(){return jsxRuntime.jsx("svg",{width:"20",height:"20",viewBox:"0 0 20 20",fill:"currentColor",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",className:"shrink-0",children:jsxRuntime.jsx("path",{d:"M6.5 3A2.5 2.5 0 0 0 4 5.5v9A2.5 2.5 0 0 0 6.5 17h7a2.5 2.5 0 0 0 2.5-2.5v-7A2.5 2.5 0 0 0 13.5 5H11V3.5a.5.5 0 0 0-1 0V5H6.5ZM5 5.5A1.5 1.5 0 0 1 6.5 4H9v1H6.5A1.5 1.5 0 0 0 5 6.5v8A1.5 1.5 0 0 0 6.5 16h7a1.5 1.5 0 0 0 1.5-1.5v-7A1.5 1.5 0 0 0 13.5 6H11V4h2.5A2.5 2.5 0 0 1 16 6.5v8a2.5 2.5 0 0 1-2.5 2.5h-7A2.5 2.5 0 0 1 4 14.5v-9Z"})})}function ke(){return jsxRuntime.jsx("svg",{width:"20",height:"20",viewBox:"0 0 20 20",fill:"currentColor",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",className:"shrink-0",children:jsxRuntime.jsx("path",{d:"M5.5 3A2.5 2.5 0 0 0 3 5.5v9A2.5 2.5 0 0 0 5.5 17h9a2.5 2.5 0 0 0 2.5-2.5v-9A2.5 2.5 0 0 0 14.5 3h-9ZM4 5.5A1.5 1.5 0 0 1 5.5 4h9A1.5 1.5 0 0 1 16 5.5v9a1.5 1.5 0 0 1-1.5 1.5h-9A1.5 1.5 0 0 1 4 14.5v-9ZM7 7.5a.5.5 0 0 1 .5-.5h5a.5.5 0 0 1 0 1h-5a.5.5 0 0 1-.5-.5Zm0 3a.5.5 0 0 1 .5-.5h5a.5.5 0 0 1 0 1h-5a.5.5 0 0 1-.5-.5Zm0 3a.5.5 0 0 1 .5-.5h3a.5.5 0 0 1 0 1h-3a.5.5 0 0 1-.5-.5Z"})})}function Ne(){return jsxRuntime.jsx("svg",{width:"20",height:"20",viewBox:"0 0 20 20",fill:"currentColor",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",className:"shrink-0",children:jsxRuntime.jsx("path",{d:"M10 2a.5.5 0 0 1 .354.146l3 3a.5.5 0 0 1-.708.708L10.5 3.707V12.5a.5.5 0 0 1-1 0V3.707L7.354 5.854a.5.5 0 1 1-.708-.708l3-3A.5.5 0 0 1 10 2ZM4 13.5a.5.5 0 0 1 1 0v1A1.5 1.5 0 0 0 6.5 16h7a1.5 1.5 0 0 0 1.5-1.5v-1a.5.5 0 0 1 1 0v1a2.5 2.5 0 0 1-2.5 2.5h-7A2.5 2.5 0 0 1 4 14.5v-1Z"})})}function X(){let[n,e]=react.useState(false);return react.useEffect(()=>{if(typeof window>"u")return;let s=()=>e(window.innerWidth<768);return s(),window.addEventListener("resize",s),()=>window.removeEventListener("resize",s)},[]),n}function ee({onClose:n,children:e,title:s}){let r=X(),o=react.useRef(n);return o.current=n,react.useEffect(()=>{let a=i=>{i.key==="Escape"&&o.current();};return window.addEventListener("keydown",a),()=>window.removeEventListener("keydown",a)},[]),r?jsxRuntime.jsxs("div",{className:"fixed inset-0 z-50 flex items-end justify-center",onClick:n,children:[jsxRuntime.jsx("div",{className:"fixed inset-0 bg-black/50"}),jsxRuntime.jsxs("div",{className:"relative z-10 w-full max-h-[90vh] overflow-y-auto rounded-t-2xl bg-[#1a1a1a] p-5 pb-8 animate-in slide-in-from-bottom duration-200",onClick:a=>a.stopPropagation(),children:[jsxRuntime.jsx("div",{className:"mx-auto mb-4 h-1 w-10 rounded-full bg-zinc-600"}),jsxRuntime.jsxs("div",{className:"flex items-center justify-between mb-5",children:[jsxRuntime.jsx("h2",{className:"text-lg font-semibold text-foreground",children:s}),jsxRuntime.jsx("button",{onClick:n,className:"rounded p-1 text-muted-foreground hover:text-foreground",children:jsxRuntime.jsx(D,{size:20})})]}),e]})]}):jsxRuntime.jsxs("div",{className:"fixed inset-0 z-50 flex items-center justify-center",onClick:n,children:[jsxRuntime.jsx("div",{className:"fixed inset-0 bg-black/50"}),jsxRuntime.jsxs("div",{className:"relative z-10 w-full max-w-lg overflow-y-auto rounded-2xl bg-[#1a1a1a] p-6 shadow-2xl animate-in fade-in zoom-in-95 duration-150",onClick:a=>a.stopPropagation(),children:[jsxRuntime.jsxs("div",{className:"flex items-center justify-between mb-5",children:[jsxRuntime.jsx("h2",{className:"text-lg font-semibold text-foreground",children:s}),jsxRuntime.jsx("button",{onClick:n,className:"rounded p-1 text-muted-foreground hover:text-foreground",children:jsxRuntime.jsx(D,{size:20})})]}),e]})]})}function Re({onClose:n,onCreated:e,config:s}){let[r,o]=react.useState(""),[a,i]=react.useState(""),[l,m]=react.useState(""),[p,f]=react.useState(false),[x,u]=react.useState(null);return jsxRuntime.jsx(ee,{title:"Write skill instructions",onClose:n,children:jsxRuntime.jsxs("div",{className:"space-y-4",children:[jsxRuntime.jsxs("div",{className:"space-y-1.5",children:[jsxRuntime.jsx("label",{htmlFor:"skill-name",className:"text-sm text-muted-foreground",children:"Skill name"}),jsxRuntime.jsx("input",{id:"skill-name",value:r,onChange:v=>o(v.target.value),placeholder:"weekly-status-report",className:"w-full rounded-lg border border-zinc-700 bg-[#252525] px-3 py-2.5 text-sm text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-zinc-500"})]}),jsxRuntime.jsxs("div",{className:"space-y-1.5",children:[jsxRuntime.jsx("label",{htmlFor:"skill-desc",className:"text-sm text-muted-foreground",children:"Description"}),jsxRuntime.jsx("textarea",{id:"skill-desc",value:a,onChange:v=>i(v.target.value),placeholder:"Generate weekly status reports from recent work.",rows:3,className:"w-full rounded-lg border border-zinc-700 bg-[#252525] px-3 py-2.5 text-sm text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-zinc-500"})]}),jsxRuntime.jsxs("div",{className:"space-y-1.5",children:[jsxRuntime.jsx("label",{htmlFor:"skill-instructions",className:"text-sm text-muted-foreground",children:"Instructions"}),jsxRuntime.jsx("textarea",{id:"skill-instructions",value:l,onChange:v=>m(v.target.value),placeholder:"Summarize my recent work in three sections: wins, blockers, and next steps.",rows:8,className:"w-full rounded-lg border border-zinc-700 bg-[#252525] px-3 py-2.5 text-sm text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-zinc-500"})]}),x&&jsxRuntime.jsx("p",{className:"text-sm text-red-500",children:x}),jsxRuntime.jsxs("div",{className:"flex justify-end gap-3 pt-2",children:[jsxRuntime.jsx("button",{onClick:n,className:"rounded-lg border border-zinc-700 px-4 py-2 text-sm text-foreground hover:bg-zinc-800",children:"Cancel"}),jsxRuntime.jsx("button",{onClick:async()=>{if(r.trim()){f(true),u(null);try{let v=s.apiBaseUrl||"",N=await fetch(`${v}/api/rack/init`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:r.trim(),description:a.trim(),owner_mid:s.ownerMid,is_gitagent:!0})});if(!N.ok){let b=`Failed to create skill (${N.status})`;try{let y=await N.json();y.error&&(b=y.error);}catch{}throw new Error(b)}let{repo_id:E}=await N.json(),z=`# ${r.trim()}
|
|
4
|
+
|
|
5
|
+
${a.trim()}
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
${l.trim()}`,k=await fetch(`${v}/api/rack/${E}/push`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({files:[{path:"SKILL.md",content:z}],message:"Initial skill definition",author_mid:s.authorMid})});if(!k.ok){let b=`Failed to save skill (${k.status})`;try{let y=await k.json();y.error&&(b=y.error);}catch{}throw new Error(b)}e?.(),n();}catch(v){u(v instanceof Error?v.message:"Failed to create skill");}finally{f(false);}}},disabled:p||!r.trim(),className:"rounded-lg bg-zinc-600 px-4 py-2 text-sm font-medium text-white hover:bg-zinc-500 disabled:opacity-50",children:p?"Creating...":"Create"})]})]})})}function Ce({onClose:n,onCreated:e,config:s}){let r=react.useRef(null),[o,a]=react.useState(false),[i,l]=react.useState(false),[m,p]=react.useState(null),f=async u=>{l(true),p(null);try{let d=await u.text(),v=s.apiBaseUrl||"",N=u.name.replace(/\.[^.]+$/,"").replace(/[^a-zA-Z0-9-_]/g,"-"),E=await fetch(`${v}/api/rack/init`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:N,owner_mid:s.ownerMid,is_gitagent:!0})});if(!E.ok){let b=`Failed to create repo (${E.status})`;try{let y=await E.json();y.error&&(b=y.error);}catch{}throw new Error(b)}let{repo_id:z}=await E.json(),k=await fetch(`${v}/api/rack/${z}/push`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({files:[{path:u.name,content:d}],message:`Upload ${u.name}`,author_mid:s.authorMid})});if(!k.ok){let b=`Upload failed (${k.status})`;try{let y=await k.json();y.error&&(b=y.error);}catch{}throw new Error(b)}e?.(),n();}catch(d){p(d instanceof Error?d.message:"Upload failed");}finally{l(false);}};return jsxRuntime.jsx(ee,{title:"Upload skill",onClose:n,children:jsxRuntime.jsxs("div",{className:"space-y-4",children:[jsxRuntime.jsxs("div",{onDragOver:u=>{u.preventDefault(),a(true);},onDragLeave:()=>a(false),onDrop:u=>{u.preventDefault(),a(false);let d=u.dataTransfer.files[0];d&&f(d);},onClick:()=>r.current?.click(),className:R("flex cursor-pointer flex-col items-center justify-center gap-3 rounded-xl border-2 border-dashed p-10 transition-colors",o?"border-zinc-400 bg-zinc-800/50":"border-zinc-700 hover:border-zinc-500"),children:[jsxRuntime.jsx("div",{className:"rounded-lg border border-zinc-600 p-2",children:jsxRuntime.jsx(Y,{size:20,className:"text-muted-foreground"})}),jsxRuntime.jsx("p",{className:"text-sm text-muted-foreground",children:i?"Uploading...":"Drag and drop or click to upload"})]}),jsxRuntime.jsx("input",{ref:r,type:"file",accept:".md,.zip,.skill,.txt,.yml,.yaml",className:"hidden","aria-label":"Upload skill file",onChange:u=>{let d=u.target.files?.[0];d&&f(d);}}),m&&jsxRuntime.jsx("p",{className:"text-sm text-red-500",children:m}),jsxRuntime.jsxs("div",{className:"space-y-2 text-xs text-muted-foreground",children:[jsxRuntime.jsx("p",{className:"font-medium text-foreground/70",children:"File requirements"}),jsxRuntime.jsxs("ul",{className:"list-disc pl-5 space-y-1",children:[jsxRuntime.jsx("li",{children:".md file must contain skill name and description formatted in YAML"}),jsxRuntime.jsx("li",{children:".zip or .skill file must include a SKILL.md file"})]})]})]})})}function Ee({onClose:n,onSelect:e}){let s=X(),r=react.useRef(null),o=react.useRef(n);o.current=n,react.useEffect(()=>{if(s)return;let i=l=>{r.current&&l.target instanceof Node&&!r.current.contains(l.target)&&o.current();};return document.addEventListener("mousedown",i),()=>document.removeEventListener("mousedown",i)},[s]);let a=[{id:"create-with-geoff",icon:jsxRuntime.jsx(ye,{}),label:"Create with Geoff"},{id:"write",icon:jsxRuntime.jsx(ke,{}),label:"Write skill instructions"},{id:"upload",icon:jsxRuntime.jsx(Ne,{}),label:"Upload a skill"}];return s?jsxRuntime.jsxs("div",{className:"fixed inset-0 z-50 flex items-end",onClick:n,children:[jsxRuntime.jsx("div",{className:"fixed inset-0 bg-black/50"}),jsxRuntime.jsxs("div",{className:"relative z-10 w-full rounded-t-2xl bg-[#1a1a1a] p-4 pb-8 animate-in slide-in-from-bottom duration-200",onClick:i=>i.stopPropagation(),children:[jsxRuntime.jsx("div",{className:"mx-auto mb-3 h-1 w-10 rounded-full bg-zinc-600"}),a.map(i=>jsxRuntime.jsxs("button",{onClick:()=>{e(i.id),n();},className:"flex w-full items-center gap-3 rounded-lg px-4 py-3 text-sm text-foreground transition-colors hover:bg-zinc-800",children:[i.icon,i.label]},i.id))]})]}):jsxRuntime.jsx("div",{ref:r,className:"absolute right-2 top-11 z-50 w-56 overflow-hidden rounded-xl border border-zinc-700 bg-[#2a2a2a] shadow-xl animate-in fade-in zoom-in-95 duration-100",children:a.map(i=>jsxRuntime.jsxs("button",{onClick:()=>{e(i.id),n();},className:"flex w-full items-center gap-3 px-4 py-3 text-sm text-foreground transition-colors hover:bg-zinc-700/50",children:[i.icon,i.label]},i.id))})}function Te({entry:n,selected:e,onSelect:s,depth:r=0}){return jsxRuntime.jsxs("button",{onClick:()=>s(n),className:R("flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-left text-sm transition-colors",e?"bg-[#141414] text-foreground":"text-muted-foreground hover:bg-muted/50 hover:text-foreground"),style:{paddingLeft:`${8+r*16}px`},children:[jsxRuntime.jsx("span",{className:"truncate flex-1",children:n.path.split("/").pop()}),n.isDir&&jsxRuntime.jsx(Q,{className:"ml-auto text-muted-foreground"})]})}function ze({repo:n,selected:e,expanded:s,onSelect:r,onToggle:o,children:a}){return jsxRuntime.jsxs("div",{children:[jsxRuntime.jsxs("button",{onClick:()=>{r(),o();},className:R("flex w-full items-center gap-2 rounded-md px-2 py-2 text-left text-sm font-medium transition-colors",e?"bg-[#141414] text-foreground":"text-muted-foreground hover:bg-muted/50 hover:text-foreground"),children:[jsxRuntime.jsx(Q,{open:s}),jsxRuntime.jsx(lucideReact.FileText,{className:"h-4 w-4 shrink-0"}),jsxRuntime.jsx("span",{className:"truncate",children:n.name})]}),s&&a]})}function $e({entry:n,content:e,loading:s,repoName:r}){let[o,a]=react.useState(false),i=react.useRef(null);react.useEffect(()=>()=>{i.current&&clearTimeout(i.current);},[]);let[l,m]=react.useState(false),p=async()=>{if(e)try{await navigator.clipboard.writeText(e),a(!0),m(!1),i.current&&clearTimeout(i.current),i.current=setTimeout(()=>a(!1),2e3);}catch{m(true),i.current&&clearTimeout(i.current),i.current=setTimeout(()=>m(false),2e3);}};if(!n)return jsxRuntime.jsx("div",{className:"flex h-full items-center justify-center text-sm text-muted-foreground",children:"Select a file to view its content"});if(s)return jsxRuntime.jsx("div",{className:"flex h-full items-center justify-center",children:jsxRuntime.jsx(lucideReact.Loader2,{className:"h-5 w-5 animate-spin text-muted-foreground"})});let f=n.path.split("/").pop()||n.path,x=/\.(md|mdx)$/i.test(f);return jsxRuntime.jsxs("div",{className:"flex h-full flex-col px-3",children:[jsxRuntime.jsxs("div",{className:"flex items-center justify-between px-4 py-3",children:[jsxRuntime.jsx("h3",{className:"text-sm sm:text-lg font-semibold text-foreground",children:f}),jsxRuntime.jsx("button",{onClick:p,"aria-label":"Copy file content",className:R("rounded p-1 transition-colors",o?"text-green-500":l?"text-red-500":"text-muted-foreground hover:text-foreground"),children:jsxRuntime.jsx("svg",{width:"20",height:"20",viewBox:"0 0 20 20",fill:"currentColor",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",className:"shrink-0",children:jsxRuntime.jsx("path",{d:"M12.5 3A1.5 1.5 0 0 1 14 4.5V6h1.5A1.5 1.5 0 0 1 17 7.5v8a1.5 1.5 0 0 1-1.5 1.5h-8A1.5 1.5 0 0 1 6 15.5V14H4.5A1.5 1.5 0 0 1 3 12.5v-8A1.5 1.5 0 0 1 4.5 3zm1.5 9.5a1.5 1.5 0 0 1-1.5 1.5H7v1.5a.5.5 0 0 0 .5.5h8a.5.5 0 0 0 .5-.5v-8a.5.5 0 0 0-.5-.5H14zM4.5 4a.5.5 0 0 0-.5.5v8a.5.5 0 0 0 .5.5h8a.5.5 0 0 0 .5-.5v-8a.5.5 0 0 0-.5-.5z"})})})]}),jsxRuntime.jsx("div",{className:"flex-1 overflow-auto p-4",children:x?jsxRuntime.jsx(B,{content:e||""}):jsxRuntime.jsx("pre",{className:"whitespace-pre-wrap text-sm text-foreground font-mono leading-relaxed",children:e||""})})]})}function Me({config:n,category:e,className:s,style:r}){let{repos:o,loading:a,error:i,refresh:l}=Z(n),[m,p]=react.useState(null),[f,x]=react.useState(null),[u,d]=react.useState(null),[v,N]=react.useState(null),[E,z]=react.useState(false),[k,b]=react.useState(""),[y,U]=react.useState(false),[j,F]=react.useState(false),[O,L]=react.useState(null),te=o.find(g=>g.repo_id===m),{entries:re,getFileContent:H}=J(n,f),V=o.filter(g=>!k||g.name.toLowerCase().includes(k.toLowerCase())),ne=react.useCallback(async g=>{if(!g.isDir){d(g),z(true);try{let C=await H(g.cid);N(C);}catch(C){let se=C instanceof Error?C.message:"Unknown error";N(`Failed to load file: ${se}`);}finally{z(false);}}},[H]);react.useEffect(()=>{o.length>0&&!m&&(p(o[0].repo_id),x(o[0].repo_id));},[o,m]);let oe=g=>{g==="create-with-geoff"?window.open(`https://www.geoff.ai/?p=${encodeURIComponent("Let's create a skill together using your skill-creator skill. First ask me what the skill should do.")}`,"_blank","noopener,noreferrer"):L(g);};return jsxRuntime.jsxs("div",{className:R("flex flex-1 h-full min-h-0",s),style:r,children:[jsxRuntime.jsxs("div",{className:"relative flex w-96 shrink-0 flex-col border-r",children:[jsxRuntime.jsx("div",{className:"flex h-12 items-center gap-2 px-3",children:y?jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[jsxRuntime.jsxs("div",{className:"flex flex-1 items-center gap-2 rounded-md border bg-muted/50 px-2 py-1",children:[jsxRuntime.jsx(q,{size:16,className:"shrink-0 text-muted-foreground"}),jsxRuntime.jsx("input",{type:"text",value:k,onChange:g=>b(g.target.value),placeholder:"Search",autoFocus:true,"aria-label":"Search items",className:"flex-1 bg-transparent text-xs text-foreground placeholder:text-muted-foreground focus:outline-none"})]}),jsxRuntime.jsx("button",{onClick:()=>{U(false),b("");},className:"rounded p-1 text-muted-foreground hover:text-foreground",children:jsxRuntime.jsx(D,{size:16})})]}):jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[jsxRuntime.jsx("h3",{className:"flex-1 text-sm sm:text-lg font-semibold text-foreground capitalize",children:e||"Items"}),jsxRuntime.jsx("button",{onClick:()=>U(true),className:"rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground","aria-label":"Search",children:jsxRuntime.jsx(q,{size:20})}),jsxRuntime.jsx("button",{onClick:()=>F(!j),className:"rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground","aria-label":"Add new",children:jsxRuntime.jsx(Y,{size:20})})]})}),j&&jsxRuntime.jsx(Ee,{onClose:()=>F(false),onSelect:oe}),jsxRuntime.jsx("div",{className:"flex-1 overflow-y-auto p-2",children:a?jsxRuntime.jsx("div",{className:"flex items-center justify-center py-8",children:jsxRuntime.jsx(lucideReact.Loader2,{className:"h-5 w-5 animate-spin text-muted-foreground"})}):i?jsxRuntime.jsx("p",{className:"px-2 py-4 text-xs text-red-500",children:i}):V.length===0?jsxRuntime.jsx("p",{className:"px-2 py-4 text-xs text-muted-foreground",children:k?"No matching items":"No items yet"}):jsxRuntime.jsx("div",{className:"space-y-0.5",children:V.map(g=>jsxRuntime.jsx(ze,{repo:g,selected:m===g.repo_id,expanded:f===g.repo_id,onSelect:()=>{p(g.repo_id),d(null),N(null);},onToggle:()=>x(f===g.repo_id?null:g.repo_id),children:jsxRuntime.jsx("div",{className:"ml-10 pl-1",children:re.map(C=>jsxRuntime.jsx(Te,{entry:C,selected:u?.path===C.path,onSelect:ne,depth:C.path.split("/").length-1},C.path))})},g.repo_id))})})]}),jsxRuntime.jsx("div",{className:"flex-1 min-w-0",children:jsxRuntime.jsx($e,{entry:u,content:v,loading:E,repoName:te?.name||""})}),O==="write"&&jsxRuntime.jsx(Re,{config:n,onClose:()=>L(null),onCreated:l}),O==="upload"&&jsxRuntime.jsx(Ce,{config:n,onClose:()=>L(null),onCreated:l})]})}
|
|
10
|
+
exports.Markdown=B;exports.RackBrowser=Me;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { RackConfig } from '../types/index.cjs';
|
|
4
|
+
|
|
5
|
+
interface RackBrowserProps {
|
|
6
|
+
config: RackConfig;
|
|
7
|
+
category?: string;
|
|
8
|
+
className?: string;
|
|
9
|
+
style?: React.CSSProperties;
|
|
10
|
+
}
|
|
11
|
+
declare function RackBrowser({ config, category, className, style }: RackBrowserProps): react_jsx_runtime.JSX.Element;
|
|
12
|
+
|
|
13
|
+
interface MarkdownProps {
|
|
14
|
+
content: string;
|
|
15
|
+
className?: string;
|
|
16
|
+
}
|
|
17
|
+
declare function Markdown({ content, className }: MarkdownProps): react_jsx_runtime.JSX.Element;
|
|
18
|
+
|
|
19
|
+
export { Markdown, RackBrowser, type RackBrowserProps };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { RackConfig } from '../types/index.js';
|
|
4
|
+
|
|
5
|
+
interface RackBrowserProps {
|
|
6
|
+
config: RackConfig;
|
|
7
|
+
category?: string;
|
|
8
|
+
className?: string;
|
|
9
|
+
style?: React.CSSProperties;
|
|
10
|
+
}
|
|
11
|
+
declare function RackBrowser({ config, category, className, style }: RackBrowserProps): react_jsx_runtime.JSX.Element;
|
|
12
|
+
|
|
13
|
+
interface MarkdownProps {
|
|
14
|
+
content: string;
|
|
15
|
+
className?: string;
|
|
16
|
+
}
|
|
17
|
+
declare function Markdown({ content, className }: MarkdownProps): react_jsx_runtime.JSX.Element;
|
|
18
|
+
|
|
19
|
+
export { Markdown, RackBrowser, type RackBrowserProps };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import {useState,useCallback,useEffect,useRef,useMemo}from'react';import {Loader2,FileText}from'lucide-react';import {clsx}from'clsx';import {twMerge}from'tailwind-merge';import {jsx,jsxs,Fragment}from'react/jsx-runtime';function R(...n){return twMerge(clsx(n))}async function T(n,e,s){let r=await fetch(`${n}${e}`,{...s,headers:{"Content-Type":"application/json",...s?.headers}});if(!r.ok){let o=`HTTP ${r.status}`;try{let a=await r.json();a.error&&(o=a.error);}catch{}throw new Error(o)}return r.json()}function S(n){let e=n.apiBaseUrl,s=n.authorMid,r=n.ownerMid;return useMemo(()=>({async listRepos(o){let a=o||r?`?owner=${encodeURIComponent(o||r)}`:"";return (await T(e,`/api/rack/repos${a}`)).repos||[]},async initRepo(o){return T(e,"/api/rack/init",{method:"POST",body:JSON.stringify({...o,owner_mid:r})})},async push(o,a){return T(e,`/api/rack/${o}/push`,{method:"POST",body:JSON.stringify({...a,author_mid:s})})},async getTree(o,a="main"){let i=await T(e,`/api/rack/${o}/tree/${a}`);return {tree:i.tree,commit_cid:i.commit_cid}},async getBlob(o,a){return (await T(e,`/api/rack/${o}/blob/${a}`)).content},async getLog(o,a,i){let l=new URLSearchParams;a&&l.set("ref",a),i&&l.set("max_count",String(i));let m=l.toString()?`?${l}`:"";return (await T(e,`/api/rack/${o}/log${m}`)).commits||[]},async getBranches(o){return (await T(e,`/api/rack/${o}/branches`)).branches||[]},async getDiff(o,a,i){return (await T(e,`/api/rack/${o}/diff/${a}/${i}`)).diff?.entries||[]}}),[e,s,r])}function Z(n){let e=S(n),s=useRef(e);s.current=e;let[r,o]=useState([]),[a,i]=useState(true),[l,m]=useState(null),p=useRef(true),f=useRef(null),x=useCallback(async()=>{f.current?.abort();let u=new AbortController;f.current=u;try{p.current&&(i(!0),m(null));let d=await s.current.listRepos();p.current&&!u.signal.aborted&&o(d);}catch(d){p.current&&!u.signal.aborted&&m(d instanceof Error?d.message:"Failed to load repos");}finally{p.current&&!u.signal.aborted&&i(false);}},[]);return useEffect(()=>(p.current=true,x(),()=>{p.current=false,f.current?.abort();}),[x]),{repos:r,loading:a,error:l,refresh:x}}function fe(n){return Object.entries(n).map(([e,s])=>{let r=s.indexOf(":"),o=r>0?s.slice(0,r):"100644",a=r>0?s.slice(r+1):s;return {path:e,mode:o,cid:a,isDir:o==="040000"}}).sort((e,s)=>e.isDir!==s.isDir?e.isDir?-1:1:e.path.localeCompare(s.path))}function J(n,e,s="main"){let r=S(n),[o,a]=useState([]),[i,l]=useState(false),[m,p]=useState(null),f=useRef(true),x=useCallback(async()=>{if(e)try{f.current&&(l(!0),p(null));let{tree:d}=await r.getTree(e,s);f.current&&a(fe(d.entries));}catch(d){f.current&&p(d instanceof Error?d.message:"Failed to load tree");}finally{f.current&&l(false);}},[r,e,s]);useEffect(()=>(f.current=true,x(),()=>{f.current=false;}),[x]);let u=useCallback(async d=>{if(!e)throw new Error("No repo selected");return r.getBlob(e,d)},[r,e]);return {entries:o,loading:i,error:m,refresh:x,getFileContent:u}}var pe=/^(https?:\/\/|mailto:|\/[^/])/i;function ge(n){let e=n.trim();return pe.test(e)?e:null}function I(n){let e=[],s=/(`[^`]+`)|(\*\*(.+?)\*\*)|(\*(.+?)\*)|(_(.+?)_)|(\[([^\]]+)\]\(([^)]+)\))/g,r=0,o,a=0;for(;(o=s.exec(n))!==null;){o.index>r&&e.push(n.slice(r,o.index));let i=`i${a++}`;if(o[1])e.push(jsx("code",{className:"rounded bg-muted px-1.5 py-0.5 text-[0.85em] font-mono text-pink-400",children:o[1].slice(1,-1)},i));else if(o[2])e.push(jsx("strong",{children:o[3]},i));else if(o[4])e.push(jsx("em",{children:o[5]},i));else if(o[6])e.push(jsx("em",{children:o[7]},i));else if(o[8]){let l=ge(o[10]);l?e.push(jsx("a",{href:l,className:"text-blue-400 underline hover:text-blue-300",target:"_blank",rel:"noopener noreferrer",children:o[9]},i)):e.push(o[9]);}r=o.index+o[0].length;}return r<n.length&&e.push(n.slice(r)),e.length>0?e:[n]}function he(n){let e=n.split(`
|
|
2
|
+
`),s=[],r=0;for(;r<e.length;){let o=e[r];if(o.trim()===""){r++;continue}if(/^(-{3,}|\*{3,}|_{3,})$/.test(o.trim())){s.push({type:"hr"}),r++;continue}let a=o.match(/^(#{1,6})\s+(.+)/);if(a){s.push({type:"heading",level:a[1].length,content:a[2]}),r++;continue}if(o.trim().startsWith("```")){let l=o.trim().slice(3).trim(),m=[];for(r++;r<e.length&&!e[r].trim().startsWith("```");)m.push(e[r]),r++;s.push({type:"code",content:m.join(`
|
|
3
|
+
`),lang:l||void 0}),r++;continue}if(/^\s*[-*+]\s/.test(o)){let l=[];for(;r<e.length&&/^\s*[-*+]\s/.test(e[r]);)l.push(e[r].replace(/^\s*[-*+]\s+/,"")),r++;s.push({type:"ul",items:l});continue}if(/^\s*\d+[.)]\s/.test(o)){let l=[];for(;r<e.length&&/^\s*\d+[.)]\s/.test(e[r]);)l.push(e[r].replace(/^\s*\d+[.)]\s+/,"")),r++;s.push({type:"ol",items:l});continue}let i=[];for(;r<e.length&&e[r].trim()!==""&&!e[r].match(/^#{1,6}\s/)&&!e[r].trim().startsWith("```")&&!/^\s*[-*+]\s/.test(e[r])&&!/^\s*\d+[.)]\s/.test(e[r]);)i.push(e[r]),r++;i.length>0&&s.push({type:"paragraph",content:i.join(" ")});}return s}var xe={1:"text-2xl font-bold mt-6 mb-3",2:"text-xl font-bold mt-5 mb-2",3:"text-lg font-semibold mt-4 mb-2",4:"text-base font-semibold mt-3 mb-1",5:"text-sm font-semibold mt-2 mb-1",6:"text-sm font-medium mt-2 mb-1"};function ve(n,e){switch(n.type){case "hr":return jsx("hr",{className:"my-4 border-border"},`b${e}`);case "heading":{let s=Math.min(Math.max(n.level||1,1),6),r=`h${s}`;return jsx(r,{className:R("text-foreground",xe[s]),children:I(n.content||"")},`b${e}`)}case "paragraph":return jsx("p",{className:"mb-3 leading-relaxed text-foreground",children:I(n.content||"")},`b${e}`);case "code":return jsx("pre",{className:"mb-3 overflow-x-auto rounded-lg bg-muted p-4 text-sm font-mono leading-relaxed text-foreground",children:jsx("code",{children:n.content})},`b${e}`);case "ul":return jsx("ul",{className:"mb-3 ml-5 list-disc space-y-1 text-foreground",children:n.items?.map((s,r)=>jsx("li",{className:"leading-relaxed",children:I(s)},`li${e}-${r}`))},`b${e}`);case "ol":return jsx("ol",{className:"mb-3 ml-5 list-decimal space-y-1 text-foreground",children:n.items?.map((s,r)=>jsx("li",{className:"leading-relaxed",children:I(s)},`li${e}-${r}`))},`b${e}`);default:return null}}function B({content:n,className:e}){let s=he(n);return jsx("div",{className:R("text-sm",e),children:s.map((r,o)=>ve(r,o))})}function Q({open:n,className:e}){return jsx("svg",{width:"16",height:"16",viewBox:"0 0 20 20",fill:"currentColor",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",className:R("shrink-0 transition-transform duration-150",n?"rotate-0":"-rotate-90",e),children:jsx("path",{d:"M16.134 6.16a.5.5 0 1 1 .732.68l-6.5 7-.077.068a.5.5 0 0 1-.655-.068l-6.5-7-.062-.08a.5.5 0 0 1 .718-.667l.076.067L10 12.767z"})})}function q({size:n=20,className:e}){return jsx("svg",{width:n,height:n,viewBox:"0 0 20 20",fill:"currentColor",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",className:e,children:jsx("path",{d:"M8.5 2a6.5 6.5 0 0 1 4.935 10.728l4.419 4.419.064.078a.5.5 0 0 1-.693.693l-.079-.064-4.419-4.42A6.5 6.5 0 1 1 8.5 2m0 1a5.5 5.5 0 1 0 0 11 5.5 5.5 0 0 0 0-11"})})}function D({size:n=20,className:e}){return jsx("svg",{width:n,height:n,viewBox:"0 0 20 20",fill:"currentColor",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",className:e,children:jsx("path",{d:"M15.147 4.146a.5.5 0 0 1 .707.707L10.707 10l5.147 5.147a.5.5 0 0 1-.63.771l-.078-.064L10 10.707l-5.146 5.147a.5.5 0 0 1-.708-.707L9.293 10 4.146 4.853a.5.5 0 0 1 .708-.707L10 9.293z"})})}function Y({size:n=20,className:e}){return jsx("svg",{width:n,height:n,viewBox:"0 0 20 20",fill:"currentColor",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",className:e,children:jsx("path",{d:"M10 3a.5.5 0 0 1 .5.5v6h6l.1.01a.5.5 0 0 1 0 .98l-.1.01h-6v6a.5.5 0 0 1-1 0v-6h-6a.5.5 0 0 1 0-1h6v-6A.5.5 0 0 1 10 3"})})}function ye(){return jsx("svg",{width:"20",height:"20",viewBox:"0 0 20 20",fill:"currentColor",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",className:"shrink-0",children:jsx("path",{d:"M6.5 3A2.5 2.5 0 0 0 4 5.5v9A2.5 2.5 0 0 0 6.5 17h7a2.5 2.5 0 0 0 2.5-2.5v-7A2.5 2.5 0 0 0 13.5 5H11V3.5a.5.5 0 0 0-1 0V5H6.5ZM5 5.5A1.5 1.5 0 0 1 6.5 4H9v1H6.5A1.5 1.5 0 0 0 5 6.5v8A1.5 1.5 0 0 0 6.5 16h7a1.5 1.5 0 0 0 1.5-1.5v-7A1.5 1.5 0 0 0 13.5 6H11V4h2.5A2.5 2.5 0 0 1 16 6.5v8a2.5 2.5 0 0 1-2.5 2.5h-7A2.5 2.5 0 0 1 4 14.5v-9Z"})})}function ke(){return jsx("svg",{width:"20",height:"20",viewBox:"0 0 20 20",fill:"currentColor",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",className:"shrink-0",children:jsx("path",{d:"M5.5 3A2.5 2.5 0 0 0 3 5.5v9A2.5 2.5 0 0 0 5.5 17h9a2.5 2.5 0 0 0 2.5-2.5v-9A2.5 2.5 0 0 0 14.5 3h-9ZM4 5.5A1.5 1.5 0 0 1 5.5 4h9A1.5 1.5 0 0 1 16 5.5v9a1.5 1.5 0 0 1-1.5 1.5h-9A1.5 1.5 0 0 1 4 14.5v-9ZM7 7.5a.5.5 0 0 1 .5-.5h5a.5.5 0 0 1 0 1h-5a.5.5 0 0 1-.5-.5Zm0 3a.5.5 0 0 1 .5-.5h5a.5.5 0 0 1 0 1h-5a.5.5 0 0 1-.5-.5Zm0 3a.5.5 0 0 1 .5-.5h3a.5.5 0 0 1 0 1h-3a.5.5 0 0 1-.5-.5Z"})})}function Ne(){return jsx("svg",{width:"20",height:"20",viewBox:"0 0 20 20",fill:"currentColor",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",className:"shrink-0",children:jsx("path",{d:"M10 2a.5.5 0 0 1 .354.146l3 3a.5.5 0 0 1-.708.708L10.5 3.707V12.5a.5.5 0 0 1-1 0V3.707L7.354 5.854a.5.5 0 1 1-.708-.708l3-3A.5.5 0 0 1 10 2ZM4 13.5a.5.5 0 0 1 1 0v1A1.5 1.5 0 0 0 6.5 16h7a1.5 1.5 0 0 0 1.5-1.5v-1a.5.5 0 0 1 1 0v1a2.5 2.5 0 0 1-2.5 2.5h-7A2.5 2.5 0 0 1 4 14.5v-1Z"})})}function X(){let[n,e]=useState(false);return useEffect(()=>{if(typeof window>"u")return;let s=()=>e(window.innerWidth<768);return s(),window.addEventListener("resize",s),()=>window.removeEventListener("resize",s)},[]),n}function ee({onClose:n,children:e,title:s}){let r=X(),o=useRef(n);return o.current=n,useEffect(()=>{let a=i=>{i.key==="Escape"&&o.current();};return window.addEventListener("keydown",a),()=>window.removeEventListener("keydown",a)},[]),r?jsxs("div",{className:"fixed inset-0 z-50 flex items-end justify-center",onClick:n,children:[jsx("div",{className:"fixed inset-0 bg-black/50"}),jsxs("div",{className:"relative z-10 w-full max-h-[90vh] overflow-y-auto rounded-t-2xl bg-[#1a1a1a] p-5 pb-8 animate-in slide-in-from-bottom duration-200",onClick:a=>a.stopPropagation(),children:[jsx("div",{className:"mx-auto mb-4 h-1 w-10 rounded-full bg-zinc-600"}),jsxs("div",{className:"flex items-center justify-between mb-5",children:[jsx("h2",{className:"text-lg font-semibold text-foreground",children:s}),jsx("button",{onClick:n,className:"rounded p-1 text-muted-foreground hover:text-foreground",children:jsx(D,{size:20})})]}),e]})]}):jsxs("div",{className:"fixed inset-0 z-50 flex items-center justify-center",onClick:n,children:[jsx("div",{className:"fixed inset-0 bg-black/50"}),jsxs("div",{className:"relative z-10 w-full max-w-lg overflow-y-auto rounded-2xl bg-[#1a1a1a] p-6 shadow-2xl animate-in fade-in zoom-in-95 duration-150",onClick:a=>a.stopPropagation(),children:[jsxs("div",{className:"flex items-center justify-between mb-5",children:[jsx("h2",{className:"text-lg font-semibold text-foreground",children:s}),jsx("button",{onClick:n,className:"rounded p-1 text-muted-foreground hover:text-foreground",children:jsx(D,{size:20})})]}),e]})]})}function Re({onClose:n,onCreated:e,config:s}){let[r,o]=useState(""),[a,i]=useState(""),[l,m]=useState(""),[p,f]=useState(false),[x,u]=useState(null);return jsx(ee,{title:"Write skill instructions",onClose:n,children:jsxs("div",{className:"space-y-4",children:[jsxs("div",{className:"space-y-1.5",children:[jsx("label",{htmlFor:"skill-name",className:"text-sm text-muted-foreground",children:"Skill name"}),jsx("input",{id:"skill-name",value:r,onChange:v=>o(v.target.value),placeholder:"weekly-status-report",className:"w-full rounded-lg border border-zinc-700 bg-[#252525] px-3 py-2.5 text-sm text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-zinc-500"})]}),jsxs("div",{className:"space-y-1.5",children:[jsx("label",{htmlFor:"skill-desc",className:"text-sm text-muted-foreground",children:"Description"}),jsx("textarea",{id:"skill-desc",value:a,onChange:v=>i(v.target.value),placeholder:"Generate weekly status reports from recent work.",rows:3,className:"w-full rounded-lg border border-zinc-700 bg-[#252525] px-3 py-2.5 text-sm text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-zinc-500"})]}),jsxs("div",{className:"space-y-1.5",children:[jsx("label",{htmlFor:"skill-instructions",className:"text-sm text-muted-foreground",children:"Instructions"}),jsx("textarea",{id:"skill-instructions",value:l,onChange:v=>m(v.target.value),placeholder:"Summarize my recent work in three sections: wins, blockers, and next steps.",rows:8,className:"w-full rounded-lg border border-zinc-700 bg-[#252525] px-3 py-2.5 text-sm text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-zinc-500"})]}),x&&jsx("p",{className:"text-sm text-red-500",children:x}),jsxs("div",{className:"flex justify-end gap-3 pt-2",children:[jsx("button",{onClick:n,className:"rounded-lg border border-zinc-700 px-4 py-2 text-sm text-foreground hover:bg-zinc-800",children:"Cancel"}),jsx("button",{onClick:async()=>{if(r.trim()){f(true),u(null);try{let v=s.apiBaseUrl||"",N=await fetch(`${v}/api/rack/init`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:r.trim(),description:a.trim(),owner_mid:s.ownerMid,is_gitagent:!0})});if(!N.ok){let b=`Failed to create skill (${N.status})`;try{let y=await N.json();y.error&&(b=y.error);}catch{}throw new Error(b)}let{repo_id:E}=await N.json(),z=`# ${r.trim()}
|
|
4
|
+
|
|
5
|
+
${a.trim()}
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
${l.trim()}`,k=await fetch(`${v}/api/rack/${E}/push`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({files:[{path:"SKILL.md",content:z}],message:"Initial skill definition",author_mid:s.authorMid})});if(!k.ok){let b=`Failed to save skill (${k.status})`;try{let y=await k.json();y.error&&(b=y.error);}catch{}throw new Error(b)}e?.(),n();}catch(v){u(v instanceof Error?v.message:"Failed to create skill");}finally{f(false);}}},disabled:p||!r.trim(),className:"rounded-lg bg-zinc-600 px-4 py-2 text-sm font-medium text-white hover:bg-zinc-500 disabled:opacity-50",children:p?"Creating...":"Create"})]})]})})}function Ce({onClose:n,onCreated:e,config:s}){let r=useRef(null),[o,a]=useState(false),[i,l]=useState(false),[m,p]=useState(null),f=async u=>{l(true),p(null);try{let d=await u.text(),v=s.apiBaseUrl||"",N=u.name.replace(/\.[^.]+$/,"").replace(/[^a-zA-Z0-9-_]/g,"-"),E=await fetch(`${v}/api/rack/init`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:N,owner_mid:s.ownerMid,is_gitagent:!0})});if(!E.ok){let b=`Failed to create repo (${E.status})`;try{let y=await E.json();y.error&&(b=y.error);}catch{}throw new Error(b)}let{repo_id:z}=await E.json(),k=await fetch(`${v}/api/rack/${z}/push`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({files:[{path:u.name,content:d}],message:`Upload ${u.name}`,author_mid:s.authorMid})});if(!k.ok){let b=`Upload failed (${k.status})`;try{let y=await k.json();y.error&&(b=y.error);}catch{}throw new Error(b)}e?.(),n();}catch(d){p(d instanceof Error?d.message:"Upload failed");}finally{l(false);}};return jsx(ee,{title:"Upload skill",onClose:n,children:jsxs("div",{className:"space-y-4",children:[jsxs("div",{onDragOver:u=>{u.preventDefault(),a(true);},onDragLeave:()=>a(false),onDrop:u=>{u.preventDefault(),a(false);let d=u.dataTransfer.files[0];d&&f(d);},onClick:()=>r.current?.click(),className:R("flex cursor-pointer flex-col items-center justify-center gap-3 rounded-xl border-2 border-dashed p-10 transition-colors",o?"border-zinc-400 bg-zinc-800/50":"border-zinc-700 hover:border-zinc-500"),children:[jsx("div",{className:"rounded-lg border border-zinc-600 p-2",children:jsx(Y,{size:20,className:"text-muted-foreground"})}),jsx("p",{className:"text-sm text-muted-foreground",children:i?"Uploading...":"Drag and drop or click to upload"})]}),jsx("input",{ref:r,type:"file",accept:".md,.zip,.skill,.txt,.yml,.yaml",className:"hidden","aria-label":"Upload skill file",onChange:u=>{let d=u.target.files?.[0];d&&f(d);}}),m&&jsx("p",{className:"text-sm text-red-500",children:m}),jsxs("div",{className:"space-y-2 text-xs text-muted-foreground",children:[jsx("p",{className:"font-medium text-foreground/70",children:"File requirements"}),jsxs("ul",{className:"list-disc pl-5 space-y-1",children:[jsx("li",{children:".md file must contain skill name and description formatted in YAML"}),jsx("li",{children:".zip or .skill file must include a SKILL.md file"})]})]})]})})}function Ee({onClose:n,onSelect:e}){let s=X(),r=useRef(null),o=useRef(n);o.current=n,useEffect(()=>{if(s)return;let i=l=>{r.current&&l.target instanceof Node&&!r.current.contains(l.target)&&o.current();};return document.addEventListener("mousedown",i),()=>document.removeEventListener("mousedown",i)},[s]);let a=[{id:"create-with-geoff",icon:jsx(ye,{}),label:"Create with Geoff"},{id:"write",icon:jsx(ke,{}),label:"Write skill instructions"},{id:"upload",icon:jsx(Ne,{}),label:"Upload a skill"}];return s?jsxs("div",{className:"fixed inset-0 z-50 flex items-end",onClick:n,children:[jsx("div",{className:"fixed inset-0 bg-black/50"}),jsxs("div",{className:"relative z-10 w-full rounded-t-2xl bg-[#1a1a1a] p-4 pb-8 animate-in slide-in-from-bottom duration-200",onClick:i=>i.stopPropagation(),children:[jsx("div",{className:"mx-auto mb-3 h-1 w-10 rounded-full bg-zinc-600"}),a.map(i=>jsxs("button",{onClick:()=>{e(i.id),n();},className:"flex w-full items-center gap-3 rounded-lg px-4 py-3 text-sm text-foreground transition-colors hover:bg-zinc-800",children:[i.icon,i.label]},i.id))]})]}):jsx("div",{ref:r,className:"absolute right-2 top-11 z-50 w-56 overflow-hidden rounded-xl border border-zinc-700 bg-[#2a2a2a] shadow-xl animate-in fade-in zoom-in-95 duration-100",children:a.map(i=>jsxs("button",{onClick:()=>{e(i.id),n();},className:"flex w-full items-center gap-3 px-4 py-3 text-sm text-foreground transition-colors hover:bg-zinc-700/50",children:[i.icon,i.label]},i.id))})}function Te({entry:n,selected:e,onSelect:s,depth:r=0}){return jsxs("button",{onClick:()=>s(n),className:R("flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-left text-sm transition-colors",e?"bg-[#141414] text-foreground":"text-muted-foreground hover:bg-muted/50 hover:text-foreground"),style:{paddingLeft:`${8+r*16}px`},children:[jsx("span",{className:"truncate flex-1",children:n.path.split("/").pop()}),n.isDir&&jsx(Q,{className:"ml-auto text-muted-foreground"})]})}function ze({repo:n,selected:e,expanded:s,onSelect:r,onToggle:o,children:a}){return jsxs("div",{children:[jsxs("button",{onClick:()=>{r(),o();},className:R("flex w-full items-center gap-2 rounded-md px-2 py-2 text-left text-sm font-medium transition-colors",e?"bg-[#141414] text-foreground":"text-muted-foreground hover:bg-muted/50 hover:text-foreground"),children:[jsx(Q,{open:s}),jsx(FileText,{className:"h-4 w-4 shrink-0"}),jsx("span",{className:"truncate",children:n.name})]}),s&&a]})}function $e({entry:n,content:e,loading:s,repoName:r}){let[o,a]=useState(false),i=useRef(null);useEffect(()=>()=>{i.current&&clearTimeout(i.current);},[]);let[l,m]=useState(false),p=async()=>{if(e)try{await navigator.clipboard.writeText(e),a(!0),m(!1),i.current&&clearTimeout(i.current),i.current=setTimeout(()=>a(!1),2e3);}catch{m(true),i.current&&clearTimeout(i.current),i.current=setTimeout(()=>m(false),2e3);}};if(!n)return jsx("div",{className:"flex h-full items-center justify-center text-sm text-muted-foreground",children:"Select a file to view its content"});if(s)return jsx("div",{className:"flex h-full items-center justify-center",children:jsx(Loader2,{className:"h-5 w-5 animate-spin text-muted-foreground"})});let f=n.path.split("/").pop()||n.path,x=/\.(md|mdx)$/i.test(f);return jsxs("div",{className:"flex h-full flex-col px-3",children:[jsxs("div",{className:"flex items-center justify-between px-4 py-3",children:[jsx("h3",{className:"text-sm sm:text-lg font-semibold text-foreground",children:f}),jsx("button",{onClick:p,"aria-label":"Copy file content",className:R("rounded p-1 transition-colors",o?"text-green-500":l?"text-red-500":"text-muted-foreground hover:text-foreground"),children:jsx("svg",{width:"20",height:"20",viewBox:"0 0 20 20",fill:"currentColor",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",className:"shrink-0",children:jsx("path",{d:"M12.5 3A1.5 1.5 0 0 1 14 4.5V6h1.5A1.5 1.5 0 0 1 17 7.5v8a1.5 1.5 0 0 1-1.5 1.5h-8A1.5 1.5 0 0 1 6 15.5V14H4.5A1.5 1.5 0 0 1 3 12.5v-8A1.5 1.5 0 0 1 4.5 3zm1.5 9.5a1.5 1.5 0 0 1-1.5 1.5H7v1.5a.5.5 0 0 0 .5.5h8a.5.5 0 0 0 .5-.5v-8a.5.5 0 0 0-.5-.5H14zM4.5 4a.5.5 0 0 0-.5.5v8a.5.5 0 0 0 .5.5h8a.5.5 0 0 0 .5-.5v-8a.5.5 0 0 0-.5-.5z"})})})]}),jsx("div",{className:"flex-1 overflow-auto p-4",children:x?jsx(B,{content:e||""}):jsx("pre",{className:"whitespace-pre-wrap text-sm text-foreground font-mono leading-relaxed",children:e||""})})]})}function Me({config:n,category:e,className:s,style:r}){let{repos:o,loading:a,error:i,refresh:l}=Z(n),[m,p]=useState(null),[f,x]=useState(null),[u,d]=useState(null),[v,N]=useState(null),[E,z]=useState(false),[k,b]=useState(""),[y,U]=useState(false),[j,F]=useState(false),[O,L]=useState(null),te=o.find(g=>g.repo_id===m),{entries:re,getFileContent:H}=J(n,f),V=o.filter(g=>!k||g.name.toLowerCase().includes(k.toLowerCase())),ne=useCallback(async g=>{if(!g.isDir){d(g),z(true);try{let C=await H(g.cid);N(C);}catch(C){let se=C instanceof Error?C.message:"Unknown error";N(`Failed to load file: ${se}`);}finally{z(false);}}},[H]);useEffect(()=>{o.length>0&&!m&&(p(o[0].repo_id),x(o[0].repo_id));},[o,m]);let oe=g=>{g==="create-with-geoff"?window.open(`https://www.geoff.ai/?p=${encodeURIComponent("Let's create a skill together using your skill-creator skill. First ask me what the skill should do.")}`,"_blank","noopener,noreferrer"):L(g);};return jsxs("div",{className:R("flex flex-1 h-full min-h-0",s),style:r,children:[jsxs("div",{className:"relative flex w-96 shrink-0 flex-col border-r",children:[jsx("div",{className:"flex h-12 items-center gap-2 px-3",children:y?jsxs(Fragment,{children:[jsxs("div",{className:"flex flex-1 items-center gap-2 rounded-md border bg-muted/50 px-2 py-1",children:[jsx(q,{size:16,className:"shrink-0 text-muted-foreground"}),jsx("input",{type:"text",value:k,onChange:g=>b(g.target.value),placeholder:"Search",autoFocus:true,"aria-label":"Search items",className:"flex-1 bg-transparent text-xs text-foreground placeholder:text-muted-foreground focus:outline-none"})]}),jsx("button",{onClick:()=>{U(false),b("");},className:"rounded p-1 text-muted-foreground hover:text-foreground",children:jsx(D,{size:16})})]}):jsxs(Fragment,{children:[jsx("h3",{className:"flex-1 text-sm sm:text-lg font-semibold text-foreground capitalize",children:e||"Items"}),jsx("button",{onClick:()=>U(true),className:"rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground","aria-label":"Search",children:jsx(q,{size:20})}),jsx("button",{onClick:()=>F(!j),className:"rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground","aria-label":"Add new",children:jsx(Y,{size:20})})]})}),j&&jsx(Ee,{onClose:()=>F(false),onSelect:oe}),jsx("div",{className:"flex-1 overflow-y-auto p-2",children:a?jsx("div",{className:"flex items-center justify-center py-8",children:jsx(Loader2,{className:"h-5 w-5 animate-spin text-muted-foreground"})}):i?jsx("p",{className:"px-2 py-4 text-xs text-red-500",children:i}):V.length===0?jsx("p",{className:"px-2 py-4 text-xs text-muted-foreground",children:k?"No matching items":"No items yet"}):jsx("div",{className:"space-y-0.5",children:V.map(g=>jsx(ze,{repo:g,selected:m===g.repo_id,expanded:f===g.repo_id,onSelect:()=>{p(g.repo_id),d(null),N(null);},onToggle:()=>x(f===g.repo_id?null:g.repo_id),children:jsx("div",{className:"ml-10 pl-1",children:re.map(C=>jsx(Te,{entry:C,selected:u?.path===C.path,onSelect:ne,depth:C.path.split("/").length-1},C.path))})},g.repo_id))})})]}),jsx("div",{className:"flex-1 min-w-0",children:jsx($e,{entry:u,content:v,loading:E,repoName:te?.name||""})}),O==="write"&&jsx(Re,{config:n,onClose:()=>L(null),onCreated:l}),O==="upload"&&jsx(Ce,{config:n,onClose:()=>L(null),onCreated:l})]})}
|
|
10
|
+
export{B as Markdown,Me as RackBrowser};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
'use strict';var react=require('react');async function m(i,e,s){let n=await fetch(`${i}${e}`,{...s,headers:{"Content-Type":"application/json",...s?.headers}});if(!n.ok){let r=`HTTP ${n.status}`;try{let t=await n.json();t.error&&(r=t.error);}catch{}throw new Error(r)}return n.json()}function R(i){let e=i.apiBaseUrl,s=i.authorMid,n=i.ownerMid;return react.useMemo(()=>({async listRepos(r){let t=r||n?`?owner=${encodeURIComponent(r||n)}`:"";return (await m(e,`/api/rack/repos${t}`)).repos||[]},async initRepo(r){return m(e,"/api/rack/init",{method:"POST",body:JSON.stringify({...r,owner_mid:n})})},async push(r,t){return m(e,`/api/rack/${r}/push`,{method:"POST",body:JSON.stringify({...t,author_mid:s})})},async getTree(r,t="main"){let o=await m(e,`/api/rack/${r}/tree/${t}`);return {tree:o.tree,commit_cid:o.commit_cid}},async getBlob(r,t){return (await m(e,`/api/rack/${r}/blob/${t}`)).content},async getLog(r,t,o){let l=new URLSearchParams;t&&l.set("ref",t),o&&l.set("max_count",String(o));let g=l.toString()?`?${l}`:"";return (await m(e,`/api/rack/${r}/log${g}`)).commits||[]},async getBranches(r){return (await m(e,`/api/rack/${r}/branches`)).branches||[]},async getDiff(r,t,o){return (await m(e,`/api/rack/${r}/diff/${t}/${o}`)).diff?.entries||[]}}),[e,s,n])}function T(i){let e=R(i),s=react.useRef(e);s.current=e;let[n,r]=react.useState([]),[t,o]=react.useState(true),[l,g]=react.useState(null),c=react.useRef(true),u=react.useRef(null),p=react.useCallback(async()=>{u.current?.abort();let f=new AbortController;u.current=f;try{c.current&&(o(!0),g(null));let a=await s.current.listRepos();c.current&&!f.signal.aborted&&r(a);}catch(a){c.current&&!f.signal.aborted&&g(a instanceof Error?a.message:"Failed to load repos");}finally{c.current&&!f.signal.aborted&&o(false);}},[]);return react.useEffect(()=>(c.current=true,p(),()=>{c.current=false,u.current?.abort();}),[p]),{repos:n,loading:t,error:l,refresh:p}}function I(i){return Object.entries(i).map(([e,s])=>{let n=s.indexOf(":"),r=n>0?s.slice(0,n):"100644",t=n>0?s.slice(n+1):s;return {path:e,mode:r,cid:t,isDir:r==="040000"}}).sort((e,s)=>e.isDir!==s.isDir?e.isDir?-1:1:e.path.localeCompare(s.path))}function x(i,e,s="main"){let n=R(i),[r,t]=react.useState([]),[o,l]=react.useState(false),[g,c]=react.useState(null),u=react.useRef(true),p=react.useCallback(async()=>{if(e)try{u.current&&(l(!0),c(null));let{tree:a}=await n.getTree(e,s);u.current&&t(I(a.entries));}catch(a){u.current&&c(a instanceof Error?a.message:"Failed to load tree");}finally{u.current&&l(false);}},[n,e,s]);react.useEffect(()=>(u.current=true,p(),()=>{u.current=false;}),[p]);let f=react.useCallback(async a=>{if(!e)throw new Error("No repo selected");return n.getBlob(e,a)},[n,e]);return {entries:r,loading:o,error:g,refresh:p,getFileContent:f}}function U(i){let e=R(i),[s,n]=react.useState(false),[r,t]=react.useState(null),o=react.useRef(true);return react.useEffect(()=>(o.current=true,()=>{o.current=false;}),[]),{push:react.useCallback(async(g,c,u,p)=>{try{return o.current&&(n(!0),t(null)),await e.push(g,{files:c,message:u,branch:p})}catch(f){let a=f instanceof Error?f.message:"Push failed";return o.current&&t(a),null}finally{o.current&&n(false);}},[e]),pushing:s,error:r}}exports.useRackClient=R;exports.useRepoPush=U;exports.useRepoTree=x;exports.useRepos=T;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { RepoInfo, InitResult, RepoFile, PushResult, RepoTree, RepoCommit, DiffEntry, RackConfig, TreeEntry } from '../types/index.cjs';
|
|
2
|
+
|
|
3
|
+
interface RackClient {
|
|
4
|
+
listRepos: (owner?: string) => Promise<RepoInfo[]>;
|
|
5
|
+
initRepo: (params: {
|
|
6
|
+
name: string;
|
|
7
|
+
description?: string;
|
|
8
|
+
is_gitagent?: boolean;
|
|
9
|
+
}) => Promise<InitResult>;
|
|
10
|
+
push: (repoId: string, params: {
|
|
11
|
+
files: RepoFile[];
|
|
12
|
+
message: string;
|
|
13
|
+
branch?: string;
|
|
14
|
+
}) => Promise<PushResult>;
|
|
15
|
+
getTree: (repoId: string, ref?: string) => Promise<{
|
|
16
|
+
tree: RepoTree;
|
|
17
|
+
commit_cid: string;
|
|
18
|
+
}>;
|
|
19
|
+
getBlob: (repoId: string, cid: string) => Promise<string>;
|
|
20
|
+
getLog: (repoId: string, ref?: string, maxCount?: number) => Promise<RepoCommit[]>;
|
|
21
|
+
getBranches: (repoId: string) => Promise<string[]>;
|
|
22
|
+
getDiff: (repoId: string, fromRef: string, toRef: string) => Promise<DiffEntry[]>;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Low-level hook returning a rack API client.
|
|
26
|
+
* All methods route through the host app's proxy.
|
|
27
|
+
*/
|
|
28
|
+
declare function useRackClient(config: RackConfig): RackClient;
|
|
29
|
+
|
|
30
|
+
interface UseReposReturn {
|
|
31
|
+
repos: RepoInfo[];
|
|
32
|
+
loading: boolean;
|
|
33
|
+
error: string | null;
|
|
34
|
+
refresh: () => Promise<void>;
|
|
35
|
+
}
|
|
36
|
+
declare function useRepos(config: RackConfig): UseReposReturn;
|
|
37
|
+
|
|
38
|
+
interface UseRepoTreeReturn {
|
|
39
|
+
entries: TreeEntry[];
|
|
40
|
+
loading: boolean;
|
|
41
|
+
error: string | null;
|
|
42
|
+
refresh: () => Promise<void>;
|
|
43
|
+
getFileContent: (cid: string) => Promise<string>;
|
|
44
|
+
}
|
|
45
|
+
declare function useRepoTree(config: RackConfig, repoId: string | null, ref?: string): UseRepoTreeReturn;
|
|
46
|
+
|
|
47
|
+
interface UseRepoPushReturn {
|
|
48
|
+
push: (repoId: string, files: RepoFile[], message: string, branch?: string) => Promise<PushResult | null>;
|
|
49
|
+
pushing: boolean;
|
|
50
|
+
error: string | null;
|
|
51
|
+
}
|
|
52
|
+
declare function useRepoPush(config: RackConfig): UseRepoPushReturn;
|
|
53
|
+
|
|
54
|
+
export { type RackClient, useRackClient, useRepoPush, useRepoTree, useRepos };
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { RepoInfo, InitResult, RepoFile, PushResult, RepoTree, RepoCommit, DiffEntry, RackConfig, TreeEntry } from '../types/index.js';
|
|
2
|
+
|
|
3
|
+
interface RackClient {
|
|
4
|
+
listRepos: (owner?: string) => Promise<RepoInfo[]>;
|
|
5
|
+
initRepo: (params: {
|
|
6
|
+
name: string;
|
|
7
|
+
description?: string;
|
|
8
|
+
is_gitagent?: boolean;
|
|
9
|
+
}) => Promise<InitResult>;
|
|
10
|
+
push: (repoId: string, params: {
|
|
11
|
+
files: RepoFile[];
|
|
12
|
+
message: string;
|
|
13
|
+
branch?: string;
|
|
14
|
+
}) => Promise<PushResult>;
|
|
15
|
+
getTree: (repoId: string, ref?: string) => Promise<{
|
|
16
|
+
tree: RepoTree;
|
|
17
|
+
commit_cid: string;
|
|
18
|
+
}>;
|
|
19
|
+
getBlob: (repoId: string, cid: string) => Promise<string>;
|
|
20
|
+
getLog: (repoId: string, ref?: string, maxCount?: number) => Promise<RepoCommit[]>;
|
|
21
|
+
getBranches: (repoId: string) => Promise<string[]>;
|
|
22
|
+
getDiff: (repoId: string, fromRef: string, toRef: string) => Promise<DiffEntry[]>;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Low-level hook returning a rack API client.
|
|
26
|
+
* All methods route through the host app's proxy.
|
|
27
|
+
*/
|
|
28
|
+
declare function useRackClient(config: RackConfig): RackClient;
|
|
29
|
+
|
|
30
|
+
interface UseReposReturn {
|
|
31
|
+
repos: RepoInfo[];
|
|
32
|
+
loading: boolean;
|
|
33
|
+
error: string | null;
|
|
34
|
+
refresh: () => Promise<void>;
|
|
35
|
+
}
|
|
36
|
+
declare function useRepos(config: RackConfig): UseReposReturn;
|
|
37
|
+
|
|
38
|
+
interface UseRepoTreeReturn {
|
|
39
|
+
entries: TreeEntry[];
|
|
40
|
+
loading: boolean;
|
|
41
|
+
error: string | null;
|
|
42
|
+
refresh: () => Promise<void>;
|
|
43
|
+
getFileContent: (cid: string) => Promise<string>;
|
|
44
|
+
}
|
|
45
|
+
declare function useRepoTree(config: RackConfig, repoId: string | null, ref?: string): UseRepoTreeReturn;
|
|
46
|
+
|
|
47
|
+
interface UseRepoPushReturn {
|
|
48
|
+
push: (repoId: string, files: RepoFile[], message: string, branch?: string) => Promise<PushResult | null>;
|
|
49
|
+
pushing: boolean;
|
|
50
|
+
error: string | null;
|
|
51
|
+
}
|
|
52
|
+
declare function useRepoPush(config: RackConfig): UseRepoPushReturn;
|
|
53
|
+
|
|
54
|
+
export { type RackClient, useRackClient, useRepoPush, useRepoTree, useRepos };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import {useMemo,useRef,useState,useCallback,useEffect}from'react';async function m(i,e,s){let n=await fetch(`${i}${e}`,{...s,headers:{"Content-Type":"application/json",...s?.headers}});if(!n.ok){let r=`HTTP ${n.status}`;try{let t=await n.json();t.error&&(r=t.error);}catch{}throw new Error(r)}return n.json()}function R(i){let e=i.apiBaseUrl,s=i.authorMid,n=i.ownerMid;return useMemo(()=>({async listRepos(r){let t=r||n?`?owner=${encodeURIComponent(r||n)}`:"";return (await m(e,`/api/rack/repos${t}`)).repos||[]},async initRepo(r){return m(e,"/api/rack/init",{method:"POST",body:JSON.stringify({...r,owner_mid:n})})},async push(r,t){return m(e,`/api/rack/${r}/push`,{method:"POST",body:JSON.stringify({...t,author_mid:s})})},async getTree(r,t="main"){let o=await m(e,`/api/rack/${r}/tree/${t}`);return {tree:o.tree,commit_cid:o.commit_cid}},async getBlob(r,t){return (await m(e,`/api/rack/${r}/blob/${t}`)).content},async getLog(r,t,o){let l=new URLSearchParams;t&&l.set("ref",t),o&&l.set("max_count",String(o));let g=l.toString()?`?${l}`:"";return (await m(e,`/api/rack/${r}/log${g}`)).commits||[]},async getBranches(r){return (await m(e,`/api/rack/${r}/branches`)).branches||[]},async getDiff(r,t,o){return (await m(e,`/api/rack/${r}/diff/${t}/${o}`)).diff?.entries||[]}}),[e,s,n])}function T(i){let e=R(i),s=useRef(e);s.current=e;let[n,r]=useState([]),[t,o]=useState(true),[l,g]=useState(null),c=useRef(true),u=useRef(null),p=useCallback(async()=>{u.current?.abort();let f=new AbortController;u.current=f;try{c.current&&(o(!0),g(null));let a=await s.current.listRepos();c.current&&!f.signal.aborted&&r(a);}catch(a){c.current&&!f.signal.aborted&&g(a instanceof Error?a.message:"Failed to load repos");}finally{c.current&&!f.signal.aborted&&o(false);}},[]);return useEffect(()=>(c.current=true,p(),()=>{c.current=false,u.current?.abort();}),[p]),{repos:n,loading:t,error:l,refresh:p}}function I(i){return Object.entries(i).map(([e,s])=>{let n=s.indexOf(":"),r=n>0?s.slice(0,n):"100644",t=n>0?s.slice(n+1):s;return {path:e,mode:r,cid:t,isDir:r==="040000"}}).sort((e,s)=>e.isDir!==s.isDir?e.isDir?-1:1:e.path.localeCompare(s.path))}function x(i,e,s="main"){let n=R(i),[r,t]=useState([]),[o,l]=useState(false),[g,c]=useState(null),u=useRef(true),p=useCallback(async()=>{if(e)try{u.current&&(l(!0),c(null));let{tree:a}=await n.getTree(e,s);u.current&&t(I(a.entries));}catch(a){u.current&&c(a instanceof Error?a.message:"Failed to load tree");}finally{u.current&&l(false);}},[n,e,s]);useEffect(()=>(u.current=true,p(),()=>{u.current=false;}),[p]);let f=useCallback(async a=>{if(!e)throw new Error("No repo selected");return n.getBlob(e,a)},[n,e]);return {entries:r,loading:o,error:g,refresh:p,getFileContent:f}}function U(i){let e=R(i),[s,n]=useState(false),[r,t]=useState(null),o=useRef(true);return useEffect(()=>(o.current=true,()=>{o.current=false;}),[]),{push:useCallback(async(g,c,u,p)=>{try{return o.current&&(n(!0),t(null)),await e.push(g,{files:c,message:u,branch:p})}catch(f){let a=f instanceof Error?f.message:"Push failed";return o.current&&t(a),null}finally{o.current&&n(false);}},[e]),pushing:s,error:r}}export{R as useRackClient,U as useRepoPush,x as useRepoTree,T as useRepos};
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
'use strict';var react=require('react'),lucideReact=require('lucide-react'),clsx=require('clsx'),tailwindMerge=require('tailwind-merge'),jsxRuntime=require('react/jsx-runtime');async function T(n,e,s){let t=await fetch(`${n}${e}`,{...s,headers:{"Content-Type":"application/json",...s?.headers}});if(!t.ok){let o=`HTTP ${t.status}`;try{let a=await t.json();a.error&&(o=a.error);}catch{}throw new Error(o)}return t.json()}function z(n){let e=n.apiBaseUrl,s=n.authorMid,t=n.ownerMid;return react.useMemo(()=>({async listRepos(o){let a=o||t?`?owner=${encodeURIComponent(o||t)}`:"";return (await T(e,`/api/rack/repos${a}`)).repos||[]},async initRepo(o){return T(e,"/api/rack/init",{method:"POST",body:JSON.stringify({...o,owner_mid:t})})},async push(o,a){return T(e,`/api/rack/${o}/push`,{method:"POST",body:JSON.stringify({...a,author_mid:s})})},async getTree(o,a="main"){let i=await T(e,`/api/rack/${o}/tree/${a}`);return {tree:i.tree,commit_cid:i.commit_cid}},async getBlob(o,a){return (await T(e,`/api/rack/${o}/blob/${a}`)).content},async getLog(o,a,i){let l=new URLSearchParams;a&&l.set("ref",a),i&&l.set("max_count",String(i));let m=l.toString()?`?${l}`:"";return (await T(e,`/api/rack/${o}/log${m}`)).commits||[]},async getBranches(o){return (await T(e,`/api/rack/${o}/branches`)).branches||[]},async getDiff(o,a,i){return (await T(e,`/api/rack/${o}/diff/${a}/${i}`)).diff?.entries||[]}}),[e,s,t])}function _(n){let e=z(n),s=react.useRef(e);s.current=e;let[t,o]=react.useState([]),[a,i]=react.useState(true),[l,m]=react.useState(null),p=react.useRef(true),f=react.useRef(null),x=react.useCallback(async()=>{f.current?.abort();let u=new AbortController;f.current=u;try{p.current&&(i(!0),m(null));let d=await s.current.listRepos();p.current&&!u.signal.aborted&&o(d);}catch(d){p.current&&!u.signal.aborted&&m(d instanceof Error?d.message:"Failed to load repos");}finally{p.current&&!u.signal.aborted&&i(false);}},[]);return react.useEffect(()=>(p.current=true,x(),()=>{p.current=false,f.current?.abort();}),[x]),{repos:t,loading:a,error:l,refresh:x}}function me(n){return Object.entries(n).map(([e,s])=>{let t=s.indexOf(":"),o=t>0?s.slice(0,t):"100644",a=t>0?s.slice(t+1):s;return {path:e,mode:o,cid:a,isDir:o==="040000"}}).sort((e,s)=>e.isDir!==s.isDir?e.isDir?-1:1:e.path.localeCompare(s.path))}function F(n,e,s="main"){let t=z(n),[o,a]=react.useState([]),[i,l]=react.useState(false),[m,p]=react.useState(null),f=react.useRef(true),x=react.useCallback(async()=>{if(e)try{f.current&&(l(!0),p(null));let{tree:d}=await t.getTree(e,s);f.current&&a(me(d.entries));}catch(d){f.current&&p(d instanceof Error?d.message:"Failed to load tree");}finally{f.current&&l(false);}},[t,e,s]);react.useEffect(()=>(f.current=true,x(),()=>{f.current=false;}),[x]);let u=react.useCallback(async d=>{if(!e)throw new Error("No repo selected");return t.getBlob(e,d)},[t,e]);return {entries:o,loading:i,error:m,refresh:x,getFileContent:u}}function he(n){let e=z(n),[s,t]=react.useState(false),[o,a]=react.useState(null),i=react.useRef(true);return react.useEffect(()=>(i.current=true,()=>{i.current=false;}),[]),{push:react.useCallback(async(m,p,f,x)=>{try{return i.current&&(t(!0),a(null)),await e.push(m,{files:p,message:f,branch:x})}catch(u){let d=u instanceof Error?u.message:"Push failed";return i.current&&a(d),null}finally{i.current&&t(false);}},[e]),pushing:s,error:o}}function N(...n){return tailwindMerge.twMerge(clsx.clsx(n))}var we=/^(https?:\/\/|mailto:|\/[^/])/i;function be(n){let e=n.trim();return we.test(e)?e:null}function M(n){let e=[],s=/(`[^`]+`)|(\*\*(.+?)\*\*)|(\*(.+?)\*)|(_(.+?)_)|(\[([^\]]+)\]\(([^)]+)\))/g,t=0,o,a=0;for(;(o=s.exec(n))!==null;){o.index>t&&e.push(n.slice(t,o.index));let i=`i${a++}`;if(o[1])e.push(jsxRuntime.jsx("code",{className:"rounded bg-muted px-1.5 py-0.5 text-[0.85em] font-mono text-pink-400",children:o[1].slice(1,-1)},i));else if(o[2])e.push(jsxRuntime.jsx("strong",{children:o[3]},i));else if(o[4])e.push(jsxRuntime.jsx("em",{children:o[5]},i));else if(o[6])e.push(jsxRuntime.jsx("em",{children:o[7]},i));else if(o[8]){let l=be(o[10]);l?e.push(jsxRuntime.jsx("a",{href:l,className:"text-blue-400 underline hover:text-blue-300",target:"_blank",rel:"noopener noreferrer",children:o[9]},i)):e.push(o[9]);}t=o.index+o[0].length;}return t<n.length&&e.push(n.slice(t)),e.length>0?e:[n]}function ye(n){let e=n.split(`
|
|
2
|
+
`),s=[],t=0;for(;t<e.length;){let o=e[t];if(o.trim()===""){t++;continue}if(/^(-{3,}|\*{3,}|_{3,})$/.test(o.trim())){s.push({type:"hr"}),t++;continue}let a=o.match(/^(#{1,6})\s+(.+)/);if(a){s.push({type:"heading",level:a[1].length,content:a[2]}),t++;continue}if(o.trim().startsWith("```")){let l=o.trim().slice(3).trim(),m=[];for(t++;t<e.length&&!e[t].trim().startsWith("```");)m.push(e[t]),t++;s.push({type:"code",content:m.join(`
|
|
3
|
+
`),lang:l||void 0}),t++;continue}if(/^\s*[-*+]\s/.test(o)){let l=[];for(;t<e.length&&/^\s*[-*+]\s/.test(e[t]);)l.push(e[t].replace(/^\s*[-*+]\s+/,"")),t++;s.push({type:"ul",items:l});continue}if(/^\s*\d+[.)]\s/.test(o)){let l=[];for(;t<e.length&&/^\s*\d+[.)]\s/.test(e[t]);)l.push(e[t].replace(/^\s*\d+[.)]\s+/,"")),t++;s.push({type:"ol",items:l});continue}let i=[];for(;t<e.length&&e[t].trim()!==""&&!e[t].match(/^#{1,6}\s/)&&!e[t].trim().startsWith("```")&&!/^\s*[-*+]\s/.test(e[t])&&!/^\s*\d+[.)]\s/.test(e[t]);)i.push(e[t]),t++;i.length>0&&s.push({type:"paragraph",content:i.join(" ")});}return s}var ke={1:"text-2xl font-bold mt-6 mb-3",2:"text-xl font-bold mt-5 mb-2",3:"text-lg font-semibold mt-4 mb-2",4:"text-base font-semibold mt-3 mb-1",5:"text-sm font-semibold mt-2 mb-1",6:"text-sm font-medium mt-2 mb-1"};function Re(n,e){switch(n.type){case "hr":return jsxRuntime.jsx("hr",{className:"my-4 border-border"},`b${e}`);case "heading":{let s=Math.min(Math.max(n.level||1,1),6),t=`h${s}`;return jsxRuntime.jsx(t,{className:N("text-foreground",ke[s]),children:M(n.content||"")},`b${e}`)}case "paragraph":return jsxRuntime.jsx("p",{className:"mb-3 leading-relaxed text-foreground",children:M(n.content||"")},`b${e}`);case "code":return jsxRuntime.jsx("pre",{className:"mb-3 overflow-x-auto rounded-lg bg-muted p-4 text-sm font-mono leading-relaxed text-foreground",children:jsxRuntime.jsx("code",{children:n.content})},`b${e}`);case "ul":return jsxRuntime.jsx("ul",{className:"mb-3 ml-5 list-disc space-y-1 text-foreground",children:n.items?.map((s,t)=>jsxRuntime.jsx("li",{className:"leading-relaxed",children:M(s)},`li${e}-${t}`))},`b${e}`);case "ol":return jsxRuntime.jsx("ol",{className:"mb-3 ml-5 list-decimal space-y-1 text-foreground",children:n.items?.map((s,t)=>jsxRuntime.jsx("li",{className:"leading-relaxed",children:M(s)},`li${e}-${t}`))},`b${e}`);default:return null}}function U({content:n,className:e}){let s=ye(n);return jsxRuntime.jsx("div",{className:N("text-sm",e),children:s.map((t,o)=>Re(t,o))})}function Y({open:n,className:e}){return jsxRuntime.jsx("svg",{width:"16",height:"16",viewBox:"0 0 20 20",fill:"currentColor",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",className:N("shrink-0 transition-transform duration-150",n?"rotate-0":"-rotate-90",e),children:jsxRuntime.jsx("path",{d:"M16.134 6.16a.5.5 0 1 1 .732.68l-6.5 7-.077.068a.5.5 0 0 1-.655-.068l-6.5-7-.062-.08a.5.5 0 0 1 .718-.667l.076.067L10 12.767z"})})}function G({size:n=20,className:e}){return jsxRuntime.jsx("svg",{width:n,height:n,viewBox:"0 0 20 20",fill:"currentColor",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",className:e,children:jsxRuntime.jsx("path",{d:"M8.5 2a6.5 6.5 0 0 1 4.935 10.728l4.419 4.419.064.078a.5.5 0 0 1-.693.693l-.079-.064-4.419-4.42A6.5 6.5 0 1 1 8.5 2m0 1a5.5 5.5 0 1 0 0 11 5.5 5.5 0 0 0 0-11"})})}function D({size:n=20,className:e}){return jsxRuntime.jsx("svg",{width:n,height:n,viewBox:"0 0 20 20",fill:"currentColor",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",className:e,children:jsxRuntime.jsx("path",{d:"M15.147 4.146a.5.5 0 0 1 .707.707L10.707 10l5.147 5.147a.5.5 0 0 1-.63.771l-.078-.064L10 10.707l-5.146 5.147a.5.5 0 0 1-.708-.707L9.293 10 4.146 4.853a.5.5 0 0 1 .708-.707L10 9.293z"})})}function X({size:n=20,className:e}){return jsxRuntime.jsx("svg",{width:n,height:n,viewBox:"0 0 20 20",fill:"currentColor",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",className:e,children:jsxRuntime.jsx("path",{d:"M10 3a.5.5 0 0 1 .5.5v6h6l.1.01a.5.5 0 0 1 0 .98l-.1.01h-6v6a.5.5 0 0 1-1 0v-6h-6a.5.5 0 0 1 0-1h6v-6A.5.5 0 0 1 10 3"})})}function Ee(){return jsxRuntime.jsx("svg",{width:"20",height:"20",viewBox:"0 0 20 20",fill:"currentColor",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",className:"shrink-0",children:jsxRuntime.jsx("path",{d:"M6.5 3A2.5 2.5 0 0 0 4 5.5v9A2.5 2.5 0 0 0 6.5 17h7a2.5 2.5 0 0 0 2.5-2.5v-7A2.5 2.5 0 0 0 13.5 5H11V3.5a.5.5 0 0 0-1 0V5H6.5ZM5 5.5A1.5 1.5 0 0 1 6.5 4H9v1H6.5A1.5 1.5 0 0 0 5 6.5v8A1.5 1.5 0 0 0 6.5 16h7a1.5 1.5 0 0 0 1.5-1.5v-7A1.5 1.5 0 0 0 13.5 6H11V4h2.5A2.5 2.5 0 0 1 16 6.5v8a2.5 2.5 0 0 1-2.5 2.5h-7A2.5 2.5 0 0 1 4 14.5v-9Z"})})}function Te(){return jsxRuntime.jsx("svg",{width:"20",height:"20",viewBox:"0 0 20 20",fill:"currentColor",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",className:"shrink-0",children:jsxRuntime.jsx("path",{d:"M5.5 3A2.5 2.5 0 0 0 3 5.5v9A2.5 2.5 0 0 0 5.5 17h9a2.5 2.5 0 0 0 2.5-2.5v-9A2.5 2.5 0 0 0 14.5 3h-9ZM4 5.5A1.5 1.5 0 0 1 5.5 4h9A1.5 1.5 0 0 1 16 5.5v9a1.5 1.5 0 0 1-1.5 1.5h-9A1.5 1.5 0 0 1 4 14.5v-9ZM7 7.5a.5.5 0 0 1 .5-.5h5a.5.5 0 0 1 0 1h-5a.5.5 0 0 1-.5-.5Zm0 3a.5.5 0 0 1 .5-.5h5a.5.5 0 0 1 0 1h-5a.5.5 0 0 1-.5-.5Zm0 3a.5.5 0 0 1 .5-.5h3a.5.5 0 0 1 0 1h-3a.5.5 0 0 1-.5-.5Z"})})}function ze(){return jsxRuntime.jsx("svg",{width:"20",height:"20",viewBox:"0 0 20 20",fill:"currentColor",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",className:"shrink-0",children:jsxRuntime.jsx("path",{d:"M10 2a.5.5 0 0 1 .354.146l3 3a.5.5 0 0 1-.708.708L10.5 3.707V12.5a.5.5 0 0 1-1 0V3.707L7.354 5.854a.5.5 0 1 1-.708-.708l3-3A.5.5 0 0 1 10 2ZM4 13.5a.5.5 0 0 1 1 0v1A1.5 1.5 0 0 0 6.5 16h7a1.5 1.5 0 0 0 1.5-1.5v-1a.5.5 0 0 1 1 0v1a2.5 2.5 0 0 1-2.5 2.5h-7A2.5 2.5 0 0 1 4 14.5v-1Z"})})}function ee(){let[n,e]=react.useState(false);return react.useEffect(()=>{if(typeof window>"u")return;let s=()=>e(window.innerWidth<768);return s(),window.addEventListener("resize",s),()=>window.removeEventListener("resize",s)},[]),n}function te({onClose:n,children:e,title:s}){let t=ee(),o=react.useRef(n);return o.current=n,react.useEffect(()=>{let a=i=>{i.key==="Escape"&&o.current();};return window.addEventListener("keydown",a),()=>window.removeEventListener("keydown",a)},[]),t?jsxRuntime.jsxs("div",{className:"fixed inset-0 z-50 flex items-end justify-center",onClick:n,children:[jsxRuntime.jsx("div",{className:"fixed inset-0 bg-black/50"}),jsxRuntime.jsxs("div",{className:"relative z-10 w-full max-h-[90vh] overflow-y-auto rounded-t-2xl bg-[#1a1a1a] p-5 pb-8 animate-in slide-in-from-bottom duration-200",onClick:a=>a.stopPropagation(),children:[jsxRuntime.jsx("div",{className:"mx-auto mb-4 h-1 w-10 rounded-full bg-zinc-600"}),jsxRuntime.jsxs("div",{className:"flex items-center justify-between mb-5",children:[jsxRuntime.jsx("h2",{className:"text-lg font-semibold text-foreground",children:s}),jsxRuntime.jsx("button",{onClick:n,className:"rounded p-1 text-muted-foreground hover:text-foreground",children:jsxRuntime.jsx(D,{size:20})})]}),e]})]}):jsxRuntime.jsxs("div",{className:"fixed inset-0 z-50 flex items-center justify-center",onClick:n,children:[jsxRuntime.jsx("div",{className:"fixed inset-0 bg-black/50"}),jsxRuntime.jsxs("div",{className:"relative z-10 w-full max-w-lg overflow-y-auto rounded-2xl bg-[#1a1a1a] p-6 shadow-2xl animate-in fade-in zoom-in-95 duration-150",onClick:a=>a.stopPropagation(),children:[jsxRuntime.jsxs("div",{className:"flex items-center justify-between mb-5",children:[jsxRuntime.jsx("h2",{className:"text-lg font-semibold text-foreground",children:s}),jsxRuntime.jsx("button",{onClick:n,className:"rounded p-1 text-muted-foreground hover:text-foreground",children:jsxRuntime.jsx(D,{size:20})})]}),e]})]})}function Pe({onClose:n,onCreated:e,config:s}){let[t,o]=react.useState(""),[a,i]=react.useState(""),[l,m]=react.useState(""),[p,f]=react.useState(false),[x,u]=react.useState(null);return jsxRuntime.jsx(te,{title:"Write skill instructions",onClose:n,children:jsxRuntime.jsxs("div",{className:"space-y-4",children:[jsxRuntime.jsxs("div",{className:"space-y-1.5",children:[jsxRuntime.jsx("label",{htmlFor:"skill-name",className:"text-sm text-muted-foreground",children:"Skill name"}),jsxRuntime.jsx("input",{id:"skill-name",value:t,onChange:v=>o(v.target.value),placeholder:"weekly-status-report",className:"w-full rounded-lg border border-zinc-700 bg-[#252525] px-3 py-2.5 text-sm text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-zinc-500"})]}),jsxRuntime.jsxs("div",{className:"space-y-1.5",children:[jsxRuntime.jsx("label",{htmlFor:"skill-desc",className:"text-sm text-muted-foreground",children:"Description"}),jsxRuntime.jsx("textarea",{id:"skill-desc",value:a,onChange:v=>i(v.target.value),placeholder:"Generate weekly status reports from recent work.",rows:3,className:"w-full rounded-lg border border-zinc-700 bg-[#252525] px-3 py-2.5 text-sm text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-zinc-500"})]}),jsxRuntime.jsxs("div",{className:"space-y-1.5",children:[jsxRuntime.jsx("label",{htmlFor:"skill-instructions",className:"text-sm text-muted-foreground",children:"Instructions"}),jsxRuntime.jsx("textarea",{id:"skill-instructions",value:l,onChange:v=>m(v.target.value),placeholder:"Summarize my recent work in three sections: wins, blockers, and next steps.",rows:8,className:"w-full rounded-lg border border-zinc-700 bg-[#252525] px-3 py-2.5 text-sm text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-zinc-500"})]}),x&&jsxRuntime.jsx("p",{className:"text-sm text-red-500",children:x}),jsxRuntime.jsxs("div",{className:"flex justify-end gap-3 pt-2",children:[jsxRuntime.jsx("button",{onClick:n,className:"rounded-lg border border-zinc-700 px-4 py-2 text-sm text-foreground hover:bg-zinc-800",children:"Cancel"}),jsxRuntime.jsx("button",{onClick:async()=>{if(t.trim()){f(true),u(null);try{let v=s.apiBaseUrl||"",R=await fetch(`${v}/api/rack/init`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:t.trim(),description:a.trim(),owner_mid:s.ownerMid,is_gitagent:!0})});if(!R.ok){let b=`Failed to create skill (${R.status})`;try{let y=await R.json();y.error&&(b=y.error);}catch{}throw new Error(b)}let{repo_id:E}=await R.json(),P=`# ${t.trim()}
|
|
4
|
+
|
|
5
|
+
${a.trim()}
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
${l.trim()}`,k=await fetch(`${v}/api/rack/${E}/push`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({files:[{path:"SKILL.md",content:P}],message:"Initial skill definition",author_mid:s.authorMid})});if(!k.ok){let b=`Failed to save skill (${k.status})`;try{let y=await k.json();y.error&&(b=y.error);}catch{}throw new Error(b)}e?.(),n();}catch(v){u(v instanceof Error?v.message:"Failed to create skill");}finally{f(false);}}},disabled:p||!t.trim(),className:"rounded-lg bg-zinc-600 px-4 py-2 text-sm font-medium text-white hover:bg-zinc-500 disabled:opacity-50",children:p?"Creating...":"Create"})]})]})})}function $e({onClose:n,onCreated:e,config:s}){let t=react.useRef(null),[o,a]=react.useState(false),[i,l]=react.useState(false),[m,p]=react.useState(null),f=async u=>{l(true),p(null);try{let d=await u.text(),v=s.apiBaseUrl||"",R=u.name.replace(/\.[^.]+$/,"").replace(/[^a-zA-Z0-9-_]/g,"-"),E=await fetch(`${v}/api/rack/init`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:R,owner_mid:s.ownerMid,is_gitagent:!0})});if(!E.ok){let b=`Failed to create repo (${E.status})`;try{let y=await E.json();y.error&&(b=y.error);}catch{}throw new Error(b)}let{repo_id:P}=await E.json(),k=await fetch(`${v}/api/rack/${P}/push`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({files:[{path:u.name,content:d}],message:`Upload ${u.name}`,author_mid:s.authorMid})});if(!k.ok){let b=`Upload failed (${k.status})`;try{let y=await k.json();y.error&&(b=y.error);}catch{}throw new Error(b)}e?.(),n();}catch(d){p(d instanceof Error?d.message:"Upload failed");}finally{l(false);}};return jsxRuntime.jsx(te,{title:"Upload skill",onClose:n,children:jsxRuntime.jsxs("div",{className:"space-y-4",children:[jsxRuntime.jsxs("div",{onDragOver:u=>{u.preventDefault(),a(true);},onDragLeave:()=>a(false),onDrop:u=>{u.preventDefault(),a(false);let d=u.dataTransfer.files[0];d&&f(d);},onClick:()=>t.current?.click(),className:N("flex cursor-pointer flex-col items-center justify-center gap-3 rounded-xl border-2 border-dashed p-10 transition-colors",o?"border-zinc-400 bg-zinc-800/50":"border-zinc-700 hover:border-zinc-500"),children:[jsxRuntime.jsx("div",{className:"rounded-lg border border-zinc-600 p-2",children:jsxRuntime.jsx(X,{size:20,className:"text-muted-foreground"})}),jsxRuntime.jsx("p",{className:"text-sm text-muted-foreground",children:i?"Uploading...":"Drag and drop or click to upload"})]}),jsxRuntime.jsx("input",{ref:t,type:"file",accept:".md,.zip,.skill,.txt,.yml,.yaml",className:"hidden","aria-label":"Upload skill file",onChange:u=>{let d=u.target.files?.[0];d&&f(d);}}),m&&jsxRuntime.jsx("p",{className:"text-sm text-red-500",children:m}),jsxRuntime.jsxs("div",{className:"space-y-2 text-xs text-muted-foreground",children:[jsxRuntime.jsx("p",{className:"font-medium text-foreground/70",children:"File requirements"}),jsxRuntime.jsxs("ul",{className:"list-disc pl-5 space-y-1",children:[jsxRuntime.jsx("li",{children:".md file must contain skill name and description formatted in YAML"}),jsxRuntime.jsx("li",{children:".zip or .skill file must include a SKILL.md file"})]})]})]})})}function Se({onClose:n,onSelect:e}){let s=ee(),t=react.useRef(null),o=react.useRef(n);o.current=n,react.useEffect(()=>{if(s)return;let i=l=>{t.current&&l.target instanceof Node&&!t.current.contains(l.target)&&o.current();};return document.addEventListener("mousedown",i),()=>document.removeEventListener("mousedown",i)},[s]);let a=[{id:"create-with-geoff",icon:jsxRuntime.jsx(Ee,{}),label:"Create with Geoff"},{id:"write",icon:jsxRuntime.jsx(Te,{}),label:"Write skill instructions"},{id:"upload",icon:jsxRuntime.jsx(ze,{}),label:"Upload a skill"}];return s?jsxRuntime.jsxs("div",{className:"fixed inset-0 z-50 flex items-end",onClick:n,children:[jsxRuntime.jsx("div",{className:"fixed inset-0 bg-black/50"}),jsxRuntime.jsxs("div",{className:"relative z-10 w-full rounded-t-2xl bg-[#1a1a1a] p-4 pb-8 animate-in slide-in-from-bottom duration-200",onClick:i=>i.stopPropagation(),children:[jsxRuntime.jsx("div",{className:"mx-auto mb-3 h-1 w-10 rounded-full bg-zinc-600"}),a.map(i=>jsxRuntime.jsxs("button",{onClick:()=>{e(i.id),n();},className:"flex w-full items-center gap-3 rounded-lg px-4 py-3 text-sm text-foreground transition-colors hover:bg-zinc-800",children:[i.icon,i.label]},i.id))]})]}):jsxRuntime.jsx("div",{ref:t,className:"absolute right-2 top-11 z-50 w-56 overflow-hidden rounded-xl border border-zinc-700 bg-[#2a2a2a] shadow-xl animate-in fade-in zoom-in-95 duration-100",children:a.map(i=>jsxRuntime.jsxs("button",{onClick:()=>{e(i.id),n();},className:"flex w-full items-center gap-3 px-4 py-3 text-sm text-foreground transition-colors hover:bg-zinc-700/50",children:[i.icon,i.label]},i.id))})}function Me({entry:n,selected:e,onSelect:s,depth:t=0}){return jsxRuntime.jsxs("button",{onClick:()=>s(n),className:N("flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-left text-sm transition-colors",e?"bg-[#141414] text-foreground":"text-muted-foreground hover:bg-muted/50 hover:text-foreground"),style:{paddingLeft:`${8+t*16}px`},children:[jsxRuntime.jsx("span",{className:"truncate flex-1",children:n.path.split("/").pop()}),n.isDir&&jsxRuntime.jsx(Y,{className:"ml-auto text-muted-foreground"})]})}function Ie({repo:n,selected:e,expanded:s,onSelect:t,onToggle:o,children:a}){return jsxRuntime.jsxs("div",{children:[jsxRuntime.jsxs("button",{onClick:()=>{t(),o();},className:N("flex w-full items-center gap-2 rounded-md px-2 py-2 text-left text-sm font-medium transition-colors",e?"bg-[#141414] text-foreground":"text-muted-foreground hover:bg-muted/50 hover:text-foreground"),children:[jsxRuntime.jsx(Y,{open:s}),jsxRuntime.jsx(lucideReact.FileText,{className:"h-4 w-4 shrink-0"}),jsxRuntime.jsx("span",{className:"truncate",children:n.name})]}),s&&a]})}function Le({entry:n,content:e,loading:s,repoName:t}){let[o,a]=react.useState(false),i=react.useRef(null);react.useEffect(()=>()=>{i.current&&clearTimeout(i.current);},[]);let[l,m]=react.useState(false),p=async()=>{if(e)try{await navigator.clipboard.writeText(e),a(!0),m(!1),i.current&&clearTimeout(i.current),i.current=setTimeout(()=>a(!1),2e3);}catch{m(true),i.current&&clearTimeout(i.current),i.current=setTimeout(()=>m(false),2e3);}};if(!n)return jsxRuntime.jsx("div",{className:"flex h-full items-center justify-center text-sm text-muted-foreground",children:"Select a file to view its content"});if(s)return jsxRuntime.jsx("div",{className:"flex h-full items-center justify-center",children:jsxRuntime.jsx(lucideReact.Loader2,{className:"h-5 w-5 animate-spin text-muted-foreground"})});let f=n.path.split("/").pop()||n.path,x=/\.(md|mdx)$/i.test(f);return jsxRuntime.jsxs("div",{className:"flex h-full flex-col px-3",children:[jsxRuntime.jsxs("div",{className:"flex items-center justify-between px-4 py-3",children:[jsxRuntime.jsx("h3",{className:"text-sm sm:text-lg font-semibold text-foreground",children:f}),jsxRuntime.jsx("button",{onClick:p,"aria-label":"Copy file content",className:N("rounded p-1 transition-colors",o?"text-green-500":l?"text-red-500":"text-muted-foreground hover:text-foreground"),children:jsxRuntime.jsx("svg",{width:"20",height:"20",viewBox:"0 0 20 20",fill:"currentColor",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",className:"shrink-0",children:jsxRuntime.jsx("path",{d:"M12.5 3A1.5 1.5 0 0 1 14 4.5V6h1.5A1.5 1.5 0 0 1 17 7.5v8a1.5 1.5 0 0 1-1.5 1.5h-8A1.5 1.5 0 0 1 6 15.5V14H4.5A1.5 1.5 0 0 1 3 12.5v-8A1.5 1.5 0 0 1 4.5 3zm1.5 9.5a1.5 1.5 0 0 1-1.5 1.5H7v1.5a.5.5 0 0 0 .5.5h8a.5.5 0 0 0 .5-.5v-8a.5.5 0 0 0-.5-.5H14zM4.5 4a.5.5 0 0 0-.5.5v8a.5.5 0 0 0 .5.5h8a.5.5 0 0 0 .5-.5v-8a.5.5 0 0 0-.5-.5z"})})})]}),jsxRuntime.jsx("div",{className:"flex-1 overflow-auto p-4",children:x?jsxRuntime.jsx(U,{content:e||""}):jsxRuntime.jsx("pre",{className:"whitespace-pre-wrap text-sm text-foreground font-mono leading-relaxed",children:e||""})})]})}function Ae({config:n,category:e,className:s,style:t}){let{repos:o,loading:a,error:i,refresh:l}=_(n),[m,p]=react.useState(null),[f,x]=react.useState(null),[u,d]=react.useState(null),[v,R]=react.useState(null),[E,P]=react.useState(false),[k,b]=react.useState(""),[y,j]=react.useState(false),[O,H]=react.useState(false),[V,I]=react.useState(null),re=o.find(g=>g.repo_id===m),{entries:ne,getFileContent:Z}=F(n,f),W=o.filter(g=>!k||g.name.toLowerCase().includes(k.toLowerCase())),oe=react.useCallback(async g=>{if(!g.isDir){d(g),P(true);try{let C=await Z(g.cid);R(C);}catch(C){let ie=C instanceof Error?C.message:"Unknown error";R(`Failed to load file: ${ie}`);}finally{P(false);}}},[Z]);react.useEffect(()=>{o.length>0&&!m&&(p(o[0].repo_id),x(o[0].repo_id));},[o,m]);let se=g=>{g==="create-with-geoff"?window.open(`https://www.geoff.ai/?p=${encodeURIComponent("Let's create a skill together using your skill-creator skill. First ask me what the skill should do.")}`,"_blank","noopener,noreferrer"):I(g);};return jsxRuntime.jsxs("div",{className:N("flex flex-1 h-full min-h-0",s),style:t,children:[jsxRuntime.jsxs("div",{className:"relative flex w-96 shrink-0 flex-col border-r",children:[jsxRuntime.jsx("div",{className:"flex h-12 items-center gap-2 px-3",children:y?jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[jsxRuntime.jsxs("div",{className:"flex flex-1 items-center gap-2 rounded-md border bg-muted/50 px-2 py-1",children:[jsxRuntime.jsx(G,{size:16,className:"shrink-0 text-muted-foreground"}),jsxRuntime.jsx("input",{type:"text",value:k,onChange:g=>b(g.target.value),placeholder:"Search",autoFocus:true,"aria-label":"Search items",className:"flex-1 bg-transparent text-xs text-foreground placeholder:text-muted-foreground focus:outline-none"})]}),jsxRuntime.jsx("button",{onClick:()=>{j(false),b("");},className:"rounded p-1 text-muted-foreground hover:text-foreground",children:jsxRuntime.jsx(D,{size:16})})]}):jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[jsxRuntime.jsx("h3",{className:"flex-1 text-sm sm:text-lg font-semibold text-foreground capitalize",children:e||"Items"}),jsxRuntime.jsx("button",{onClick:()=>j(true),className:"rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground","aria-label":"Search",children:jsxRuntime.jsx(G,{size:20})}),jsxRuntime.jsx("button",{onClick:()=>H(!O),className:"rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground","aria-label":"Add new",children:jsxRuntime.jsx(X,{size:20})})]})}),O&&jsxRuntime.jsx(Se,{onClose:()=>H(false),onSelect:se}),jsxRuntime.jsx("div",{className:"flex-1 overflow-y-auto p-2",children:a?jsxRuntime.jsx("div",{className:"flex items-center justify-center py-8",children:jsxRuntime.jsx(lucideReact.Loader2,{className:"h-5 w-5 animate-spin text-muted-foreground"})}):i?jsxRuntime.jsx("p",{className:"px-2 py-4 text-xs text-red-500",children:i}):W.length===0?jsxRuntime.jsx("p",{className:"px-2 py-4 text-xs text-muted-foreground",children:k?"No matching items":"No items yet"}):jsxRuntime.jsx("div",{className:"space-y-0.5",children:W.map(g=>jsxRuntime.jsx(Ie,{repo:g,selected:m===g.repo_id,expanded:f===g.repo_id,onSelect:()=>{p(g.repo_id),d(null),R(null);},onToggle:()=>x(f===g.repo_id?null:g.repo_id),children:jsxRuntime.jsx("div",{className:"ml-10 pl-1",children:ne.map(C=>jsxRuntime.jsx(Me,{entry:C,selected:u?.path===C.path,onSelect:oe,depth:C.path.split("/").length-1},C.path))})},g.repo_id))})})]}),jsxRuntime.jsx("div",{className:"flex-1 min-w-0",children:jsxRuntime.jsx(Le,{entry:u,content:v,loading:E,repoName:re?.name||""})}),V==="write"&&jsxRuntime.jsx(Pe,{config:n,onClose:()=>I(null),onCreated:l}),V==="upload"&&jsxRuntime.jsx($e,{config:n,onClose:()=>I(null),onCreated:l})]})}
|
|
10
|
+
exports.Markdown=U;exports.RackBrowser=Ae;exports.useRackClient=z;exports.useRepoPush=he;exports.useRepoTree=F;exports.useRepos=_;
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { DiffEntry, InitResult, PushResult, RackConfig, RepoCommit, RepoFile, RepoInfo, RepoTree, TreeEntry } from './types/index.cjs';
|
|
2
|
+
export { RackClient, useRackClient, useRepoPush, useRepoTree, useRepos } from './hooks/index.cjs';
|
|
3
|
+
export { Markdown, RackBrowser, RackBrowserProps } from './components/index.cjs';
|
|
4
|
+
import 'react/jsx-runtime';
|
|
5
|
+
import 'react';
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { DiffEntry, InitResult, PushResult, RackConfig, RepoCommit, RepoFile, RepoInfo, RepoTree, TreeEntry } from './types/index.js';
|
|
2
|
+
export { RackClient, useRackClient, useRepoPush, useRepoTree, useRepos } from './hooks/index.js';
|
|
3
|
+
export { Markdown, RackBrowser, RackBrowserProps } from './components/index.js';
|
|
4
|
+
import 'react/jsx-runtime';
|
|
5
|
+
import 'react';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import {useMemo,useRef,useState,useCallback,useEffect}from'react';import {Loader2,FileText}from'lucide-react';import {clsx}from'clsx';import {twMerge}from'tailwind-merge';import {jsx,jsxs,Fragment}from'react/jsx-runtime';async function T(n,e,s){let t=await fetch(`${n}${e}`,{...s,headers:{"Content-Type":"application/json",...s?.headers}});if(!t.ok){let o=`HTTP ${t.status}`;try{let a=await t.json();a.error&&(o=a.error);}catch{}throw new Error(o)}return t.json()}function z(n){let e=n.apiBaseUrl,s=n.authorMid,t=n.ownerMid;return useMemo(()=>({async listRepos(o){let a=o||t?`?owner=${encodeURIComponent(o||t)}`:"";return (await T(e,`/api/rack/repos${a}`)).repos||[]},async initRepo(o){return T(e,"/api/rack/init",{method:"POST",body:JSON.stringify({...o,owner_mid:t})})},async push(o,a){return T(e,`/api/rack/${o}/push`,{method:"POST",body:JSON.stringify({...a,author_mid:s})})},async getTree(o,a="main"){let i=await T(e,`/api/rack/${o}/tree/${a}`);return {tree:i.tree,commit_cid:i.commit_cid}},async getBlob(o,a){return (await T(e,`/api/rack/${o}/blob/${a}`)).content},async getLog(o,a,i){let l=new URLSearchParams;a&&l.set("ref",a),i&&l.set("max_count",String(i));let m=l.toString()?`?${l}`:"";return (await T(e,`/api/rack/${o}/log${m}`)).commits||[]},async getBranches(o){return (await T(e,`/api/rack/${o}/branches`)).branches||[]},async getDiff(o,a,i){return (await T(e,`/api/rack/${o}/diff/${a}/${i}`)).diff?.entries||[]}}),[e,s,t])}function _(n){let e=z(n),s=useRef(e);s.current=e;let[t,o]=useState([]),[a,i]=useState(true),[l,m]=useState(null),p=useRef(true),f=useRef(null),x=useCallback(async()=>{f.current?.abort();let u=new AbortController;f.current=u;try{p.current&&(i(!0),m(null));let d=await s.current.listRepos();p.current&&!u.signal.aborted&&o(d);}catch(d){p.current&&!u.signal.aborted&&m(d instanceof Error?d.message:"Failed to load repos");}finally{p.current&&!u.signal.aborted&&i(false);}},[]);return useEffect(()=>(p.current=true,x(),()=>{p.current=false,f.current?.abort();}),[x]),{repos:t,loading:a,error:l,refresh:x}}function me(n){return Object.entries(n).map(([e,s])=>{let t=s.indexOf(":"),o=t>0?s.slice(0,t):"100644",a=t>0?s.slice(t+1):s;return {path:e,mode:o,cid:a,isDir:o==="040000"}}).sort((e,s)=>e.isDir!==s.isDir?e.isDir?-1:1:e.path.localeCompare(s.path))}function F(n,e,s="main"){let t=z(n),[o,a]=useState([]),[i,l]=useState(false),[m,p]=useState(null),f=useRef(true),x=useCallback(async()=>{if(e)try{f.current&&(l(!0),p(null));let{tree:d}=await t.getTree(e,s);f.current&&a(me(d.entries));}catch(d){f.current&&p(d instanceof Error?d.message:"Failed to load tree");}finally{f.current&&l(false);}},[t,e,s]);useEffect(()=>(f.current=true,x(),()=>{f.current=false;}),[x]);let u=useCallback(async d=>{if(!e)throw new Error("No repo selected");return t.getBlob(e,d)},[t,e]);return {entries:o,loading:i,error:m,refresh:x,getFileContent:u}}function he(n){let e=z(n),[s,t]=useState(false),[o,a]=useState(null),i=useRef(true);return useEffect(()=>(i.current=true,()=>{i.current=false;}),[]),{push:useCallback(async(m,p,f,x)=>{try{return i.current&&(t(!0),a(null)),await e.push(m,{files:p,message:f,branch:x})}catch(u){let d=u instanceof Error?u.message:"Push failed";return i.current&&a(d),null}finally{i.current&&t(false);}},[e]),pushing:s,error:o}}function N(...n){return twMerge(clsx(n))}var we=/^(https?:\/\/|mailto:|\/[^/])/i;function be(n){let e=n.trim();return we.test(e)?e:null}function M(n){let e=[],s=/(`[^`]+`)|(\*\*(.+?)\*\*)|(\*(.+?)\*)|(_(.+?)_)|(\[([^\]]+)\]\(([^)]+)\))/g,t=0,o,a=0;for(;(o=s.exec(n))!==null;){o.index>t&&e.push(n.slice(t,o.index));let i=`i${a++}`;if(o[1])e.push(jsx("code",{className:"rounded bg-muted px-1.5 py-0.5 text-[0.85em] font-mono text-pink-400",children:o[1].slice(1,-1)},i));else if(o[2])e.push(jsx("strong",{children:o[3]},i));else if(o[4])e.push(jsx("em",{children:o[5]},i));else if(o[6])e.push(jsx("em",{children:o[7]},i));else if(o[8]){let l=be(o[10]);l?e.push(jsx("a",{href:l,className:"text-blue-400 underline hover:text-blue-300",target:"_blank",rel:"noopener noreferrer",children:o[9]},i)):e.push(o[9]);}t=o.index+o[0].length;}return t<n.length&&e.push(n.slice(t)),e.length>0?e:[n]}function ye(n){let e=n.split(`
|
|
2
|
+
`),s=[],t=0;for(;t<e.length;){let o=e[t];if(o.trim()===""){t++;continue}if(/^(-{3,}|\*{3,}|_{3,})$/.test(o.trim())){s.push({type:"hr"}),t++;continue}let a=o.match(/^(#{1,6})\s+(.+)/);if(a){s.push({type:"heading",level:a[1].length,content:a[2]}),t++;continue}if(o.trim().startsWith("```")){let l=o.trim().slice(3).trim(),m=[];for(t++;t<e.length&&!e[t].trim().startsWith("```");)m.push(e[t]),t++;s.push({type:"code",content:m.join(`
|
|
3
|
+
`),lang:l||void 0}),t++;continue}if(/^\s*[-*+]\s/.test(o)){let l=[];for(;t<e.length&&/^\s*[-*+]\s/.test(e[t]);)l.push(e[t].replace(/^\s*[-*+]\s+/,"")),t++;s.push({type:"ul",items:l});continue}if(/^\s*\d+[.)]\s/.test(o)){let l=[];for(;t<e.length&&/^\s*\d+[.)]\s/.test(e[t]);)l.push(e[t].replace(/^\s*\d+[.)]\s+/,"")),t++;s.push({type:"ol",items:l});continue}let i=[];for(;t<e.length&&e[t].trim()!==""&&!e[t].match(/^#{1,6}\s/)&&!e[t].trim().startsWith("```")&&!/^\s*[-*+]\s/.test(e[t])&&!/^\s*\d+[.)]\s/.test(e[t]);)i.push(e[t]),t++;i.length>0&&s.push({type:"paragraph",content:i.join(" ")});}return s}var ke={1:"text-2xl font-bold mt-6 mb-3",2:"text-xl font-bold mt-5 mb-2",3:"text-lg font-semibold mt-4 mb-2",4:"text-base font-semibold mt-3 mb-1",5:"text-sm font-semibold mt-2 mb-1",6:"text-sm font-medium mt-2 mb-1"};function Re(n,e){switch(n.type){case "hr":return jsx("hr",{className:"my-4 border-border"},`b${e}`);case "heading":{let s=Math.min(Math.max(n.level||1,1),6),t=`h${s}`;return jsx(t,{className:N("text-foreground",ke[s]),children:M(n.content||"")},`b${e}`)}case "paragraph":return jsx("p",{className:"mb-3 leading-relaxed text-foreground",children:M(n.content||"")},`b${e}`);case "code":return jsx("pre",{className:"mb-3 overflow-x-auto rounded-lg bg-muted p-4 text-sm font-mono leading-relaxed text-foreground",children:jsx("code",{children:n.content})},`b${e}`);case "ul":return jsx("ul",{className:"mb-3 ml-5 list-disc space-y-1 text-foreground",children:n.items?.map((s,t)=>jsx("li",{className:"leading-relaxed",children:M(s)},`li${e}-${t}`))},`b${e}`);case "ol":return jsx("ol",{className:"mb-3 ml-5 list-decimal space-y-1 text-foreground",children:n.items?.map((s,t)=>jsx("li",{className:"leading-relaxed",children:M(s)},`li${e}-${t}`))},`b${e}`);default:return null}}function U({content:n,className:e}){let s=ye(n);return jsx("div",{className:N("text-sm",e),children:s.map((t,o)=>Re(t,o))})}function Y({open:n,className:e}){return jsx("svg",{width:"16",height:"16",viewBox:"0 0 20 20",fill:"currentColor",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",className:N("shrink-0 transition-transform duration-150",n?"rotate-0":"-rotate-90",e),children:jsx("path",{d:"M16.134 6.16a.5.5 0 1 1 .732.68l-6.5 7-.077.068a.5.5 0 0 1-.655-.068l-6.5-7-.062-.08a.5.5 0 0 1 .718-.667l.076.067L10 12.767z"})})}function G({size:n=20,className:e}){return jsx("svg",{width:n,height:n,viewBox:"0 0 20 20",fill:"currentColor",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",className:e,children:jsx("path",{d:"M8.5 2a6.5 6.5 0 0 1 4.935 10.728l4.419 4.419.064.078a.5.5 0 0 1-.693.693l-.079-.064-4.419-4.42A6.5 6.5 0 1 1 8.5 2m0 1a5.5 5.5 0 1 0 0 11 5.5 5.5 0 0 0 0-11"})})}function D({size:n=20,className:e}){return jsx("svg",{width:n,height:n,viewBox:"0 0 20 20",fill:"currentColor",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",className:e,children:jsx("path",{d:"M15.147 4.146a.5.5 0 0 1 .707.707L10.707 10l5.147 5.147a.5.5 0 0 1-.63.771l-.078-.064L10 10.707l-5.146 5.147a.5.5 0 0 1-.708-.707L9.293 10 4.146 4.853a.5.5 0 0 1 .708-.707L10 9.293z"})})}function X({size:n=20,className:e}){return jsx("svg",{width:n,height:n,viewBox:"0 0 20 20",fill:"currentColor",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",className:e,children:jsx("path",{d:"M10 3a.5.5 0 0 1 .5.5v6h6l.1.01a.5.5 0 0 1 0 .98l-.1.01h-6v6a.5.5 0 0 1-1 0v-6h-6a.5.5 0 0 1 0-1h6v-6A.5.5 0 0 1 10 3"})})}function Ee(){return jsx("svg",{width:"20",height:"20",viewBox:"0 0 20 20",fill:"currentColor",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",className:"shrink-0",children:jsx("path",{d:"M6.5 3A2.5 2.5 0 0 0 4 5.5v9A2.5 2.5 0 0 0 6.5 17h7a2.5 2.5 0 0 0 2.5-2.5v-7A2.5 2.5 0 0 0 13.5 5H11V3.5a.5.5 0 0 0-1 0V5H6.5ZM5 5.5A1.5 1.5 0 0 1 6.5 4H9v1H6.5A1.5 1.5 0 0 0 5 6.5v8A1.5 1.5 0 0 0 6.5 16h7a1.5 1.5 0 0 0 1.5-1.5v-7A1.5 1.5 0 0 0 13.5 6H11V4h2.5A2.5 2.5 0 0 1 16 6.5v8a2.5 2.5 0 0 1-2.5 2.5h-7A2.5 2.5 0 0 1 4 14.5v-9Z"})})}function Te(){return jsx("svg",{width:"20",height:"20",viewBox:"0 0 20 20",fill:"currentColor",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",className:"shrink-0",children:jsx("path",{d:"M5.5 3A2.5 2.5 0 0 0 3 5.5v9A2.5 2.5 0 0 0 5.5 17h9a2.5 2.5 0 0 0 2.5-2.5v-9A2.5 2.5 0 0 0 14.5 3h-9ZM4 5.5A1.5 1.5 0 0 1 5.5 4h9A1.5 1.5 0 0 1 16 5.5v9a1.5 1.5 0 0 1-1.5 1.5h-9A1.5 1.5 0 0 1 4 14.5v-9ZM7 7.5a.5.5 0 0 1 .5-.5h5a.5.5 0 0 1 0 1h-5a.5.5 0 0 1-.5-.5Zm0 3a.5.5 0 0 1 .5-.5h5a.5.5 0 0 1 0 1h-5a.5.5 0 0 1-.5-.5Zm0 3a.5.5 0 0 1 .5-.5h3a.5.5 0 0 1 0 1h-3a.5.5 0 0 1-.5-.5Z"})})}function ze(){return jsx("svg",{width:"20",height:"20",viewBox:"0 0 20 20",fill:"currentColor",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",className:"shrink-0",children:jsx("path",{d:"M10 2a.5.5 0 0 1 .354.146l3 3a.5.5 0 0 1-.708.708L10.5 3.707V12.5a.5.5 0 0 1-1 0V3.707L7.354 5.854a.5.5 0 1 1-.708-.708l3-3A.5.5 0 0 1 10 2ZM4 13.5a.5.5 0 0 1 1 0v1A1.5 1.5 0 0 0 6.5 16h7a1.5 1.5 0 0 0 1.5-1.5v-1a.5.5 0 0 1 1 0v1a2.5 2.5 0 0 1-2.5 2.5h-7A2.5 2.5 0 0 1 4 14.5v-1Z"})})}function ee(){let[n,e]=useState(false);return useEffect(()=>{if(typeof window>"u")return;let s=()=>e(window.innerWidth<768);return s(),window.addEventListener("resize",s),()=>window.removeEventListener("resize",s)},[]),n}function te({onClose:n,children:e,title:s}){let t=ee(),o=useRef(n);return o.current=n,useEffect(()=>{let a=i=>{i.key==="Escape"&&o.current();};return window.addEventListener("keydown",a),()=>window.removeEventListener("keydown",a)},[]),t?jsxs("div",{className:"fixed inset-0 z-50 flex items-end justify-center",onClick:n,children:[jsx("div",{className:"fixed inset-0 bg-black/50"}),jsxs("div",{className:"relative z-10 w-full max-h-[90vh] overflow-y-auto rounded-t-2xl bg-[#1a1a1a] p-5 pb-8 animate-in slide-in-from-bottom duration-200",onClick:a=>a.stopPropagation(),children:[jsx("div",{className:"mx-auto mb-4 h-1 w-10 rounded-full bg-zinc-600"}),jsxs("div",{className:"flex items-center justify-between mb-5",children:[jsx("h2",{className:"text-lg font-semibold text-foreground",children:s}),jsx("button",{onClick:n,className:"rounded p-1 text-muted-foreground hover:text-foreground",children:jsx(D,{size:20})})]}),e]})]}):jsxs("div",{className:"fixed inset-0 z-50 flex items-center justify-center",onClick:n,children:[jsx("div",{className:"fixed inset-0 bg-black/50"}),jsxs("div",{className:"relative z-10 w-full max-w-lg overflow-y-auto rounded-2xl bg-[#1a1a1a] p-6 shadow-2xl animate-in fade-in zoom-in-95 duration-150",onClick:a=>a.stopPropagation(),children:[jsxs("div",{className:"flex items-center justify-between mb-5",children:[jsx("h2",{className:"text-lg font-semibold text-foreground",children:s}),jsx("button",{onClick:n,className:"rounded p-1 text-muted-foreground hover:text-foreground",children:jsx(D,{size:20})})]}),e]})]})}function Pe({onClose:n,onCreated:e,config:s}){let[t,o]=useState(""),[a,i]=useState(""),[l,m]=useState(""),[p,f]=useState(false),[x,u]=useState(null);return jsx(te,{title:"Write skill instructions",onClose:n,children:jsxs("div",{className:"space-y-4",children:[jsxs("div",{className:"space-y-1.5",children:[jsx("label",{htmlFor:"skill-name",className:"text-sm text-muted-foreground",children:"Skill name"}),jsx("input",{id:"skill-name",value:t,onChange:v=>o(v.target.value),placeholder:"weekly-status-report",className:"w-full rounded-lg border border-zinc-700 bg-[#252525] px-3 py-2.5 text-sm text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-zinc-500"})]}),jsxs("div",{className:"space-y-1.5",children:[jsx("label",{htmlFor:"skill-desc",className:"text-sm text-muted-foreground",children:"Description"}),jsx("textarea",{id:"skill-desc",value:a,onChange:v=>i(v.target.value),placeholder:"Generate weekly status reports from recent work.",rows:3,className:"w-full rounded-lg border border-zinc-700 bg-[#252525] px-3 py-2.5 text-sm text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-zinc-500"})]}),jsxs("div",{className:"space-y-1.5",children:[jsx("label",{htmlFor:"skill-instructions",className:"text-sm text-muted-foreground",children:"Instructions"}),jsx("textarea",{id:"skill-instructions",value:l,onChange:v=>m(v.target.value),placeholder:"Summarize my recent work in three sections: wins, blockers, and next steps.",rows:8,className:"w-full rounded-lg border border-zinc-700 bg-[#252525] px-3 py-2.5 text-sm text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-zinc-500"})]}),x&&jsx("p",{className:"text-sm text-red-500",children:x}),jsxs("div",{className:"flex justify-end gap-3 pt-2",children:[jsx("button",{onClick:n,className:"rounded-lg border border-zinc-700 px-4 py-2 text-sm text-foreground hover:bg-zinc-800",children:"Cancel"}),jsx("button",{onClick:async()=>{if(t.trim()){f(true),u(null);try{let v=s.apiBaseUrl||"",R=await fetch(`${v}/api/rack/init`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:t.trim(),description:a.trim(),owner_mid:s.ownerMid,is_gitagent:!0})});if(!R.ok){let b=`Failed to create skill (${R.status})`;try{let y=await R.json();y.error&&(b=y.error);}catch{}throw new Error(b)}let{repo_id:E}=await R.json(),P=`# ${t.trim()}
|
|
4
|
+
|
|
5
|
+
${a.trim()}
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
${l.trim()}`,k=await fetch(`${v}/api/rack/${E}/push`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({files:[{path:"SKILL.md",content:P}],message:"Initial skill definition",author_mid:s.authorMid})});if(!k.ok){let b=`Failed to save skill (${k.status})`;try{let y=await k.json();y.error&&(b=y.error);}catch{}throw new Error(b)}e?.(),n();}catch(v){u(v instanceof Error?v.message:"Failed to create skill");}finally{f(false);}}},disabled:p||!t.trim(),className:"rounded-lg bg-zinc-600 px-4 py-2 text-sm font-medium text-white hover:bg-zinc-500 disabled:opacity-50",children:p?"Creating...":"Create"})]})]})})}function $e({onClose:n,onCreated:e,config:s}){let t=useRef(null),[o,a]=useState(false),[i,l]=useState(false),[m,p]=useState(null),f=async u=>{l(true),p(null);try{let d=await u.text(),v=s.apiBaseUrl||"",R=u.name.replace(/\.[^.]+$/,"").replace(/[^a-zA-Z0-9-_]/g,"-"),E=await fetch(`${v}/api/rack/init`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:R,owner_mid:s.ownerMid,is_gitagent:!0})});if(!E.ok){let b=`Failed to create repo (${E.status})`;try{let y=await E.json();y.error&&(b=y.error);}catch{}throw new Error(b)}let{repo_id:P}=await E.json(),k=await fetch(`${v}/api/rack/${P}/push`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({files:[{path:u.name,content:d}],message:`Upload ${u.name}`,author_mid:s.authorMid})});if(!k.ok){let b=`Upload failed (${k.status})`;try{let y=await k.json();y.error&&(b=y.error);}catch{}throw new Error(b)}e?.(),n();}catch(d){p(d instanceof Error?d.message:"Upload failed");}finally{l(false);}};return jsx(te,{title:"Upload skill",onClose:n,children:jsxs("div",{className:"space-y-4",children:[jsxs("div",{onDragOver:u=>{u.preventDefault(),a(true);},onDragLeave:()=>a(false),onDrop:u=>{u.preventDefault(),a(false);let d=u.dataTransfer.files[0];d&&f(d);},onClick:()=>t.current?.click(),className:N("flex cursor-pointer flex-col items-center justify-center gap-3 rounded-xl border-2 border-dashed p-10 transition-colors",o?"border-zinc-400 bg-zinc-800/50":"border-zinc-700 hover:border-zinc-500"),children:[jsx("div",{className:"rounded-lg border border-zinc-600 p-2",children:jsx(X,{size:20,className:"text-muted-foreground"})}),jsx("p",{className:"text-sm text-muted-foreground",children:i?"Uploading...":"Drag and drop or click to upload"})]}),jsx("input",{ref:t,type:"file",accept:".md,.zip,.skill,.txt,.yml,.yaml",className:"hidden","aria-label":"Upload skill file",onChange:u=>{let d=u.target.files?.[0];d&&f(d);}}),m&&jsx("p",{className:"text-sm text-red-500",children:m}),jsxs("div",{className:"space-y-2 text-xs text-muted-foreground",children:[jsx("p",{className:"font-medium text-foreground/70",children:"File requirements"}),jsxs("ul",{className:"list-disc pl-5 space-y-1",children:[jsx("li",{children:".md file must contain skill name and description formatted in YAML"}),jsx("li",{children:".zip or .skill file must include a SKILL.md file"})]})]})]})})}function Se({onClose:n,onSelect:e}){let s=ee(),t=useRef(null),o=useRef(n);o.current=n,useEffect(()=>{if(s)return;let i=l=>{t.current&&l.target instanceof Node&&!t.current.contains(l.target)&&o.current();};return document.addEventListener("mousedown",i),()=>document.removeEventListener("mousedown",i)},[s]);let a=[{id:"create-with-geoff",icon:jsx(Ee,{}),label:"Create with Geoff"},{id:"write",icon:jsx(Te,{}),label:"Write skill instructions"},{id:"upload",icon:jsx(ze,{}),label:"Upload a skill"}];return s?jsxs("div",{className:"fixed inset-0 z-50 flex items-end",onClick:n,children:[jsx("div",{className:"fixed inset-0 bg-black/50"}),jsxs("div",{className:"relative z-10 w-full rounded-t-2xl bg-[#1a1a1a] p-4 pb-8 animate-in slide-in-from-bottom duration-200",onClick:i=>i.stopPropagation(),children:[jsx("div",{className:"mx-auto mb-3 h-1 w-10 rounded-full bg-zinc-600"}),a.map(i=>jsxs("button",{onClick:()=>{e(i.id),n();},className:"flex w-full items-center gap-3 rounded-lg px-4 py-3 text-sm text-foreground transition-colors hover:bg-zinc-800",children:[i.icon,i.label]},i.id))]})]}):jsx("div",{ref:t,className:"absolute right-2 top-11 z-50 w-56 overflow-hidden rounded-xl border border-zinc-700 bg-[#2a2a2a] shadow-xl animate-in fade-in zoom-in-95 duration-100",children:a.map(i=>jsxs("button",{onClick:()=>{e(i.id),n();},className:"flex w-full items-center gap-3 px-4 py-3 text-sm text-foreground transition-colors hover:bg-zinc-700/50",children:[i.icon,i.label]},i.id))})}function Me({entry:n,selected:e,onSelect:s,depth:t=0}){return jsxs("button",{onClick:()=>s(n),className:N("flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-left text-sm transition-colors",e?"bg-[#141414] text-foreground":"text-muted-foreground hover:bg-muted/50 hover:text-foreground"),style:{paddingLeft:`${8+t*16}px`},children:[jsx("span",{className:"truncate flex-1",children:n.path.split("/").pop()}),n.isDir&&jsx(Y,{className:"ml-auto text-muted-foreground"})]})}function Ie({repo:n,selected:e,expanded:s,onSelect:t,onToggle:o,children:a}){return jsxs("div",{children:[jsxs("button",{onClick:()=>{t(),o();},className:N("flex w-full items-center gap-2 rounded-md px-2 py-2 text-left text-sm font-medium transition-colors",e?"bg-[#141414] text-foreground":"text-muted-foreground hover:bg-muted/50 hover:text-foreground"),children:[jsx(Y,{open:s}),jsx(FileText,{className:"h-4 w-4 shrink-0"}),jsx("span",{className:"truncate",children:n.name})]}),s&&a]})}function Le({entry:n,content:e,loading:s,repoName:t}){let[o,a]=useState(false),i=useRef(null);useEffect(()=>()=>{i.current&&clearTimeout(i.current);},[]);let[l,m]=useState(false),p=async()=>{if(e)try{await navigator.clipboard.writeText(e),a(!0),m(!1),i.current&&clearTimeout(i.current),i.current=setTimeout(()=>a(!1),2e3);}catch{m(true),i.current&&clearTimeout(i.current),i.current=setTimeout(()=>m(false),2e3);}};if(!n)return jsx("div",{className:"flex h-full items-center justify-center text-sm text-muted-foreground",children:"Select a file to view its content"});if(s)return jsx("div",{className:"flex h-full items-center justify-center",children:jsx(Loader2,{className:"h-5 w-5 animate-spin text-muted-foreground"})});let f=n.path.split("/").pop()||n.path,x=/\.(md|mdx)$/i.test(f);return jsxs("div",{className:"flex h-full flex-col px-3",children:[jsxs("div",{className:"flex items-center justify-between px-4 py-3",children:[jsx("h3",{className:"text-sm sm:text-lg font-semibold text-foreground",children:f}),jsx("button",{onClick:p,"aria-label":"Copy file content",className:N("rounded p-1 transition-colors",o?"text-green-500":l?"text-red-500":"text-muted-foreground hover:text-foreground"),children:jsx("svg",{width:"20",height:"20",viewBox:"0 0 20 20",fill:"currentColor",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",className:"shrink-0",children:jsx("path",{d:"M12.5 3A1.5 1.5 0 0 1 14 4.5V6h1.5A1.5 1.5 0 0 1 17 7.5v8a1.5 1.5 0 0 1-1.5 1.5h-8A1.5 1.5 0 0 1 6 15.5V14H4.5A1.5 1.5 0 0 1 3 12.5v-8A1.5 1.5 0 0 1 4.5 3zm1.5 9.5a1.5 1.5 0 0 1-1.5 1.5H7v1.5a.5.5 0 0 0 .5.5h8a.5.5 0 0 0 .5-.5v-8a.5.5 0 0 0-.5-.5H14zM4.5 4a.5.5 0 0 0-.5.5v8a.5.5 0 0 0 .5.5h8a.5.5 0 0 0 .5-.5v-8a.5.5 0 0 0-.5-.5z"})})})]}),jsx("div",{className:"flex-1 overflow-auto p-4",children:x?jsx(U,{content:e||""}):jsx("pre",{className:"whitespace-pre-wrap text-sm text-foreground font-mono leading-relaxed",children:e||""})})]})}function Ae({config:n,category:e,className:s,style:t}){let{repos:o,loading:a,error:i,refresh:l}=_(n),[m,p]=useState(null),[f,x]=useState(null),[u,d]=useState(null),[v,R]=useState(null),[E,P]=useState(false),[k,b]=useState(""),[y,j]=useState(false),[O,H]=useState(false),[V,I]=useState(null),re=o.find(g=>g.repo_id===m),{entries:ne,getFileContent:Z}=F(n,f),W=o.filter(g=>!k||g.name.toLowerCase().includes(k.toLowerCase())),oe=useCallback(async g=>{if(!g.isDir){d(g),P(true);try{let C=await Z(g.cid);R(C);}catch(C){let ie=C instanceof Error?C.message:"Unknown error";R(`Failed to load file: ${ie}`);}finally{P(false);}}},[Z]);useEffect(()=>{o.length>0&&!m&&(p(o[0].repo_id),x(o[0].repo_id));},[o,m]);let se=g=>{g==="create-with-geoff"?window.open(`https://www.geoff.ai/?p=${encodeURIComponent("Let's create a skill together using your skill-creator skill. First ask me what the skill should do.")}`,"_blank","noopener,noreferrer"):I(g);};return jsxs("div",{className:N("flex flex-1 h-full min-h-0",s),style:t,children:[jsxs("div",{className:"relative flex w-96 shrink-0 flex-col border-r",children:[jsx("div",{className:"flex h-12 items-center gap-2 px-3",children:y?jsxs(Fragment,{children:[jsxs("div",{className:"flex flex-1 items-center gap-2 rounded-md border bg-muted/50 px-2 py-1",children:[jsx(G,{size:16,className:"shrink-0 text-muted-foreground"}),jsx("input",{type:"text",value:k,onChange:g=>b(g.target.value),placeholder:"Search",autoFocus:true,"aria-label":"Search items",className:"flex-1 bg-transparent text-xs text-foreground placeholder:text-muted-foreground focus:outline-none"})]}),jsx("button",{onClick:()=>{j(false),b("");},className:"rounded p-1 text-muted-foreground hover:text-foreground",children:jsx(D,{size:16})})]}):jsxs(Fragment,{children:[jsx("h3",{className:"flex-1 text-sm sm:text-lg font-semibold text-foreground capitalize",children:e||"Items"}),jsx("button",{onClick:()=>j(true),className:"rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground","aria-label":"Search",children:jsx(G,{size:20})}),jsx("button",{onClick:()=>H(!O),className:"rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground","aria-label":"Add new",children:jsx(X,{size:20})})]})}),O&&jsx(Se,{onClose:()=>H(false),onSelect:se}),jsx("div",{className:"flex-1 overflow-y-auto p-2",children:a?jsx("div",{className:"flex items-center justify-center py-8",children:jsx(Loader2,{className:"h-5 w-5 animate-spin text-muted-foreground"})}):i?jsx("p",{className:"px-2 py-4 text-xs text-red-500",children:i}):W.length===0?jsx("p",{className:"px-2 py-4 text-xs text-muted-foreground",children:k?"No matching items":"No items yet"}):jsx("div",{className:"space-y-0.5",children:W.map(g=>jsx(Ie,{repo:g,selected:m===g.repo_id,expanded:f===g.repo_id,onSelect:()=>{p(g.repo_id),d(null),R(null);},onToggle:()=>x(f===g.repo_id?null:g.repo_id),children:jsx("div",{className:"ml-10 pl-1",children:ne.map(C=>jsx(Me,{entry:C,selected:u?.path===C.path,onSelect:oe,depth:C.path.split("/").length-1},C.path))})},g.repo_id))})})]}),jsx("div",{className:"flex-1 min-w-0",children:jsx(Le,{entry:u,content:v,loading:E,repoName:re?.name||""})}),V==="write"&&jsx(Pe,{config:n,onClose:()=>I(null),onCreated:l}),V==="upload"&&jsx($e,{config:n,onClose:()=>I(null),onCreated:l})]})}
|
|
10
|
+
export{U as Markdown,Ae as RackBrowser,z as useRackClient,he as useRepoPush,F as useRepoTree,_ as useRepos};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
'use strict';
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
interface RepoInfo {
|
|
2
|
+
repo_id: string;
|
|
3
|
+
manifest_cid: string;
|
|
4
|
+
owner_mid: string;
|
|
5
|
+
name: string;
|
|
6
|
+
description?: string;
|
|
7
|
+
updated_at: string;
|
|
8
|
+
is_gitagent?: boolean;
|
|
9
|
+
tags?: string[];
|
|
10
|
+
}
|
|
11
|
+
interface RepoCommit {
|
|
12
|
+
tree_cid: string;
|
|
13
|
+
parent_cids: string[];
|
|
14
|
+
author: string;
|
|
15
|
+
author_mid: string;
|
|
16
|
+
message: string;
|
|
17
|
+
timestamp: string;
|
|
18
|
+
signature?: string;
|
|
19
|
+
}
|
|
20
|
+
interface RepoTree {
|
|
21
|
+
entries: Record<string, string>;
|
|
22
|
+
}
|
|
23
|
+
interface TreeEntry {
|
|
24
|
+
path: string;
|
|
25
|
+
mode: string;
|
|
26
|
+
cid: string;
|
|
27
|
+
isDir: boolean;
|
|
28
|
+
}
|
|
29
|
+
interface RepoFile {
|
|
30
|
+
path: string;
|
|
31
|
+
content: string;
|
|
32
|
+
mode?: string;
|
|
33
|
+
}
|
|
34
|
+
interface DiffEntry {
|
|
35
|
+
path: string;
|
|
36
|
+
status: 'added' | 'deleted' | 'modified';
|
|
37
|
+
old_cid?: string;
|
|
38
|
+
new_cid?: string;
|
|
39
|
+
}
|
|
40
|
+
interface RackConfig {
|
|
41
|
+
/** Base URL for rack API proxy (e.g. "" for same-origin, or full URL) */
|
|
42
|
+
apiBaseUrl: string;
|
|
43
|
+
/** Owner MID for filtering repos */
|
|
44
|
+
ownerMid?: string;
|
|
45
|
+
/** Author MID for write operations */
|
|
46
|
+
authorMid?: string;
|
|
47
|
+
}
|
|
48
|
+
interface InitResult {
|
|
49
|
+
success: boolean;
|
|
50
|
+
repo_id: string;
|
|
51
|
+
manifest_cid: string;
|
|
52
|
+
commit_cid: string;
|
|
53
|
+
tree_cid: string;
|
|
54
|
+
}
|
|
55
|
+
interface PushResult {
|
|
56
|
+
success: boolean;
|
|
57
|
+
commit_cid: string;
|
|
58
|
+
tree_cid: string;
|
|
59
|
+
manifest_cid?: string;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export type { DiffEntry, InitResult, PushResult, RackConfig, RepoCommit, RepoFile, RepoInfo, RepoTree, TreeEntry };
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
interface RepoInfo {
|
|
2
|
+
repo_id: string;
|
|
3
|
+
manifest_cid: string;
|
|
4
|
+
owner_mid: string;
|
|
5
|
+
name: string;
|
|
6
|
+
description?: string;
|
|
7
|
+
updated_at: string;
|
|
8
|
+
is_gitagent?: boolean;
|
|
9
|
+
tags?: string[];
|
|
10
|
+
}
|
|
11
|
+
interface RepoCommit {
|
|
12
|
+
tree_cid: string;
|
|
13
|
+
parent_cids: string[];
|
|
14
|
+
author: string;
|
|
15
|
+
author_mid: string;
|
|
16
|
+
message: string;
|
|
17
|
+
timestamp: string;
|
|
18
|
+
signature?: string;
|
|
19
|
+
}
|
|
20
|
+
interface RepoTree {
|
|
21
|
+
entries: Record<string, string>;
|
|
22
|
+
}
|
|
23
|
+
interface TreeEntry {
|
|
24
|
+
path: string;
|
|
25
|
+
mode: string;
|
|
26
|
+
cid: string;
|
|
27
|
+
isDir: boolean;
|
|
28
|
+
}
|
|
29
|
+
interface RepoFile {
|
|
30
|
+
path: string;
|
|
31
|
+
content: string;
|
|
32
|
+
mode?: string;
|
|
33
|
+
}
|
|
34
|
+
interface DiffEntry {
|
|
35
|
+
path: string;
|
|
36
|
+
status: 'added' | 'deleted' | 'modified';
|
|
37
|
+
old_cid?: string;
|
|
38
|
+
new_cid?: string;
|
|
39
|
+
}
|
|
40
|
+
interface RackConfig {
|
|
41
|
+
/** Base URL for rack API proxy (e.g. "" for same-origin, or full URL) */
|
|
42
|
+
apiBaseUrl: string;
|
|
43
|
+
/** Owner MID for filtering repos */
|
|
44
|
+
ownerMid?: string;
|
|
45
|
+
/** Author MID for write operations */
|
|
46
|
+
authorMid?: string;
|
|
47
|
+
}
|
|
48
|
+
interface InitResult {
|
|
49
|
+
success: boolean;
|
|
50
|
+
repo_id: string;
|
|
51
|
+
manifest_cid: string;
|
|
52
|
+
commit_cid: string;
|
|
53
|
+
tree_cid: string;
|
|
54
|
+
}
|
|
55
|
+
interface PushResult {
|
|
56
|
+
success: boolean;
|
|
57
|
+
commit_cid: string;
|
|
58
|
+
tree_cid: string;
|
|
59
|
+
manifest_cid?: string;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export type { DiffEntry, InitResult, PushResult, RackConfig, RepoCommit, RepoFile, RepoInfo, RepoTree, TreeEntry };
|
|
File without changes
|
package/package.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@stacknet/rackutils",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "React hooks and components for reading and writing StackNet Racks",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"require": "./dist/index.cjs"
|
|
14
|
+
},
|
|
15
|
+
"./hooks": {
|
|
16
|
+
"types": "./dist/hooks/index.d.ts",
|
|
17
|
+
"import": "./dist/hooks/index.js",
|
|
18
|
+
"require": "./dist/hooks/index.cjs"
|
|
19
|
+
},
|
|
20
|
+
"./types": {
|
|
21
|
+
"types": "./dist/types/index.d.ts",
|
|
22
|
+
"import": "./dist/types/index.js",
|
|
23
|
+
"require": "./dist/types/index.cjs"
|
|
24
|
+
},
|
|
25
|
+
"./components": {
|
|
26
|
+
"types": "./dist/components/index.d.ts",
|
|
27
|
+
"import": "./dist/components/index.js",
|
|
28
|
+
"require": "./dist/components/index.cjs"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"files": ["dist", "README.md"],
|
|
32
|
+
"scripts": {
|
|
33
|
+
"build": "tsup",
|
|
34
|
+
"build:publish": "tsup --no-sourcemap --minify",
|
|
35
|
+
"dev": "tsup --watch",
|
|
36
|
+
"clean": "rm -rf dist",
|
|
37
|
+
"typecheck": "tsc --noEmit",
|
|
38
|
+
"prepublishOnly": "pnpm run clean && pnpm run typecheck && pnpm run build:publish",
|
|
39
|
+
"release": "pnpm run prepublishOnly && npm publish --access public"
|
|
40
|
+
},
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"clsx": "^2.1.1",
|
|
43
|
+
"tailwind-merge": "^2.5.4",
|
|
44
|
+
"lucide-react": "^0.460.0"
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@types/react": "^19.0.0",
|
|
48
|
+
"@types/react-dom": "^19.0.0",
|
|
49
|
+
"react": "^19.0.0",
|
|
50
|
+
"react-dom": "^19.0.0",
|
|
51
|
+
"tsup": "^8.3.5",
|
|
52
|
+
"typescript": "^5.6.3"
|
|
53
|
+
},
|
|
54
|
+
"peerDependencies": {
|
|
55
|
+
"react": ">=18.0.0",
|
|
56
|
+
"react-dom": ">=18.0.0"
|
|
57
|
+
},
|
|
58
|
+
"license": "MIT"
|
|
59
|
+
}
|