just-git 0.1.2 → 0.1.4
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 +33 -33
- package/dist/index.js +5 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -15,12 +15,12 @@ import { Bash } from "just-bash";
|
|
|
15
15
|
import { createGit } from "just-git";
|
|
16
16
|
|
|
17
17
|
const git = createGit({
|
|
18
|
-
|
|
18
|
+
identity: { name: "Alice", email: "alice@example.com" },
|
|
19
19
|
});
|
|
20
20
|
|
|
21
21
|
const bash = new Bash({
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
cwd: "/repo",
|
|
23
|
+
customCommands: [git],
|
|
24
24
|
});
|
|
25
25
|
|
|
26
26
|
await bash.exec("git init");
|
|
@@ -43,10 +43,10 @@ await bash.exec("git log --oneline");
|
|
|
43
43
|
|
|
44
44
|
```ts
|
|
45
45
|
const git = createGit({
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
46
|
+
identity: { name: "Agent Bot", email: "bot@company.com", locked: true },
|
|
47
|
+
credentials: async (url) => ({ type: "bearer", token: "ghp_..." }),
|
|
48
|
+
disabled: ["rebase"],
|
|
49
|
+
network: { allowed: ["github.com"] },
|
|
50
50
|
});
|
|
51
51
|
```
|
|
52
52
|
|
|
@@ -59,31 +59,31 @@ The `CommandEvent` provides the execution context: `{ command, rawArgs, fs, cwd,
|
|
|
59
59
|
```ts
|
|
60
60
|
// Audit log — record every command the agent runs
|
|
61
61
|
git.use(async (event, next) => {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
62
|
+
const result = await next();
|
|
63
|
+
auditLog.push({ command: `git ${event.command}`, exitCode: result.exitCode });
|
|
64
|
+
return result;
|
|
65
65
|
});
|
|
66
66
|
|
|
67
67
|
// Gate pushes on human approval
|
|
68
68
|
git.use(async (event, next) => {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
69
|
+
if (event.command === "push" && !(await getHumanApproval(event.rawArgs))) {
|
|
70
|
+
return { stdout: "", stderr: "Push blocked — awaiting approval.\n", exitCode: 1 };
|
|
71
|
+
}
|
|
72
|
+
return next();
|
|
73
73
|
});
|
|
74
74
|
|
|
75
75
|
// Block commits that add large files (uses event.fs to read the worktree)
|
|
76
76
|
git.use(async (event, next) => {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
77
|
+
if (event.command === "add") {
|
|
78
|
+
for (const path of event.rawArgs.filter((a) => !a.startsWith("-"))) {
|
|
79
|
+
const resolved = path.startsWith("/") ? path : `${event.cwd}/${path}`;
|
|
80
|
+
const stat = await event.fs.stat(resolved).catch(() => null);
|
|
81
|
+
if (stat && stat.size > 5_000_000) {
|
|
82
|
+
return { stdout: "", stderr: `Blocked: ${path} exceeds 5 MB\n`, exitCode: 1 };
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return next();
|
|
87
87
|
});
|
|
88
88
|
```
|
|
89
89
|
|
|
@@ -100,17 +100,17 @@ Pre-hooks can abort the operation by returning `{ abort: true, message? }`.
|
|
|
100
100
|
```ts
|
|
101
101
|
// Block secrets from being committed
|
|
102
102
|
git.on("pre-commit", (event) => {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
103
|
+
const forbidden = event.index.entries.filter((e) => /\.(env|pem|key)$/.test(e.path));
|
|
104
|
+
if (forbidden.length) {
|
|
105
|
+
return { abort: true, message: `Blocked: ${forbidden.map((e) => e.path).join(", ")}` };
|
|
106
|
+
}
|
|
107
107
|
});
|
|
108
108
|
|
|
109
109
|
// Enforce conventional commit messages
|
|
110
110
|
git.on("commit-msg", (event) => {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
111
|
+
if (!/^(feat|fix|docs|refactor|test|chore)(\(.+\))?:/.test(event.message)) {
|
|
112
|
+
return { abort: true, message: "Commit message must follow conventional commits format" };
|
|
113
|
+
}
|
|
114
114
|
});
|
|
115
115
|
```
|
|
116
116
|
|
|
@@ -140,11 +140,11 @@ Post-hooks are observational -- return value is ignored. Handlers are awaited in
|
|
|
140
140
|
```ts
|
|
141
141
|
// Feed agent activity to your UI or orchestration layer
|
|
142
142
|
git.on("post-commit", (event) => {
|
|
143
|
-
|
|
143
|
+
onAgentCommit({ hash: event.hash, branch: event.branch, message: event.message });
|
|
144
144
|
});
|
|
145
145
|
|
|
146
146
|
git.on("post-push", (event) => {
|
|
147
|
-
|
|
147
|
+
onAgentPush({ remote: event.remote, refs: event.refs });
|
|
148
148
|
});
|
|
149
149
|
```
|
|
150
150
|
|
package/dist/index.js
CHANGED
|
@@ -26,7 +26,7 @@ Run
|
|
|
26
26
|
`)):await e.fs.rm(n)}async function ki(e){let t=await le(e,"refs");if(t.length===0)return;let n=["# pack-refs with: peeled fully-peeled sorted"];for(let r of t)if(n.push(`${r.hash} ${r.name}`),r.name.startsWith("refs/tags/"))try{let o=await ce(e,r.hash);if(o.type==="tag"){let s=jt(o.content).object;for(let a=0;a<100;a++){let i=await ce(e,s);if(i.type!=="tag")break;s=jt(i.content).object}n.push(`^${s}`)}}catch{}await e.fs.writeFile(v(e.gitDir,"packed-refs"),`${n.join(`
|
|
27
27
|
`)}
|
|
28
28
|
`);for(let r of t){let o=Xn(e,r.name);await e.fs.exists(o)&&await e.fs.rm(o)}await Ci(e,v(e.gitDir,"refs"))}async function Ci(e,t){if(!await e.fs.exists(t)||!(await e.fs.stat(t)).isDirectory)return;let r=await e.fs.readdir(t);for(let s of r)await Ci(e,v(t,s));(await e.fs.readdir(t)).length===0&&await e.fs.rm(t,{recursive:!0})}async function Pi(e){let t=v(e.gitDir,"packed-refs");if(!await e.fs.exists(t))return new Map;let n=await e.fs.readFile(t),r=new Map;for(let o of n.split(`
|
|
29
|
-
`)){if(!o||o.startsWith("#")||o.startsWith("^"))continue;let s=o.indexOf(" ");if(s===-1)continue;let a=o.slice(0,s),i=o.slice(s+1).trim();a.length===40&&i&&r.set(i,a)}return r}function Xn(e,t){return v(e.gitDir,t)}async function Oi(e,t,n,r){let o=await e.fs.readdir(t);for(let s of o){let a=v(t,s),i=`${n}/${s}`,c=await e.fs.stat(a);if(c.isDirectory)await Oi(e,a,i,r);else if(c.isFile){let f=await F(e,i);f&&r.push({name:i,hash:f})}}}async function $n(e,t){let n=t;for(;;){let r=v(n,".git");if(await e.exists(r)&&(await e.stat(r)).isDirectory)return{fs:e,gitDir:r,workTree:n};let o=jf(n);if(o===n)return null;n=o}}async function vr(e,t,n={}){let{bare:r=!1,initialBranch:o="main"}=n,s=r?t:v(t,".git"),a=r?null:t;await e.mkdir(v(s,"objects"),{recursive:!0}),await e.mkdir(v(s,"refs","heads"),{recursive:!0}),await e.mkdir(v(s,"refs","tags"),{recursive:!0});let
|
|
29
|
+
`)){if(!o||o.startsWith("#")||o.startsWith("^"))continue;let s=o.indexOf(" ");if(s===-1)continue;let a=o.slice(0,s),i=o.slice(s+1).trim();a.length===40&&i&&r.set(i,a)}return r}function Xn(e,t){return v(e.gitDir,t)}async function Oi(e,t,n,r){let o=await e.fs.readdir(t);for(let s of o){let a=v(t,s),i=`${n}/${s}`,c=await e.fs.stat(a);if(c.isDirectory)await Oi(e,a,i,r);else if(c.isFile){let f=await F(e,i);f&&r.push({name:i,hash:f})}}}async function $n(e,t){let n=t;for(;;){let r=v(n,".git");if(await e.exists(r)&&(await e.stat(r)).isDirectory)return{fs:e,gitDir:r,workTree:n};let o=jf(n);if(o===n)return null;n=o}}async function vr(e,t,n={}){let{bare:r=!1,initialBranch:o="main"}=n,s=r?t:v(t,".git"),a=r?null:t,i=v(s,"HEAD"),c=await e.exists(i);await e.mkdir(v(s,"objects"),{recursive:!0}),await e.mkdir(v(s,"refs","heads"),{recursive:!0}),await e.mkdir(v(s,"refs","tags"),{recursive:!0});let f={fs:e,gitDir:s,workTree:a};if(!c){await $e(f,"HEAD",`refs/heads/${o}`);let d={core:{repositoryformatversion:"0",filemode:"true",bare:r?"true":"false"}};await e.writeFile(v(s,"config"),As(d))}return{ctx:f,reinit:c}}async function In(e,t){let n=t.lastIndexOf("/");if(n>0){let r=t.slice(0,n);await e.mkdir(r,{recursive:!0})}}function jf(e){let t=e.lastIndexOf("/");return t<=0?"/":e.slice(0,t)}function Sr(e,t){return v(e.gitDir,"logs",t)}function Lf(e){let t=e.indexOf(" ");if(t<0)return null;let n=e.slice(0,t),r=e.slice(t+1),o=n.split(" ");if(o.length<5)return null;let s=o[0],a=o[1];if(!s||!a)return null;let i=n.indexOf("<"),c=n.indexOf(">",i);if(i<0||c<0)return null;let f=n.slice(s.length+1+a.length+1,i).trim(),d=n.slice(i+1,c),u=n.slice(c+2),l=u.indexOf(" ");if(l<0)return null;let m=parseInt(u.slice(0,l),10),h=u.slice(l+1);return{oldHash:s,newHash:a,name:f,email:d,timestamp:m,tz:h,message:r}}async function Me(e,t){let n=Sr(e,t);if(!await e.fs.exists(n))return[];let r=await e.fs.readFile(n);if(!r.trim())return[];let o=[];for(let s of r.split(`
|
|
30
30
|
`)){if(!s)continue;let a=Lf(s);a&&o.push(a)}return o}function Ri(e){return`${e.oldHash} ${e.newHash} ${e.name} <${e.email}> ${e.timestamp} ${e.tz} ${e.message}`}async function Xt(e,t,n){let r=Sr(e,t);if(await In(e.fs,r),n.length===0){await e.fs.writeFile(r,"");return}let o=`${n.map(Ri).join(`
|
|
31
31
|
`)}
|
|
32
32
|
`;await e.fs.writeFile(r,o)}async function Te(e,t,n){let r=Sr(e,t);await In(e.fs,r);let o=`${Ri(n)}
|
|
@@ -281,7 +281,7 @@ ${n}
|
|
|
281
281
|
`));i.push(kn(`done
|
|
282
282
|
`));let c=us(...i),f=e.replace(/\/+$/,""),d=await s(`${f}/git-upload-pack`,{method:"POST",headers:{"Content-Type":"application/x-git-upload-pack-request",...xo(o),"User-Agent":"just-git/1.0"},body:c});if(!d.ok)throw new Error(`HTTP ${d.status} fetching pack from ${f}`);let u=new Uint8Array(await d.arrayBuffer());return Kl(u,a.includes("side-band-64k"))}function Kl(e,t){let n=Gn(e),r=[],o=0;for(let f=0;f<n.length;f++){let d=n[f];if(!d||d.type==="flush"){o=f+1;continue}if(d.type!=="data")continue;let u=ms(d);if(u.startsWith("ACK ")||u==="NAK")r.push(u),o=f+1;else{o=f;break}}let s=n.slice(o);if(t){let{packData:f,progress:d,errors:u}=Eo(s);if(u.length>0)throw new Error(`Remote error: ${u.join("")}`);return{packData:f,acks:r,progress:d}}let a=0;for(let f of s)f.type==="data"&&(a+=f.data.byteLength);let i=new Uint8Array(a),c=0;for(let f of s)f.type==="data"&&(i.set(f.data,c),c+=f.data.byteLength);return{packData:i,acks:r,progress:[]}}var zl=["report-status","side-band-64k","ofs-delta","delete-refs"];async function Na(e,t,n,r,o,s=globalThis.fetch){if(t.length===0)throw new Error("pushPack requires at least one command");let a=_a(r,zl),i=[],[c,...f]=t;if(!c)throw new Error("pushPack requires at least one command");i.push(kn(`${c.oldHash} ${c.newHash} ${c.refName}\0${a.join(" ")}
|
|
283
283
|
`));for(let h of f)i.push(kn(`${h.oldHash} ${h.newHash} ${h.refName}
|
|
284
|
-
`));i.push(yo());let d;if(n&&n.byteLength>0){let h=us(...i);d=new Uint8Array(h.byteLength+n.byteLength),d.set(h,0),d.set(n,h.byteLength)}else d=us(...i);let u=e.replace(/\/+$/,""),l=await s(`${u}/git-receive-pack`,{method:"POST",headers:{"Content-Type":"application/x-git-receive-pack-request",...xo(o),"User-Agent":"just-git/1.0"},body:d});if(!l.ok)throw new Error(`HTTP ${l.status} pushing to ${u}`);let m=new Uint8Array(await l.arrayBuffer());return a.includes("report-status")?Vl(m,a.includes("side-band-64k")):{unpackOk:!0,refResults:[],progress:[]}}function Vl(e,t){let n,r=[];if(t){let i=Gn(e),{packData:c,progress:f,errors:d}=Eo(i);if(d.length>0)throw new Error(`Remote error: ${d.join("")}`);r=f,n=Gn(c)}else n=Gn(e);let o=!1,s,a=[];for(let i of n){if(i.type==="flush")break;let c=ms(i);if(c.startsWith("unpack "))o=c==="unpack ok",o||(s=c.slice(7));else if(c.startsWith("ok "))a.push({name:c.slice(3),ok:!0});else if(c.startsWith("ng ")){let f=c.slice(3),d=f.indexOf(" ");d!==-1?a.push({name:f.slice(0,d),ok:!1,error:f.slice(d+1)}):a.push({name:f,ok:!1})}}return{unpackOk:o,unpackError:s,refResults:a,progress:r}}function _a(e,t){let n=new Set(e.map(o=>o.split("=",1)[0]??o)),r=[];for(let o of t)n.has(o)&&r.push(o);return r.push("agent=just-git/1.0"),r}var ur=class{constructor(t,n){this.local=t;this.remote=n}headTarget;async advertiseRefs(){let t=await le(this.remote),n=[];for(let s of t)n.push({name:s.name,hash:s.hash});let r=await F(this.remote,"HEAD");r&&n.push({name:"HEAD",hash:r});let o=await J(this.remote);return o?.type==="symbolic"&&(this.headTarget=o.target),n}async fetch(t,n){let r=await this.advertiseRefs();if(t.length===0)return{remoteRefs:r,objectCount:0};let o=await fs(this.remote,t,n);if(o.length===0)return{remoteRefs:r,objectCount:0};let s=[];for(let c of o){let f=await ce(this.remote,c.hash);s.push({type:f.type,content:f.content})}let a=await $r(s),i=await Ar(this.local,a);return{remoteRefs:r,objectCount:i}}async push(t){let n=[],r=[];for(let s of t)s.newHash!==Z&&n.push(s.newHash),s.oldHash&&r.push(s.oldHash);if(n.length>0){let s=await fs(this.local,n,r);if(s.length>0){let a=[];for(let c of s){let f=await ce(this.local,c.hash);a.push({type:f.type,content:f.content})}let i=await $r(a);await Ar(this.remote,i)}}let o=[];for(let s of t)try{if(s.newHash===Z){await ie(this.remote,s.name),o.push({...s,ok:!0});continue}let a=await F(this.remote,s.name);if(a&&!s.ok&&!await _t(this.remote,a,s.newHash)){o.push({...s,ok:!1,error:`non-fast-forward update rejected for ${s.name}`});continue}await Y(this.remote,s.name,s.newHash),o.push({...s,ok:!0})}catch(a){o.push({...s,ok:!1,error:a instanceof Error?a.message:String(a)})}return{updates:o}}},mr=class{constructor(t,n,r,o){this.local=t;this.url=n;this.auth=r;this.fetchFn=o}headTarget;cachedFetchCaps=null;cachedPushCaps=null;cachedFetchRefs=null;async advertiseRefs(){let t=await ko(this.url,"git-upload-pack",this.auth,this.fetchFn);this.cachedFetchCaps=t.capabilities,this.cachedFetchRefs=t.refs;let n=t.symrefs.get("HEAD");return n&&(this.headTarget=n),t.refs}async ensureFetchDiscovery(){return(!this.cachedFetchCaps||!this.cachedFetchRefs)&&await this.advertiseRefs(),{caps:this.cachedFetchCaps,refs:this.cachedFetchRefs}}async ensurePushDiscovery(){if(!this.cachedPushCaps){let t=await ko(this.url,"git-receive-pack",this.auth,this.fetchFn);this.cachedPushCaps=t.capabilities}return this.cachedPushCaps}async fetch(t,n){let{caps:r,refs:o}=await this.ensureFetchDiscovery();if(t.length===0)return{remoteRefs:o,objectCount:0};let s=await Ga(this.url,t,n,r,this.auth,this.fetchFn);if(s.packData.byteLength===0)return{remoteRefs:o,objectCount:0};let a=await Ar(this.local,s.packData);return{remoteRefs:o,objectCount:a}}async push(t){for(let d of t)if(d.oldHash&&d.oldHash!==Z&&d.newHash!==Z&&!d.ok&&!await _t(this.local,d.oldHash,d.newHash))return{updates:t.map(l=>l===d?{...l,ok:!1,error:"non-fast-forward"}:{...l,ok:!1,error:"atomic push failed"})};let n=await this.ensurePushDiscovery(),r=t.map(d=>({oldHash:d.oldHash??Z,newHash:d.newHash,refName:d.name})),o=[],s=[],a=!1;for(let d of t)d.newHash!==Z&&(o.push(d.newHash),a=!0),d.oldHash&&d.oldHash!==Z&&s.push(d.oldHash);let i=null;if(a){let d=await fs(this.local,o,s),u=[];for(let l of d){let m=await ce(this.local,l.hash);u.push({type:m.type,content:m.content})}i=await $r(u)}let c=await Na(this.url,r,i,n,this.auth,this.fetchFn);return{updates:t.map(d=>{let u=c.refResults.find(h=>h.name===d.name),l=u?.ok??c.unpackOk,m=u?.error??(!l&&c.unpackError?`unpack failed: ${c.unpackError}`:void 0);return{...d,ok:l,error:m}})}}};async function Yl(e,t){let r=(await ae(e))[`remote "${t}"`];return r?.url?{name:t,url:r.url,fetchRefspec:r.fetch??"+refs/heads/*:refs/remotes/origin/*"}:null}function Co(e){return e.startsWith("http://")||e.startsWith("https://")}function Fa(e,t){if(t===void 0)return null;if(t===!1)return"network access is disabled";if(!t.allowed)return null;if(t.allowed.length===0)return"network access is disabled";let n;try{n=new URL(e).hostname}catch{return`network policy: access to '${e}' is not allowed`}for(let r of t.allowed)if(Co(r)){if(e===r||e.startsWith(r))return null}else if(n===r)return null;return`network policy: access to '${e}' is not allowed`}function Xl(e){let t=e.get("GIT_HTTP_BEARER_TOKEN");if(t)return{type:"bearer",token:t};let n=e.get("GIT_HTTP_USER"),r=e.get("GIT_HTTP_PASSWORD");if(n&&r)return{type:"basic",username:n,password:r}}async function Ua(e,t,n){if(e.credentialProvider){let r=await e.credentialProvider(t);if(r)return r}return Xl(n)}async function Ba(e,t,n,r){if(Co(t)){let o=Fa(t,e.networkPolicy);if(o)throw new Error(o);let s=await Ua(e,t,n);return new mr(e,t,s,e.fetchFn)}if(!r)throw new Error(`'${t}' does not appear to be a git repository`);return new ur(e,r)}async function Nn(e,t,n){let r=await Yl(e,t);if(!r)return null;if(Co(r.url)){let s=Fa(r.url,e.networkPolicy);if(s)throw new Error(s);let a=n?await Ua(e,r.url,n):void 0;return{transport:new mr(e,r.url,a,e.fetchFn),config:r}}let o=await $n(e.fs,r.url);return o?{transport:new ur(e,o),config:r}:null}function Wa(e,t){e.command("clone",{description:"Clone a repository into a new directory",args:[W.string().name("repository").describe("Repository to clone"),W.string().name("directory").describe("Target directory").optional()],options:{bare:A().describe("Create a bare clone"),branch:te.string().alias("b").describe("Checkout this branch instead of HEAD")},handler:async(n,r)=>{let o=n.repository;if(!o)return T("You must specify a repository to clone.");let s=o.startsWith("http://")||o.startsWith("https://"),a=s?o:ct(r.cwd,o),i=n.branch,c=n.directory;if(!c){let E=s?o.split("/").pop()??o:Wn(a);E.endsWith(".git")&&(E=E.slice(0,-4)),c=E}let f=ct(r.cwd,c);if(t?.hooks){let E=await t.hooks.emitPre("pre-clone",{repository:o,targetPath:f,bare:n.bare,branch:i??null});if(E)return{stdout:"",stderr:E.message??"",exitCode:1}}if(await r.fs.exists(f))try{if((await r.fs.readdir(f)).length>0)return T(`destination path '${c}' already exists and is not an empty directory.`)}catch{return T(`destination path '${c}' already exists and is not an empty directory.`)}let d=null;if(!s&&(d=await $n(r.fs,a),!d))return T(`repository '${o}' does not exist`);await r.fs.mkdir(f,{recursive:!0});let
|
|
284
|
+
`));i.push(yo());let d;if(n&&n.byteLength>0){let h=us(...i);d=new Uint8Array(h.byteLength+n.byteLength),d.set(h,0),d.set(n,h.byteLength)}else d=us(...i);let u=e.replace(/\/+$/,""),l=await s(`${u}/git-receive-pack`,{method:"POST",headers:{"Content-Type":"application/x-git-receive-pack-request",...xo(o),"User-Agent":"just-git/1.0"},body:d});if(!l.ok)throw new Error(`HTTP ${l.status} pushing to ${u}`);let m=new Uint8Array(await l.arrayBuffer());return a.includes("report-status")?Vl(m,a.includes("side-band-64k")):{unpackOk:!0,refResults:[],progress:[]}}function Vl(e,t){let n,r=[];if(t){let i=Gn(e),{packData:c,progress:f,errors:d}=Eo(i);if(d.length>0)throw new Error(`Remote error: ${d.join("")}`);r=f,n=Gn(c)}else n=Gn(e);let o=!1,s,a=[];for(let i of n){if(i.type==="flush")break;let c=ms(i);if(c.startsWith("unpack "))o=c==="unpack ok",o||(s=c.slice(7));else if(c.startsWith("ok "))a.push({name:c.slice(3),ok:!0});else if(c.startsWith("ng ")){let f=c.slice(3),d=f.indexOf(" ");d!==-1?a.push({name:f.slice(0,d),ok:!1,error:f.slice(d+1)}):a.push({name:f,ok:!1})}}return{unpackOk:o,unpackError:s,refResults:a,progress:r}}function _a(e,t){let n=new Set(e.map(o=>o.split("=",1)[0]??o)),r=[];for(let o of t)n.has(o)&&r.push(o);return r.push("agent=just-git/1.0"),r}var ur=class{constructor(t,n){this.local=t;this.remote=n}headTarget;async advertiseRefs(){let t=await le(this.remote),n=[];for(let s of t)n.push({name:s.name,hash:s.hash});let r=await F(this.remote,"HEAD");r&&n.push({name:"HEAD",hash:r});let o=await J(this.remote);return o?.type==="symbolic"&&(this.headTarget=o.target),n}async fetch(t,n){let r=await this.advertiseRefs();if(t.length===0)return{remoteRefs:r,objectCount:0};let o=await fs(this.remote,t,n);if(o.length===0)return{remoteRefs:r,objectCount:0};let s=[];for(let c of o){let f=await ce(this.remote,c.hash);s.push({type:f.type,content:f.content})}let a=await $r(s),i=await Ar(this.local,a);return{remoteRefs:r,objectCount:i}}async push(t){let n=[],r=[];for(let s of t)s.newHash!==Z&&n.push(s.newHash),s.oldHash&&r.push(s.oldHash);if(n.length>0){let s=await fs(this.local,n,r);if(s.length>0){let a=[];for(let c of s){let f=await ce(this.local,c.hash);a.push({type:f.type,content:f.content})}let i=await $r(a);await Ar(this.remote,i)}}let o=[];for(let s of t)try{if(s.newHash===Z){await ie(this.remote,s.name),o.push({...s,ok:!0});continue}let a=await F(this.remote,s.name);if(a&&!s.ok&&!await _t(this.remote,a,s.newHash)){o.push({...s,ok:!1,error:`non-fast-forward update rejected for ${s.name}`});continue}await Y(this.remote,s.name,s.newHash),o.push({...s,ok:!0})}catch(a){o.push({...s,ok:!1,error:a instanceof Error?a.message:String(a)})}return{updates:o}}},mr=class{constructor(t,n,r,o){this.local=t;this.url=n;this.auth=r;this.fetchFn=o}headTarget;cachedFetchCaps=null;cachedPushCaps=null;cachedFetchRefs=null;async advertiseRefs(){let t=await ko(this.url,"git-upload-pack",this.auth,this.fetchFn);this.cachedFetchCaps=t.capabilities,this.cachedFetchRefs=t.refs;let n=t.symrefs.get("HEAD");return n&&(this.headTarget=n),t.refs}async ensureFetchDiscovery(){return(!this.cachedFetchCaps||!this.cachedFetchRefs)&&await this.advertiseRefs(),{caps:this.cachedFetchCaps,refs:this.cachedFetchRefs}}async ensurePushDiscovery(){if(!this.cachedPushCaps){let t=await ko(this.url,"git-receive-pack",this.auth,this.fetchFn);this.cachedPushCaps=t.capabilities}return this.cachedPushCaps}async fetch(t,n){let{caps:r,refs:o}=await this.ensureFetchDiscovery();if(t.length===0)return{remoteRefs:o,objectCount:0};let s=await Ga(this.url,t,n,r,this.auth,this.fetchFn);if(s.packData.byteLength===0)return{remoteRefs:o,objectCount:0};let a=await Ar(this.local,s.packData);return{remoteRefs:o,objectCount:a}}async push(t){for(let d of t)if(d.oldHash&&d.oldHash!==Z&&d.newHash!==Z&&!d.ok&&!await _t(this.local,d.oldHash,d.newHash))return{updates:t.map(l=>l===d?{...l,ok:!1,error:"non-fast-forward"}:{...l,ok:!1,error:"atomic push failed"})};let n=await this.ensurePushDiscovery(),r=t.map(d=>({oldHash:d.oldHash??Z,newHash:d.newHash,refName:d.name})),o=[],s=[],a=!1;for(let d of t)d.newHash!==Z&&(o.push(d.newHash),a=!0),d.oldHash&&d.oldHash!==Z&&s.push(d.oldHash);let i=null;if(a){let d=await fs(this.local,o,s),u=[];for(let l of d){let m=await ce(this.local,l.hash);u.push({type:m.type,content:m.content})}i=await $r(u)}let c=await Na(this.url,r,i,n,this.auth,this.fetchFn);return{updates:t.map(d=>{let u=c.refResults.find(h=>h.name===d.name),l=u?.ok??c.unpackOk,m=u?.error??(!l&&c.unpackError?`unpack failed: ${c.unpackError}`:void 0);return{...d,ok:l,error:m}})}}};async function Yl(e,t){let r=(await ae(e))[`remote "${t}"`];return r?.url?{name:t,url:r.url,fetchRefspec:r.fetch??"+refs/heads/*:refs/remotes/origin/*"}:null}function Co(e){return e.startsWith("http://")||e.startsWith("https://")}function Fa(e,t){if(t===void 0)return null;if(t===!1)return"network access is disabled";if(!t.allowed)return null;if(t.allowed.length===0)return"network access is disabled";let n;try{n=new URL(e).hostname}catch{return`network policy: access to '${e}' is not allowed`}for(let r of t.allowed)if(Co(r)){if(e===r||e.startsWith(r))return null}else if(n===r)return null;return`network policy: access to '${e}' is not allowed`}function Xl(e){let t=e.get("GIT_HTTP_BEARER_TOKEN");if(t)return{type:"bearer",token:t};let n=e.get("GIT_HTTP_USER"),r=e.get("GIT_HTTP_PASSWORD");if(n&&r)return{type:"basic",username:n,password:r}}async function Ua(e,t,n){if(e.credentialProvider){let r=await e.credentialProvider(t);if(r)return r}return Xl(n)}async function Ba(e,t,n,r){if(Co(t)){let o=Fa(t,e.networkPolicy);if(o)throw new Error(o);let s=await Ua(e,t,n);return new mr(e,t,s,e.fetchFn)}if(!r)throw new Error(`'${t}' does not appear to be a git repository`);return new ur(e,r)}async function Nn(e,t,n){let r=await Yl(e,t);if(!r)return null;if(Co(r.url)){let s=Fa(r.url,e.networkPolicy);if(s)throw new Error(s);let a=n?await Ua(e,r.url,n):void 0;return{transport:new mr(e,r.url,a,e.fetchFn),config:r}}let o=await $n(e.fs,r.url);return o?{transport:new ur(e,o),config:r}:null}function Wa(e,t){e.command("clone",{description:"Clone a repository into a new directory",args:[W.string().name("repository").describe("Repository to clone"),W.string().name("directory").describe("Target directory").optional()],options:{bare:A().describe("Create a bare clone"),branch:te.string().alias("b").describe("Checkout this branch instead of HEAD")},handler:async(n,r)=>{let o=n.repository;if(!o)return T("You must specify a repository to clone.");let s=o.startsWith("http://")||o.startsWith("https://"),a=s?o:ct(r.cwd,o),i=n.branch,c=n.directory;if(!c){let E=s?o.split("/").pop()??o:Wn(a);E.endsWith(".git")&&(E=E.slice(0,-4)),c=E}let f=ct(r.cwd,c);if(t?.hooks){let E=await t.hooks.emitPre("pre-clone",{repository:o,targetPath:f,bare:n.bare,branch:i??null});if(E)return{stdout:"",stderr:E.message??"",exitCode:1}}if(await r.fs.exists(f))try{if((await r.fs.readdir(f)).length>0)return T(`destination path '${c}' already exists and is not an empty directory.`)}catch{return T(`destination path '${c}' already exists and is not an empty directory.`)}let d=null;if(!s&&(d=await $n(r.fs,a),!d))return T(`repository '${o}' does not exist`);await r.fs.mkdir(f,{recursive:!0});let{ctx:u}=await vr(r.fs,f,{bare:n.bare}),l=t?{...u,hooks:t.hooks,credentialProvider:t.credentialProvider,identityOverride:t.identityOverride,fetchFn:t.fetchFn,networkPolicy:t.networkPolicy}:u,m=await ae(l);m['remote "origin"']={url:a,fetch:"+refs/heads/*:refs/remotes/origin/*"},await Ge(l,m);let h;try{h=await Ba(l,a,r.env,d??void 0)}catch(E){let I=E instanceof Error?E.message:"";return I.startsWith("network")?T(I):T(`repository '${o}' does not exist`)}let p=await h.advertiseRefs();if(p.length===0)return await t?.hooks?.emitPost("post-clone",{repository:o,targetPath:f,bare:n.bare,branch:i??null}),{stdout:"",stderr:`Cloning into '${c}'...
|
|
285
285
|
warning: You appear to have cloned an empty repository.
|
|
286
286
|
`,exitCode:0};let g=[],w=new Set;for(let E of p)E.name!=="HEAD"&&(w.has(E.hash)||(w.add(E.hash),g.push(E.hash)));g.length>0&&await h.fetch(g,[]);let x=p.find(E=>E.name==="HEAD"),b=null,y=null,k=await Ot(l,r.env),C=`clone: from ${a}`,P=h.headTarget;P?.startsWith("refs/heads/")&&p.some(E=>E.name===P)&&(b=P.slice(11),y=p.find(E=>E.name===P)?.hash??null);for(let E of p)if(E.name!=="HEAD"){if(E.name.startsWith("refs/heads/")){let I=E.name.slice(11),H=`refs/remotes/origin/${I}`;await Y(l,H,E.hash),await Te(l,H,{oldHash:Z,newHash:E.hash,name:k.name,email:k.email,timestamp:k.timestamp,tz:k.tz,message:C}),!b&&x&&E.hash===x.hash&&(b=I,y=E.hash)}E.name.startsWith("refs/tags/")&&await Y(l,E.name,E.hash)}if(i){let E=p.find(I=>I.name===`refs/heads/${i}`);if(!E)return T(`Remote branch '${i}' not found in upstream origin`);b=i,y=E.hash}if(!b){let E=p.find(I=>I.name.startsWith("refs/heads/"));E&&(b=E.name.slice(11),y=E.hash)}if(n.bare)return b&&await $e(l,"HEAD",`refs/heads/${b}`),await t?.hooks?.emitPost("post-clone",{repository:o,targetPath:f,bare:n.bare,branch:b}),{stdout:"",stderr:`Cloning into bare repository '${c}'...
|
|
287
287
|
`,exitCode:0};if(b&&await $e(l,"refs/remotes/origin/HEAD",`refs/remotes/origin/${b}`),b&&y){await Y(l,`refs/heads/${b}`,y),await $e(l,"HEAD",`refs/heads/${b}`);let E={oldHash:Z,newHash:y,name:k.name,email:k.email,timestamp:k.timestamp,tz:k.tz,message:C};await Te(l,`refs/heads/${b}`,E),await Te(l,"HEAD",E);let I=await ae(l);I[`branch "${b}"`]={remote:"origin",merge:`refs/heads/${b}`},await Ge(l,I);let H=await M(l,y);await Gi(l,H.tree);let _=await He(l,H.tree),G=Or(_.map(z=>({path:z.path,mode:parseInt(z.mode,8),hash:z.hash,stage:0,stat:pe()})));await re(l,G)}let O={stdout:"",stderr:`Cloning into '${c}'...
|
|
@@ -334,8 +334,9 @@ Binary files differ
|
|
|
334
334
|
`)}function uc(e,t){e.command("repack",{description:"Pack unpacked objects in a repository",options:{all:A().alias("a").describe("Pack all objects, including already-packed"),delete:A().alias("d").describe("After packing, remove redundant packs and loose objects")},handler:async(n,r)=>{let o=await B(r.fs,r.cwd,t);if(S(o))return o;let s=o,a=await ic(s),i=await Io({gitCtx:s,fs:r.fs,tips:a,cleanup:n.delete,all:n.all});return i?{stdout:"",stderr:`${$o(i.totalCount,i.deltaCount)}
|
|
335
335
|
`,exitCode:0}:{stdout:`Nothing new to pack.
|
|
336
336
|
`,stderr:"",exitCode:0}}})}function mc(e,t){e.command("gc",{description:"Cleanup unnecessary files and optimize the local repository",options:{aggressive:A().describe("More aggressively optimize the repository")},handler:async(n,r)=>{let o=await B(r.fs,r.cwd,t);if(S(o))return o;let s=o;await ki(s),await tt(s);let a=await Pu(s);if(a.length>0){let i=n.aggressive?250:10,c=n.aggressive?250:50,f=await Io({gitCtx:s,fs:r.fs,tips:a,window:i,depth:c,cleanup:!0,all:!0});if(await Ou(s.gitDir,r.fs),f)return{stdout:"",stderr:`${$o(f.totalCount,f.deltaCount,!0)}
|
|
337
|
-
`,exitCode:0}}return{stdout:"",stderr:"",exitCode:0}}})}var Cu=2160*60*60;async function Pu(e){let t=new Set,n=await X(e);n&&t.add(n);let r=await le(e,"refs");for(let f of r)t.add(f.hash);let s=Math.floor(Date.now()/1e3)-Cu,a=v(e.gitDir,"logs");await e.fs.exists(a)&&await hc(e,a,a,s,t);let i=await U(e);for(let f of i.entries)t.add(f.hash);for(let f of["MERGE_HEAD","CHERRY_PICK_HEAD","ORIG_HEAD"]){let d=await F(e,f);d&&t.add(d)}let c=[];for(let f of t)await zt(e,f)&&c.push(f);return c}async function hc(e,t,n,r,o){let s=await e.fs.readdir(t);for(let a of s){let i=v(t,a),c=await e.fs.stat(i);if(c.isDirectory){await hc(e,i,n,r,o);try{(await e.fs.readdir(i)).length===0&&await e.fs.rm(i,{recursive:!0})}catch{}}else if(c.isFile){let f=i.slice(n.length+1),d=await Me(e,f);if(f==="refs/stash"){for(let l of d)l.newHash!==Z&&o.add(l.newHash);continue}let u=d.filter(l=>l.timestamp>=r);await Xt(e,f,u);for(let l of u)l.newHash!==Z&&o.add(l.newHash)}}}async function Ou(e,t){let n=v(e,"objects"),r;try{r=await t.readdir(n)}catch{return}for(let o of r)if(!(o==="pack"||o==="info"||o.length!==2))try{await t.rm(v(n,o),{recursive:!0})}catch{}}function pc(e){e.command("init",{description:"Initialize a new repository",args:[W.string().name("directory").describe("The directory to initialize").optional()],options:{bare:A().describe("Create a bare repository"),initialBranch:te.string().alias("b").describe("Name for the initial branch")},examples:["git init","git init --bare","git init my-project"],handler:async(t,n)=>{let r=t.initialBranch,o=t.directory?ct(n.cwd,t.directory):n.cwd;t.directory&&await n.fs.mkdir(o,{recursive:!0});let
|
|
338
|
-
|
|
337
|
+
`,exitCode:0}}return{stdout:"",stderr:"",exitCode:0}}})}var Cu=2160*60*60;async function Pu(e){let t=new Set,n=await X(e);n&&t.add(n);let r=await le(e,"refs");for(let f of r)t.add(f.hash);let s=Math.floor(Date.now()/1e3)-Cu,a=v(e.gitDir,"logs");await e.fs.exists(a)&&await hc(e,a,a,s,t);let i=await U(e);for(let f of i.entries)t.add(f.hash);for(let f of["MERGE_HEAD","CHERRY_PICK_HEAD","ORIG_HEAD"]){let d=await F(e,f);d&&t.add(d)}let c=[];for(let f of t)await zt(e,f)&&c.push(f);return c}async function hc(e,t,n,r,o){let s=await e.fs.readdir(t);for(let a of s){let i=v(t,a),c=await e.fs.stat(i);if(c.isDirectory){await hc(e,i,n,r,o);try{(await e.fs.readdir(i)).length===0&&await e.fs.rm(i,{recursive:!0})}catch{}}else if(c.isFile){let f=i.slice(n.length+1),d=await Me(e,f);if(f==="refs/stash"){for(let l of d)l.newHash!==Z&&o.add(l.newHash);continue}let u=d.filter(l=>l.timestamp>=r);await Xt(e,f,u);for(let l of u)l.newHash!==Z&&o.add(l.newHash)}}}async function Ou(e,t){let n=v(e,"objects"),r;try{r=await t.readdir(n)}catch{return}for(let o of r)if(!(o==="pack"||o==="info"||o.length!==2))try{await t.rm(v(n,o),{recursive:!0})}catch{}}function pc(e){e.command("init",{description:"Initialize a new repository",args:[W.string().name("directory").describe("The directory to initialize").optional()],options:{bare:A().describe("Create a bare repository"),initialBranch:te.string().alias("b").describe("Name for the initial branch")},examples:["git init","git init --bare","git init my-project"],handler:async(t,n)=>{let r=t.initialBranch,o=t.directory?ct(n.cwd,t.directory):n.cwd;t.directory&&await n.fs.mkdir(o,{recursive:!0});let{ctx:s,reinit:a}=await vr(n.fs,o,{bare:t.bare,...r?{initialBranch:r}:{}}),i="";a&&r&&(i=`warning: re-init: ignored --initial-branch=${r}
|
|
338
|
+
`);let c=t.bare?"bare ":"";return{stdout:`${a?"Reinitialized existing":"Initialized empty"} ${c}Git repository in ${s.gitDir}/
|
|
339
|
+
`,stderr:i,exitCode:0}}})}function gc(e,t){let{hash:n,commit:r}=t,o="",s=0;for(;s<e.length;){if(e[s]==="%"){let a=e[s+1];if(a===void 0){o+="%",s++;continue}if((a==="a"||a==="c")&&s+2<e.length){let i=e[s+2],c=a==="a"?r.author:r.committer;switch(i){case"n":o+=c.name,s+=3;continue;case"e":case"E":o+=c.email,s+=3;continue;case"t":o+=c.timestamp.toString(),s+=3;continue;case"I":o+=vu(c.timestamp,c.timezone),s+=3;continue;case"i":o+=Su(c.timestamp,c.timezone),s+=3;continue;case"d":o+=vt(c.timestamp,c.timezone),s+=3;continue;case"D":o+=Du(c.timestamp,c.timezone),s+=3;continue}}switch(a){case"H":o+=n,s+=2;continue;case"h":o+=K(n),s+=2;continue;case"T":o+=r.tree,s+=2;continue;case"t":o+=K(r.tree),s+=2;continue;case"P":o+=r.parents.join(" "),s+=2;continue;case"p":o+=r.parents.map(K).join(" "),s+=2;continue;case"s":o+=To(r.message),s+=2;continue;case"b":o+=Ru(r.message),s+=2;continue;case"B":o+=r.message.replace(/\n$/,""),s+=2;continue;case"d":if(t.decorations){let i=t.decorations(n);o+=i?` ${i}`:""}s+=2;continue;case"D":t.decorationsRaw&&(o+=t.decorationsRaw(n)),s+=2;continue;case"n":o+=`
|
|
339
340
|
`,s+=2;continue;case"%":o+="%",s+=2;continue;default:o+=`%${a}`,s+=2;continue}}o+=e[s],s++}return o}var To=ue;function Ru(e){let t=e.indexOf(`
|
|
340
341
|
|
|
341
342
|
`);return t===-1?"":e.slice(t+2).replace(/\n$/,"")}function wc(e){return e.startsWith("format:")?{formatStr:e.slice(7),preset:null}:e.startsWith("tformat:")?{formatStr:e.slice(8),preset:null}:["oneline","short","medium","full","fuller"].includes(e)?{formatStr:null,preset:e}:{formatStr:e,preset:null}}function bc(e,t,n,r=!1){let{hash:o,commit:s}=t,a=t.decorations?t.decorations(o):"";switch(e){case"oneline":{let i=r?K(o):o,c=To(s.message);return a?`${i} ${a} ${c}`:`${i} ${c}`}case"short":{let i=[];return n||i.push(""),i.push(a?`commit ${o} ${a}`:`commit ${o}`),s.parents.length>=2&&i.push(`Merge: ${s.parents.map(K).join(" ")}`),i.push(`Author: ${s.author.name} <${s.author.email}>`),i.push(""),i.push(` ${To(s.message)}`),i.join(`
|