diff --git a/.gitignore b/.gitignore index 0c8a985..1e5c5c0 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,7 @@ node_modules !.env.example npm-debug.log yarn-error.log -*.work \ No newline at end of file + +# Cloned repositories - should never be committed +/repos/ +repos/ \ No newline at end of file diff --git a/repos/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z/aitherboard.git/HEAD b/repos/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z/aitherboard.git/HEAD deleted file mode 100644 index cb089cd..0000000 --- a/repos/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z/aitherboard.git/HEAD +++ /dev/null @@ -1 +0,0 @@ -ref: refs/heads/master diff --git a/repos/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z/aitherboard.git/config b/repos/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z/aitherboard.git/config deleted file mode 100644 index dc433bd..0000000 --- a/repos/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z/aitherboard.git/config +++ /dev/null @@ -1,6 +0,0 @@ -[core] - repositoryformatversion = 0 - filemode = true - bare = true -[remote "origin"] - url = https://git.imwald.eu/silberengel/aitherboard.git diff --git a/repos/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z/aitherboard.git/description b/repos/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z/aitherboard.git/description deleted file mode 100644 index 498b267..0000000 --- a/repos/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z/aitherboard.git/description +++ /dev/null @@ -1 +0,0 @@ -Unnamed repository; edit this file 'description' to name the repository. diff --git a/repos/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z/aitherboard.git/hooks/applypatch-msg.sample b/repos/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z/aitherboard.git/hooks/applypatch-msg.sample deleted file mode 100755 index a5d7b84..0000000 --- a/repos/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z/aitherboard.git/hooks/applypatch-msg.sample +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/sh -# -# An example hook script to check the commit log message taken by -# applypatch from an e-mail message. -# -# The hook should exit with non-zero status after issuing an -# appropriate message if it wants to stop the commit. The hook is -# allowed to edit the commit message file. -# -# To enable this hook, rename this file to "applypatch-msg". - -. git-sh-setup -commitmsg="$(git rev-parse --git-path hooks/commit-msg)" -test -x "$commitmsg" && exec "$commitmsg" ${1+"$@"} -: diff --git a/repos/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z/aitherboard.git/hooks/commit-msg.sample b/repos/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z/aitherboard.git/hooks/commit-msg.sample deleted file mode 100755 index b58d118..0000000 --- a/repos/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z/aitherboard.git/hooks/commit-msg.sample +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/sh -# -# An example hook script to check the commit log message. -# Called by "git commit" with one argument, the name of the file -# that has the commit message. The hook should exit with non-zero -# status after issuing an appropriate message if it wants to stop the -# commit. The hook is allowed to edit the commit message file. -# -# To enable this hook, rename this file to "commit-msg". - -# Uncomment the below to add a Signed-off-by line to the message. -# Doing this in a hook is a bad idea in general, but the prepare-commit-msg -# hook is more suited to it. -# -# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') -# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" - -# This example catches duplicate Signed-off-by lines. - -test "" = "$(grep '^Signed-off-by: ' "$1" | - sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || { - echo >&2 Duplicate Signed-off-by lines. - exit 1 -} diff --git a/repos/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z/aitherboard.git/hooks/fsmonitor-watchman.sample b/repos/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z/aitherboard.git/hooks/fsmonitor-watchman.sample deleted file mode 100755 index 23e856f..0000000 --- a/repos/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z/aitherboard.git/hooks/fsmonitor-watchman.sample +++ /dev/null @@ -1,174 +0,0 @@ -#!/usr/bin/perl - -use strict; -use warnings; -use IPC::Open2; - -# An example hook script to integrate Watchman -# (https://facebook.github.io/watchman/) with git to speed up detecting -# new and modified files. -# -# The hook is passed a version (currently 2) and last update token -# formatted as a string and outputs to stdout a new update token and -# all files that have been modified since the update token. Paths must -# be relative to the root of the working tree and separated by a single NUL. -# -# To enable this hook, rename this file to "query-watchman" and set -# 'git config core.fsmonitor .git/hooks/query-watchman' -# -my ($version, $last_update_token) = @ARGV; - -# Uncomment for debugging -# print STDERR "$0 $version $last_update_token\n"; - -# Check the hook interface version -if ($version ne 2) { - die "Unsupported query-fsmonitor hook version '$version'.\n" . - "Falling back to scanning...\n"; -} - -my $git_work_tree = get_working_dir(); - -my $retry = 1; - -my $json_pkg; -eval { - require JSON::XS; - $json_pkg = "JSON::XS"; - 1; -} or do { - require JSON::PP; - $json_pkg = "JSON::PP"; -}; - -launch_watchman(); - -sub launch_watchman { - my $o = watchman_query(); - if (is_work_tree_watched($o)) { - output_result($o->{clock}, @{$o->{files}}); - } -} - -sub output_result { - my ($clockid, @files) = @_; - - # Uncomment for debugging watchman output - # open (my $fh, ">", ".git/watchman-output.out"); - # binmode $fh, ":utf8"; - # print $fh "$clockid\n@files\n"; - # close $fh; - - binmode STDOUT, ":utf8"; - print $clockid; - print "\0"; - local $, = "\0"; - print @files; -} - -sub watchman_clock { - my $response = qx/watchman clock "$git_work_tree"/; - die "Failed to get clock id on '$git_work_tree'.\n" . - "Falling back to scanning...\n" if $? != 0; - - return $json_pkg->new->utf8->decode($response); -} - -sub watchman_query { - my $pid = open2(\*CHLD_OUT, \*CHLD_IN, 'watchman -j --no-pretty') - or die "open2() failed: $!\n" . - "Falling back to scanning...\n"; - - # In the query expression below we're asking for names of files that - # changed since $last_update_token but not from the .git folder. - # - # To accomplish this, we're using the "since" generator to use the - # recency index to select candidate nodes and "fields" to limit the - # output to file names only. Then we're using the "expression" term to - # further constrain the results. - my $last_update_line = ""; - if (substr($last_update_token, 0, 1) eq "c") { - $last_update_token = "\"$last_update_token\""; - $last_update_line = qq[\n"since": $last_update_token,]; - } - my $query = <<" END"; - ["query", "$git_work_tree", {$last_update_line - "fields": ["name"], - "expression": ["not", ["dirname", ".git"]] - }] - END - - # Uncomment for debugging the watchman query - # open (my $fh, ">", ".git/watchman-query.json"); - # print $fh $query; - # close $fh; - - print CHLD_IN $query; - close CHLD_IN; - my $response = do {local $/; }; - - # Uncomment for debugging the watch response - # open ($fh, ">", ".git/watchman-response.json"); - # print $fh $response; - # close $fh; - - die "Watchman: command returned no output.\n" . - "Falling back to scanning...\n" if $response eq ""; - die "Watchman: command returned invalid output: $response\n" . - "Falling back to scanning...\n" unless $response =~ /^\{/; - - return $json_pkg->new->utf8->decode($response); -} - -sub is_work_tree_watched { - my ($output) = @_; - my $error = $output->{error}; - if ($retry > 0 and $error and $error =~ m/unable to resolve root .* directory (.*) is not watched/) { - $retry--; - my $response = qx/watchman watch "$git_work_tree"/; - die "Failed to make watchman watch '$git_work_tree'.\n" . - "Falling back to scanning...\n" if $? != 0; - $output = $json_pkg->new->utf8->decode($response); - $error = $output->{error}; - die "Watchman: $error.\n" . - "Falling back to scanning...\n" if $error; - - # Uncomment for debugging watchman output - # open (my $fh, ">", ".git/watchman-output.out"); - # close $fh; - - # Watchman will always return all files on the first query so - # return the fast "everything is dirty" flag to git and do the - # Watchman query just to get it over with now so we won't pay - # the cost in git to look up each individual file. - my $o = watchman_clock(); - $error = $output->{error}; - - die "Watchman: $error.\n" . - "Falling back to scanning...\n" if $error; - - output_result($o->{clock}, ("/")); - $last_update_token = $o->{clock}; - - eval { launch_watchman() }; - return 0; - } - - die "Watchman: $error.\n" . - "Falling back to scanning...\n" if $error; - - return 1; -} - -sub get_working_dir { - my $working_dir; - if ($^O =~ 'msys' || $^O =~ 'cygwin') { - $working_dir = Win32::GetCwd(); - $working_dir =~ tr/\\/\//; - } else { - require Cwd; - $working_dir = Cwd::cwd(); - } - - return $working_dir; -} diff --git a/repos/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z/aitherboard.git/hooks/post-update.sample b/repos/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z/aitherboard.git/hooks/post-update.sample deleted file mode 100755 index ec17ec1..0000000 --- a/repos/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z/aitherboard.git/hooks/post-update.sample +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh -# -# An example hook script to prepare a packed repository for use over -# dumb transports. -# -# To enable this hook, rename this file to "post-update". - -exec git update-server-info diff --git a/repos/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z/aitherboard.git/hooks/pre-applypatch.sample b/repos/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z/aitherboard.git/hooks/pre-applypatch.sample deleted file mode 100755 index 4142082..0000000 --- a/repos/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z/aitherboard.git/hooks/pre-applypatch.sample +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/sh -# -# An example hook script to verify what is about to be committed -# by applypatch from an e-mail message. -# -# The hook should exit with non-zero status after issuing an -# appropriate message if it wants to stop the commit. -# -# To enable this hook, rename this file to "pre-applypatch". - -. git-sh-setup -precommit="$(git rev-parse --git-path hooks/pre-commit)" -test -x "$precommit" && exec "$precommit" ${1+"$@"} -: diff --git a/repos/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z/aitherboard.git/hooks/pre-commit.sample b/repos/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z/aitherboard.git/hooks/pre-commit.sample deleted file mode 100755 index e144712..0000000 --- a/repos/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z/aitherboard.git/hooks/pre-commit.sample +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/sh -# -# An example hook script to verify what is about to be committed. -# Called by "git commit" with no arguments. The hook should -# exit with non-zero status after issuing an appropriate message if -# it wants to stop the commit. -# -# To enable this hook, rename this file to "pre-commit". - -if git rev-parse --verify HEAD >/dev/null 2>&1 -then - against=HEAD -else - # Initial commit: diff against an empty tree object - against=$(git hash-object -t tree /dev/null) -fi - -# If you want to allow non-ASCII filenames set this variable to true. -allownonascii=$(git config --type=bool hooks.allownonascii) - -# Redirect output to stderr. -exec 1>&2 - -# Cross platform projects tend to avoid non-ASCII filenames; prevent -# them from being added to the repository. We exploit the fact that the -# printable range starts at the space character and ends with tilde. -if [ "$allownonascii" != "true" ] && - # Note that the use of brackets around a tr range is ok here, (it's - # even required, for portability to Solaris 10's /usr/bin/tr), since - # the square bracket bytes happen to fall in the designated range. - test $(git diff --cached --name-only --diff-filter=A -z $against | - LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0 -then - cat <<\EOF -Error: Attempt to add a non-ASCII file name. - -This can cause problems if you want to work with people on other platforms. - -To be portable it is advisable to rename the file. - -If you know what you are doing you can disable this check using: - - git config hooks.allownonascii true -EOF - exit 1 -fi - -# If there are whitespace errors, print the offending file names and fail. -exec git diff-index --check --cached $against -- diff --git a/repos/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z/aitherboard.git/hooks/pre-merge-commit.sample b/repos/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z/aitherboard.git/hooks/pre-merge-commit.sample deleted file mode 100755 index 399eab1..0000000 --- a/repos/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z/aitherboard.git/hooks/pre-merge-commit.sample +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/sh -# -# An example hook script to verify what is about to be committed. -# Called by "git merge" with no arguments. The hook should -# exit with non-zero status after issuing an appropriate message to -# stderr if it wants to stop the merge commit. -# -# To enable this hook, rename this file to "pre-merge-commit". - -. git-sh-setup -test -x "$GIT_DIR/hooks/pre-commit" && - exec "$GIT_DIR/hooks/pre-commit" -: diff --git a/repos/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z/aitherboard.git/hooks/pre-push.sample b/repos/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z/aitherboard.git/hooks/pre-push.sample deleted file mode 100755 index 4ce688d..0000000 --- a/repos/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z/aitherboard.git/hooks/pre-push.sample +++ /dev/null @@ -1,53 +0,0 @@ -#!/bin/sh - -# An example hook script to verify what is about to be pushed. Called by "git -# push" after it has checked the remote status, but before anything has been -# pushed. If this script exits with a non-zero status nothing will be pushed. -# -# This hook is called with the following parameters: -# -# $1 -- Name of the remote to which the push is being done -# $2 -- URL to which the push is being done -# -# If pushing without using a named remote those arguments will be equal. -# -# Information about the commits which are being pushed is supplied as lines to -# the standard input in the form: -# -# -# -# This sample shows how to prevent push of commits where the log message starts -# with "WIP" (work in progress). - -remote="$1" -url="$2" - -zero=$(git hash-object --stdin &2 "Found WIP commit in $local_ref, not pushing" - exit 1 - fi - fi -done - -exit 0 diff --git a/repos/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z/aitherboard.git/hooks/pre-rebase.sample b/repos/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z/aitherboard.git/hooks/pre-rebase.sample deleted file mode 100755 index 6cbef5c..0000000 --- a/repos/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z/aitherboard.git/hooks/pre-rebase.sample +++ /dev/null @@ -1,169 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2006, 2008 Junio C Hamano -# -# The "pre-rebase" hook is run just before "git rebase" starts doing -# its job, and can prevent the command from running by exiting with -# non-zero status. -# -# The hook is called with the following parameters: -# -# $1 -- the upstream the series was forked from. -# $2 -- the branch being rebased (or empty when rebasing the current branch). -# -# This sample shows how to prevent topic branches that are already -# merged to 'next' branch from getting rebased, because allowing it -# would result in rebasing already published history. - -publish=next -basebranch="$1" -if test "$#" = 2 -then - topic="refs/heads/$2" -else - topic=`git symbolic-ref HEAD` || - exit 0 ;# we do not interrupt rebasing detached HEAD -fi - -case "$topic" in -refs/heads/??/*) - ;; -*) - exit 0 ;# we do not interrupt others. - ;; -esac - -# Now we are dealing with a topic branch being rebased -# on top of master. Is it OK to rebase it? - -# Does the topic really exist? -git show-ref -q "$topic" || { - echo >&2 "No such branch $topic" - exit 1 -} - -# Is topic fully merged to master? -not_in_master=`git rev-list --pretty=oneline ^master "$topic"` -if test -z "$not_in_master" -then - echo >&2 "$topic is fully merged to master; better remove it." - exit 1 ;# we could allow it, but there is no point. -fi - -# Is topic ever merged to next? If so you should not be rebasing it. -only_next_1=`git rev-list ^master "^$topic" ${publish} | sort` -only_next_2=`git rev-list ^master ${publish} | sort` -if test "$only_next_1" = "$only_next_2" -then - not_in_topic=`git rev-list "^$topic" master` - if test -z "$not_in_topic" - then - echo >&2 "$topic is already up to date with master" - exit 1 ;# we could allow it, but there is no point. - else - exit 0 - fi -else - not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"` - /usr/bin/perl -e ' - my $topic = $ARGV[0]; - my $msg = "* $topic has commits already merged to public branch:\n"; - my (%not_in_next) = map { - /^([0-9a-f]+) /; - ($1 => 1); - } split(/\n/, $ARGV[1]); - for my $elem (map { - /^([0-9a-f]+) (.*)$/; - [$1 => $2]; - } split(/\n/, $ARGV[2])) { - if (!exists $not_in_next{$elem->[0]}) { - if ($msg) { - print STDERR $msg; - undef $msg; - } - print STDERR " $elem->[1]\n"; - } - } - ' "$topic" "$not_in_next" "$not_in_master" - exit 1 -fi - -<<\DOC_END - -This sample hook safeguards topic branches that have been -published from being rewound. - -The workflow assumed here is: - - * Once a topic branch forks from "master", "master" is never - merged into it again (either directly or indirectly). - - * Once a topic branch is fully cooked and merged into "master", - it is deleted. If you need to build on top of it to correct - earlier mistakes, a new topic branch is created by forking at - the tip of the "master". This is not strictly necessary, but - it makes it easier to keep your history simple. - - * Whenever you need to test or publish your changes to topic - branches, merge them into "next" branch. - -The script, being an example, hardcodes the publish branch name -to be "next", but it is trivial to make it configurable via -$GIT_DIR/config mechanism. - -With this workflow, you would want to know: - -(1) ... if a topic branch has ever been merged to "next". Young - topic branches can have stupid mistakes you would rather - clean up before publishing, and things that have not been - merged into other branches can be easily rebased without - affecting other people. But once it is published, you would - not want to rewind it. - -(2) ... if a topic branch has been fully merged to "master". - Then you can delete it. More importantly, you should not - build on top of it -- other people may already want to - change things related to the topic as patches against your - "master", so if you need further changes, it is better to - fork the topic (perhaps with the same name) afresh from the - tip of "master". - -Let's look at this example: - - o---o---o---o---o---o---o---o---o---o "next" - / / / / - / a---a---b A / / - / / / / - / / c---c---c---c B / - / / / \ / - / / / b---b C \ / - / / / / \ / - ---o---o---o---o---o---o---o---o---o---o---o "master" - - -A, B and C are topic branches. - - * A has one fix since it was merged up to "next". - - * B has finished. It has been fully merged up to "master" and "next", - and is ready to be deleted. - - * C has not merged to "next" at all. - -We would want to allow C to be rebased, refuse A, and encourage -B to be deleted. - -To compute (1): - - git rev-list ^master ^topic next - git rev-list ^master next - - if these match, topic has not merged in next at all. - -To compute (2): - - git rev-list master..topic - - if this is empty, it is fully merged to "master". - -DOC_END diff --git a/repos/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z/aitherboard.git/hooks/pre-receive.sample b/repos/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z/aitherboard.git/hooks/pre-receive.sample deleted file mode 100755 index a1fd29e..0000000 --- a/repos/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z/aitherboard.git/hooks/pre-receive.sample +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/sh -# -# An example hook script to make use of push options. -# The example simply echoes all push options that start with 'echoback=' -# and rejects all pushes when the "reject" push option is used. -# -# To enable this hook, rename this file to "pre-receive". - -if test -n "$GIT_PUSH_OPTION_COUNT" -then - i=0 - while test "$i" -lt "$GIT_PUSH_OPTION_COUNT" - do - eval "value=\$GIT_PUSH_OPTION_$i" - case "$value" in - echoback=*) - echo "echo from the pre-receive-hook: ${value#*=}" >&2 - ;; - reject) - exit 1 - esac - i=$((i + 1)) - done -fi diff --git a/repos/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z/aitherboard.git/hooks/prepare-commit-msg.sample b/repos/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z/aitherboard.git/hooks/prepare-commit-msg.sample deleted file mode 100755 index 10fa14c..0000000 --- a/repos/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z/aitherboard.git/hooks/prepare-commit-msg.sample +++ /dev/null @@ -1,42 +0,0 @@ -#!/bin/sh -# -# An example hook script to prepare the commit log message. -# Called by "git commit" with the name of the file that has the -# commit message, followed by the description of the commit -# message's source. The hook's purpose is to edit the commit -# message file. If the hook fails with a non-zero status, -# the commit is aborted. -# -# To enable this hook, rename this file to "prepare-commit-msg". - -# This hook includes three examples. The first one removes the -# "# Please enter the commit message..." help message. -# -# The second includes the output of "git diff --name-status -r" -# into the message, just before the "git status" output. It is -# commented because it doesn't cope with --amend or with squashed -# commits. -# -# The third example adds a Signed-off-by line to the message, that can -# still be edited. This is rarely a good idea. - -COMMIT_MSG_FILE=$1 -COMMIT_SOURCE=$2 -SHA1=$3 - -/usr/bin/perl -i.bak -ne 'print unless(m/^. Please enter the commit message/..m/^#$/)' "$COMMIT_MSG_FILE" - -# case "$COMMIT_SOURCE,$SHA1" in -# ,|template,) -# /usr/bin/perl -i.bak -pe ' -# print "\n" . `git diff --cached --name-status -r` -# if /^#/ && $first++ == 0' "$COMMIT_MSG_FILE" ;; -# *) ;; -# esac - -# SOB=$(git var GIT_COMMITTER_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') -# git interpret-trailers --in-place --trailer "$SOB" "$COMMIT_MSG_FILE" -# if test -z "$COMMIT_SOURCE" -# then -# /usr/bin/perl -i.bak -pe 'print "\n" if !$first_line++' "$COMMIT_MSG_FILE" -# fi diff --git a/repos/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z/aitherboard.git/hooks/push-to-checkout.sample b/repos/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z/aitherboard.git/hooks/push-to-checkout.sample deleted file mode 100755 index af5a0c0..0000000 --- a/repos/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z/aitherboard.git/hooks/push-to-checkout.sample +++ /dev/null @@ -1,78 +0,0 @@ -#!/bin/sh - -# An example hook script to update a checked-out tree on a git push. -# -# This hook is invoked by git-receive-pack(1) when it reacts to git -# push and updates reference(s) in its repository, and when the push -# tries to update the branch that is currently checked out and the -# receive.denyCurrentBranch configuration variable is set to -# updateInstead. -# -# By default, such a push is refused if the working tree and the index -# of the remote repository has any difference from the currently -# checked out commit; when both the working tree and the index match -# the current commit, they are updated to match the newly pushed tip -# of the branch. This hook is to be used to override the default -# behaviour; however the code below reimplements the default behaviour -# as a starting point for convenient modification. -# -# The hook receives the commit with which the tip of the current -# branch is going to be updated: -commit=$1 - -# It can exit with a non-zero status to refuse the push (when it does -# so, it must not modify the index or the working tree). -die () { - echo >&2 "$*" - exit 1 -} - -# Or it can make any necessary changes to the working tree and to the -# index to bring them to the desired state when the tip of the current -# branch is updated to the new commit, and exit with a zero status. -# -# For example, the hook can simply run git read-tree -u -m HEAD "$1" -# in order to emulate git fetch that is run in the reverse direction -# with git push, as the two-tree form of git read-tree -u -m is -# essentially the same as git switch or git checkout that switches -# branches while keeping the local changes in the working tree that do -# not interfere with the difference between the branches. - -# The below is a more-or-less exact translation to shell of the C code -# for the default behaviour for git's push-to-checkout hook defined in -# the push_to_deploy() function in builtin/receive-pack.c. -# -# Note that the hook will be executed from the repository directory, -# not from the working tree, so if you want to perform operations on -# the working tree, you will have to adapt your code accordingly, e.g. -# by adding "cd .." or using relative paths. - -if ! git update-index -q --ignore-submodules --refresh -then - die "Up-to-date check failed" -fi - -if ! git diff-files --quiet --ignore-submodules -- -then - die "Working directory has unstaged changes" -fi - -# This is a rough translation of: -# -# head_has_history() ? "HEAD" : EMPTY_TREE_SHA1_HEX -if git cat-file -e HEAD 2>/dev/null -then - head=HEAD -else - head=$(git hash-object -t tree --stdin &2 - exit 1 -} - -unset GIT_DIR GIT_WORK_TREE -cd "$worktree" && - -if grep -q "^diff --git " "$1" -then - validate_patch "$1" -else - validate_cover_letter "$1" -fi && - -if test "$GIT_SENDEMAIL_FILE_COUNTER" = "$GIT_SENDEMAIL_FILE_TOTAL" -then - git config --unset-all sendemail.validateWorktree && - trap 'git worktree remove -ff "$worktree"' EXIT && - validate_series -fi diff --git a/repos/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z/aitherboard.git/hooks/update.sample b/repos/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z/aitherboard.git/hooks/update.sample deleted file mode 100755 index c4d426b..0000000 --- a/repos/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z/aitherboard.git/hooks/update.sample +++ /dev/null @@ -1,128 +0,0 @@ -#!/bin/sh -# -# An example hook script to block unannotated tags from entering. -# Called by "git receive-pack" with arguments: refname sha1-old sha1-new -# -# To enable this hook, rename this file to "update". -# -# Config -# ------ -# hooks.allowunannotated -# This boolean sets whether unannotated tags will be allowed into the -# repository. By default they won't be. -# hooks.allowdeletetag -# This boolean sets whether deleting tags will be allowed in the -# repository. By default they won't be. -# hooks.allowmodifytag -# This boolean sets whether a tag may be modified after creation. By default -# it won't be. -# hooks.allowdeletebranch -# This boolean sets whether deleting branches will be allowed in the -# repository. By default they won't be. -# hooks.denycreatebranch -# This boolean sets whether remotely creating branches will be denied -# in the repository. By default this is allowed. -# - -# --- Command line -refname="$1" -oldrev="$2" -newrev="$3" - -# --- Safety check -if [ -z "$GIT_DIR" ]; then - echo "Don't run this script from the command line." >&2 - echo " (if you want, you could supply GIT_DIR then run" >&2 - echo " $0 )" >&2 - exit 1 -fi - -if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then - echo "usage: $0 " >&2 - exit 1 -fi - -# --- Config -allowunannotated=$(git config --type=bool hooks.allowunannotated) -allowdeletebranch=$(git config --type=bool hooks.allowdeletebranch) -denycreatebranch=$(git config --type=bool hooks.denycreatebranch) -allowdeletetag=$(git config --type=bool hooks.allowdeletetag) -allowmodifytag=$(git config --type=bool hooks.allowmodifytag) - -# check for no description -projectdesc=$(sed -e '1q' "$GIT_DIR/description") -case "$projectdesc" in -"Unnamed repository"* | "") - echo "*** Project description file hasn't been set" >&2 - exit 1 - ;; -esac - -# --- Check types -# if $newrev is 0000...0000, it's a commit to delete a ref. -zero=$(git hash-object --stdin &2 - echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2 - exit 1 - fi - ;; - refs/tags/*,delete) - # delete tag - if [ "$allowdeletetag" != "true" ]; then - echo "*** Deleting a tag is not allowed in this repository" >&2 - exit 1 - fi - ;; - refs/tags/*,tag) - # annotated tag - if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1 - then - echo "*** Tag '$refname' already exists." >&2 - echo "*** Modifying a tag is not allowed in this repository." >&2 - exit 1 - fi - ;; - refs/heads/*,commit) - # branch - if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then - echo "*** Creating a branch is not allowed in this repository" >&2 - exit 1 - fi - ;; - refs/heads/*,delete) - # delete branch - if [ "$allowdeletebranch" != "true" ]; then - echo "*** Deleting a branch is not allowed in this repository" >&2 - exit 1 - fi - ;; - refs/remotes/*,commit) - # tracking branch - ;; - refs/remotes/*,delete) - # delete tracking branch - if [ "$allowdeletebranch" != "true" ]; then - echo "*** Deleting a tracking branch is not allowed in this repository" >&2 - exit 1 - fi - ;; - *) - # Anything else (is there anything else?) - echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2 - exit 1 - ;; -esac - -# --- Finished -exit 0 diff --git a/repos/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z/aitherboard.git/info/exclude b/repos/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z/aitherboard.git/info/exclude deleted file mode 100644 index a5196d1..0000000 --- a/repos/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z/aitherboard.git/info/exclude +++ /dev/null @@ -1,6 +0,0 @@ -# git ls-files --others --exclude-from=.git/info/exclude -# Lines that start with '#' are comments. -# For a project mostly in C, the following would be a good set of -# exclude patterns (uncomment them if you want to use them): -# *.[oa] -# *~ diff --git a/repos/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z/aitherboard.git/objects/pack/pack-c7c33f30769d9ba1ce88b50f7b5c2e45ff731231.idx b/repos/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z/aitherboard.git/objects/pack/pack-c7c33f30769d9ba1ce88b50f7b5c2e45ff731231.idx deleted file mode 100644 index 3ebab1a..0000000 Binary files a/repos/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z/aitherboard.git/objects/pack/pack-c7c33f30769d9ba1ce88b50f7b5c2e45ff731231.idx and /dev/null differ diff --git a/repos/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z/aitherboard.git/objects/pack/pack-c7c33f30769d9ba1ce88b50f7b5c2e45ff731231.pack b/repos/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z/aitherboard.git/objects/pack/pack-c7c33f30769d9ba1ce88b50f7b5c2e45ff731231.pack deleted file mode 100644 index 329ad46..0000000 Binary files a/repos/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z/aitherboard.git/objects/pack/pack-c7c33f30769d9ba1ce88b50f7b5c2e45ff731231.pack and /dev/null differ diff --git a/repos/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z/aitherboard.git/objects/pack/pack-c7c33f30769d9ba1ce88b50f7b5c2e45ff731231.rev b/repos/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z/aitherboard.git/objects/pack/pack-c7c33f30769d9ba1ce88b50f7b5c2e45ff731231.rev deleted file mode 100644 index 285cec7..0000000 Binary files a/repos/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z/aitherboard.git/objects/pack/pack-c7c33f30769d9ba1ce88b50f7b5c2e45ff731231.rev and /dev/null differ diff --git a/repos/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z/aitherboard.git/packed-refs b/repos/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z/aitherboard.git/packed-refs deleted file mode 100644 index c3ec2b7..0000000 --- a/repos/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z/aitherboard.git/packed-refs +++ /dev/null @@ -1,2 +0,0 @@ -# pack-refs with: peeled fully-peeled sorted -432ca405d33a6389b1d12529e6e0e76b523b39f8 refs/heads/master diff --git a/repos/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z/aitherboard.work b/repos/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z/aitherboard.work deleted file mode 160000 index 432ca40..0000000 --- a/repos/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z/aitherboard.work +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 432ca405d33a6389b1d12529e6e0e76b523b39f8 diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 8278a2d..47826c4 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -2,331 +2,57 @@ import { onMount } from 'svelte'; import { goto } from '$app/navigation'; import { page } from '$app/stores'; - import { NostrClient } from '../lib/services/nostr/nostr-client.js'; - import { KIND } from '../lib/types/nostr.js'; - import type { NostrEvent } from '../lib/types/nostr.js'; - import { nip19 } from 'nostr-tools'; - import { ForkCountService } from '../lib/services/nostr/fork-count-service.js'; import { getPublicKeyWithNIP07, isNIP07Available } from '../lib/services/nostr/nip07-signer.js'; + import { nip19 } from 'nostr-tools'; - // Registered repos (with domain in clone URLs) - let registeredRepos = $state>([]); - let allRegisteredRepos = $state>([]); - - // Local clones (repos without domain in clone URLs) - let localRepos = $state>([]); - let allLocalRepos = $state>([]); - - let loading = $state(true); - let loadingLocal = $state(false); - let error = $state(null); - let forkCounts = $state>(new Map()); - let searchQuery = $state(''); - let showOnlyMyContacts = $state(false); let userPubkey = $state(null); let userPubkeyHex = $state(null); - let contactPubkeys = $state>(new Set()); - let deletingRepo = $state<{ npub: string; repo: string } | null>(null); - - import { DEFAULT_NOSTR_RELAYS } from '../lib/config.js'; - const forkCountService = new ForkCountService(DEFAULT_NOSTR_RELAYS); - - const nostrClient = new NostrClient(DEFAULT_NOSTR_RELAYS); + let checkingAuth = $state(true); onMount(async () => { - await loadRepos(); - await loadUserAndContacts(); + await checkAuth(); }); - async function loadUserAndContacts() { - if (!isNIP07Available()) { - return; - } - - try { - userPubkey = await getPublicKeyWithNIP07(); - - // Convert npub to hex for API calls + async function checkAuth() { + checkingAuth = true; + if (isNIP07Available()) { try { - const decoded = nip19.decode(userPubkey); - if (decoded.type === 'npub') { - userPubkeyHex = decoded.data as string; - } - } catch { - userPubkeyHex = userPubkey; // Assume it's already hex - } - - contactPubkeys.add(userPubkeyHex); // Include user's own repos - - // Fetch user's kind 3 contact list - const contactEvents = await nostrClient.fetchEvents([ - { - kinds: [KIND.CONTACT_LIST], - authors: [userPubkeyHex], - limit: 1 - } - ]); - - if (contactEvents.length > 0) { - const contactEvent = contactEvents[0]; - // Extract pubkeys from 'p' tags - for (const tag of contactEvent.tags) { - if (tag[0] === 'p' && tag[1]) { - let pubkey = tag[1]; - // Try to decode if it's an npub - try { - const decoded = nip19.decode(pubkey); - if (decoded.type === 'npub') { - pubkey = decoded.data as string; - } - } catch { - // Assume it's already a hex pubkey - } - if (pubkey) { - contactPubkeys.add(pubkey); - } + userPubkey = await getPublicKeyWithNIP07(); + // Convert npub to hex for API calls + try { + const decoded = nip19.decode(userPubkey); + if (decoded.type === 'npub') { + userPubkeyHex = decoded.data as string; } + } catch { + userPubkeyHex = userPubkey; // Assume it's already hex } - } - } catch (err) { - console.warn('Failed to load user or contacts:', err); - } - } - - async function loadRepos() { - loading = true; - error = null; - - try { - const gitDomain = $page.data.gitDomain || 'localhost:6543'; - const url = `/api/repos/list?domain=${encodeURIComponent(gitDomain)}`; - - const response = await fetch(url, { - headers: userPubkeyHex ? { - 'X-User-Pubkey': userPubkeyHex - } : {} - }); - - if (!response.ok) { - throw new Error(`Failed to load repositories: ${response.statusText}`); - } - - const data = await response.json(); - - // Set registered repos - registeredRepos = data.registered || []; - allRegisteredRepos = [...registeredRepos]; - - // Load fork counts for registered repos (in parallel, but don't block) - loadForkCounts(registeredRepos.map(r => r.event)).catch(err => { - console.warn('[RepoList] Failed to load some fork counts:', err); - }); - - // Load local repos separately (async, don't block) - loadLocalRepos(); - } catch (e) { - error = String(e); - console.error('[RepoList] Failed to load repos:', e); - } finally { - loading = false; - } - } - - async function loadLocalRepos() { - loadingLocal = true; - - try { - const gitDomain = $page.data.gitDomain || 'localhost:6543'; - const url = `/api/repos/local?domain=${encodeURIComponent(gitDomain)}`; - - const response = await fetch(url, { - headers: userPubkeyHex ? { - 'X-User-Pubkey': userPubkeyHex - } : {} - }); - - if (!response.ok) { - console.warn('Failed to load local repos:', response.statusText); - return; - } - - const data = await response.json(); - localRepos = data || []; - allLocalRepos = [...localRepos]; - } catch (e) { - console.warn('[RepoList] Failed to load local repos:', e); - } finally { - loadingLocal = false; - } - } - - async function deleteLocalRepo(npub: string, repo: string) { - if (!confirm(`Are you sure you want to delete the local clone of ${repo}? This will remove the repository from this server but will not delete the announcement on Nostr.`)) { - return; - } - - deletingRepo = { npub, repo }; - - try { - const response = await fetch(`/api/repos/${npub}/${repo}/delete`, { - method: 'DELETE', - headers: userPubkeyHex ? { - 'X-User-Pubkey': userPubkeyHex - } : {} - }); - - if (!response.ok) { - const error = await response.json(); - throw new Error(error.message || 'Failed to delete repository'); - } - - // Remove from local repos list - localRepos = localRepos.filter(r => !(r.npub === npub && r.repoName === repo)); - allLocalRepos = [...localRepos]; - - alert('Repository deleted successfully'); - } catch (e) { - alert(`Failed to delete repository: ${e instanceof Error ? e.message : String(e)}`); - } finally { - deletingRepo = null; - } - } - - function registerRepo(npub: string, repo: string) { - // Navigate to signup page with repo pre-filled - goto(`/signup?npub=${encodeURIComponent(npub)}&repo=${encodeURIComponent(repo)}`); - } - - async function loadForkCounts(repoEvents: NostrEvent[]) { - const counts = new Map(); - - // Extract owner pubkey and repo name for each repo - const forkCountPromises = repoEvents.map(async (event) => { - try { - const dTag = event.tags.find(t => t[0] === 'd')?.[1]; - if (!dTag) return; - - const repoKey = `${event.pubkey}:${dTag}`; - const count = await forkCountService.getForkCount(event.pubkey, dTag); - counts.set(repoKey, count); } catch (err) { - // Ignore individual failures + console.warn('Failed to load user pubkey:', err); } - }); - - await Promise.all(forkCountPromises); - forkCounts = counts; - } - - function getForkCount(event: NostrEvent): number { - const dTag = event.tags.find(t => t[0] === 'd')?.[1]; - if (!dTag) return 0; - const repoKey = `${event.pubkey}:${dTag}`; - return forkCounts.get(repoKey) || 0; - } - - function isOwner(npub: string, repoName: string): boolean { - if (!userPubkeyHex) return false; - try { - const decoded = nip19.decode(npub); - if (decoded.type === 'npub') { - return decoded.data === userPubkeyHex; - } - } catch { - // Invalid npub } - return false; + checkingAuth = false; } - function goToSearch() { - goto('/search'); - } - - function getRepoName(event: NostrEvent): string { - const nameTag = event.tags.find(t => t[0] === 'name' && t[1]); - if (nameTag?.[1]) return nameTag[1]; - - const dTag = event.tags.find(t => t[0] === 'd')?.[1]; - if (dTag) return dTag; - - return `Repository ${event.id.slice(0, 8)}`; - } - - function getRepoDescription(event: NostrEvent): string { - const descTag = event.tags.find(t => t[0] === 'description' && t[1]); - return descTag?.[1] || ''; - } - - function getRepoImage(event: NostrEvent): string | null { - const imageTag = event.tags.find(t => t[0] === 'image' && t[1]); - return imageTag?.[1] || null; - } - - function getRepoBanner(event: NostrEvent): string | null { - const bannerTag = event.tags.find(t => t[0] === 'banner' && t[1]); - return bannerTag?.[1] || null; - } - - function getCloneUrls(event: NostrEvent): string[] { - const urls: string[] = []; - - for (const tag of event.tags) { - if (tag[0] === 'clone') { - for (let i = 1; i < tag.length; i++) { - const url = tag[i]; - if (url && typeof url === 'string') { - urls.push(url); - } + async function handleLogin() { + if (isNIP07Available()) { + try { + await checkAuth(); + if (userPubkey) { + // User is logged in, go to repos page + goto('/repos'); } + } catch (err) { + console.error('Login failed:', err); + alert('Failed to login. Please make sure you have a Nostr extension installed (like nos2x or Alby).'); } + } else { + alert('Nostr extension not found. Please install a Nostr extension like nos2x or Alby to login.'); } - - return urls; } - function getNpubFromEvent(event: NostrEvent): string { - // Extract npub from clone URLs that match our domain - const gitDomain = $page.data.gitDomain || 'localhost:6543'; - const cloneUrls = getCloneUrls(event); - - for (const url of cloneUrls) { - if (url.includes(gitDomain)) { - // Extract npub from URL: https://domain/npub.../repo.git - const match = url.match(/\/(npub[a-z0-9]+)\//); - if (match) { - return match[1]; - } - } - } - - // Fallback: convert pubkey to npub if needed - try { - if (event.pubkey.startsWith('npub')) { - return event.pubkey; - } - return nip19.npubEncode(event.pubkey); - } catch { - // If conversion fails, return pubkey as-is - return event.pubkey; - } - } - - function getRepoNameFromUrl(event: NostrEvent): string { - const gitDomain = $page.data.gitDomain || 'localhost:6543'; - const cloneUrls = getCloneUrls(event); - - for (const url of cloneUrls) { - if (url.includes(gitDomain)) { - // Extract repo name from URL: https://domain/npub.../repo-name.git - const match = url.match(/\/(npub[a-z0-9]+)\/([^\/]+)\.git/); - if (match) { - return match[2]; - } - } - } - - // Fallback to repo name from event - return getRepoName(event); + function handleViewPublic() { + goto('/repos'); } // Get page data for OpenGraph metadata @@ -337,101 +63,6 @@ url?: string; ogType?: string; }; - - interface SearchResult { - repo: NostrEvent; - score: number; - matchType: string; - } - - function performSearch() { - if (!searchQuery.trim()) { - registeredRepos = [...allRegisteredRepos]; - localRepos = [...allLocalRepos]; - return; - } - - const query = searchQuery.trim().toLowerCase(); - - // Search registered repos - let registeredToSearch = allRegisteredRepos; - if (showOnlyMyContacts && contactPubkeys.size > 0) { - registeredToSearch = allRegisteredRepos.filter(item => { - const event = item.event; - // Check if owner is in contacts - if (contactPubkeys.has(event.pubkey)) return true; - - // Check if any maintainer is in contacts - const maintainerTags = event.tags.filter(t => t[0] === 'maintainers'); - for (const tag of maintainerTags) { - for (let i = 1; i < tag.length; i++) { - let maintainerPubkey = tag[i]; - try { - const decoded = nip19.decode(maintainerPubkey); - if (decoded.type === 'npub') { - maintainerPubkey = decoded.data as string; - } - } catch { - // Assume it's already a hex pubkey - } - if (contactPubkeys.has(maintainerPubkey)) return true; - } - } - return false; - }); - } - - const registeredResults: Array<{ item: typeof allRegisteredRepos[0]; score: number }> = []; - for (const item of registeredToSearch) { - const repo = item.event; - let score = 0; - - const name = getRepoName(repo).toLowerCase(); - const dTag = repo.tags.find(t => t[0] === 'd')?.[1]?.toLowerCase() || ''; - const description = getRepoDescription(repo).toLowerCase(); - - if (name.includes(query)) score += 100; - if (dTag.includes(query)) score += 100; - if (description.includes(query)) score += 30; - - if (score > 0) { - registeredResults.push({ item, score }); - } - } - - registeredResults.sort((a, b) => b.score - a.score || b.item.event.created_at - a.item.event.created_at); - registeredRepos = registeredResults.map(r => r.item); - - // Search local repos - const localResults: Array<{ item: typeof allLocalRepos[0]; score: number }> = []; - for (const item of allLocalRepos) { - let score = 0; - const repoName = item.repoName.toLowerCase(); - const announcement = item.announcement; - - if (repoName.includes(query)) score += 100; - if (announcement) { - const name = getRepoName(announcement).toLowerCase(); - const description = getRepoDescription(announcement).toLowerCase(); - if (name.includes(query)) score += 100; - if (description.includes(query)) score += 30; - } - - if (score > 0) { - localResults.push({ item, score }); - } - } - - localResults.sort((a, b) => b.score - a.score || b.item.lastModified - a.item.lastModified); - localRepos = localResults.map(r => r.item); - } - - // Reactive search when query or filter changes - $effect(() => { - if (!loading) { - performSearch(); - } - }); @@ -458,183 +89,272 @@ {/if} -
-
-
-

Repositories on {$page.data.gitDomain || 'localhost:6543'}

- +
+
+ GitRepublic Logo +
+ +
+
+ +

GitRepublic

+

Decentralized Git Hosting on Nostr

-
-
- -
- {#if isNIP07Available() && userPubkey} - +
+ {#if checkingAuth} +

Checking authentication...

+ {:else if userPubkey} +

Welcome back! You're logged in.

+

You can now access all repositories you have permission to view.

+ {:else} +

Login for full functionality

+

Access your private repositories, create new ones, and collaborate with others.

+

Or browse public repositories without logging in.

{/if}
- {#if error} -
- Error loading repositories: {error} +
+ {#if checkingAuth} +
Loading...
+ {:else if userPubkey} + + {:else} + + + {/if} +
+ +
+
+ 🔐 Private Repositories +

Control who can access your code

- {:else if loading} -
Loading repositories...
- {:else} - -
-
-

Registered Repositories

- {registeredRepos.length} -
- {#if registeredRepos.length === 0} -
No registered repositories found.
- {:else} -
- {#each registeredRepos as item} - {@const repo = item.event} - {@const repoImage = getRepoImage(repo)} - {@const repoBanner = getRepoBanner(repo)} -
- {#if repoBanner} -
- Banner -
- {/if} -
-
- {#if repoImage} - Repository - {/if} -
-

{getRepoName(repo)}

- {#if getRepoDescription(repo)} -

{getRepoDescription(repo)}

- {/if} -
- - View & Edit → - -
-
- Clone URLs: - {#each getCloneUrls(repo) as url} - {url} - {/each} -
-
- Created: {new Date(repo.created_at * 1000).toLocaleDateString()} - {#if getForkCount(repo) > 0} - {@const forkCount = getForkCount(repo)} - 🍴 {forkCount} fork{forkCount === 1 ? '' : 's'} - {/if} -
-
-
- {/each} -
- {/if} +
+ 🌐 Decentralized +

Built on Nostr protocol

- - -
-
-

Local Clones

- {localRepos.length} - Repositories cloned locally but not registered with this domain -
- {#if loadingLocal} -
Loading local repositories...
- {:else if localRepos.length === 0} -
No local clones found.
- {:else} -
- {#each localRepos as item} - {@const repo = item.announcement} - {@const repoImage = repo ? getRepoImage(repo) : null} - {@const repoBanner = repo ? getRepoBanner(repo) : null} - {@const canDelete = isOwner(item.npub, item.repoName)} -
- {#if repoBanner} -
- Banner -
- {/if} -
-
- {#if repoImage} - Repository - {/if} -
-

{repo ? getRepoName(repo) : item.repoName}

- {#if repo && getRepoDescription(repo)} -

{getRepoDescription(repo)}

- {:else} -

No description available

- {/if} -
-
- - View & Edit → - - {#if canDelete} - - {/if} - -
-
- {#if repo} -
- Clone URLs: - {#each getCloneUrls(repo) as url} - {url} - {/each} -
- {/if} -
- Last modified: {new Date(item.lastModified).toLocaleDateString()} - {#if repo} - Created: {new Date(repo.created_at * 1000).toLocaleDateString()} - {#if getForkCount(repo) > 0} - {@const forkCount = getForkCount(repo)} - 🍴 {forkCount} fork{forkCount === 1 ? '' : 's'} - {/if} - {/if} -
-
-
- {/each} -
- {/if} +
+ 🔧 Full Git Support +

All standard Git operations

- {/if} -
+
+ + diff --git a/src/routes/repos/[npub]/[repo]/+page.svelte b/src/routes/repos/[npub]/[repo]/+page.svelte index a818f8a..60bf7a9 100644 --- a/src/routes/repos/[npub]/[repo]/+page.svelte +++ b/src/routes/repos/[npub]/[repo]/+page.svelte @@ -483,6 +483,39 @@ loadingDocs = true; try { + // Check if repo is private and user has access + const data = $page.data as typeof pageData; + if (data.repoIsPrivate) { + // Check access via API + const headers: Record = {}; + if (userPubkey) { + try { + const decoded = nip19.decode(userPubkey); + if (decoded.type === 'npub') { + headers['X-User-Pubkey'] = decoded.data as string; + } else { + headers['X-User-Pubkey'] = userPubkey; + } + } catch { + headers['X-User-Pubkey'] = userPubkey; + } + } + + const accessResponse = await fetch(`/api/repos/${npub}/${repo}/access`, { headers }); + if (accessResponse.ok) { + const accessData = await accessResponse.json(); + if (!accessData.canView) { + // User doesn't have access, don't load documentation + loadingDocs = false; + return; + } + } else { + // Access check failed, don't load documentation + loadingDocs = false; + return; + } + } + const decoded = nip19.decode(npub); if (decoded.type === 'npub') { const repoOwnerPubkey = decoded.data as string; @@ -541,8 +574,37 @@ console.log('[Repo Images] Loaded banner from pageData:', repoBanner); } - // Also fetch from announcement directly as fallback + // Also fetch from announcement directly as fallback (only if not private or user has access) if (!repoImage && !repoBanner) { + const data = $page.data as typeof pageData; + // Check access for private repos + if (data.repoIsPrivate) { + const headers: Record = {}; + if (userPubkey) { + try { + const decoded = nip19.decode(userPubkey); + if (decoded.type === 'npub') { + headers['X-User-Pubkey'] = decoded.data as string; + } else { + headers['X-User-Pubkey'] = userPubkey; + } + } catch { + headers['X-User-Pubkey'] = userPubkey; + } + } + + const accessResponse = await fetch(`/api/repos/${npub}/${repo}/access`, { headers }); + if (!accessResponse.ok) { + // Access check failed, don't fetch images + return; + } + const accessData = await accessResponse.json(); + if (!accessData.canView) { + // User doesn't have access, don't fetch images + return; + } + } + const decoded = nip19.decode(npub); if (decoded.type === 'npub') { const repoOwnerPubkey = decoded.data as string; diff --git a/src/routes/repos/[npub]/[repo]/+page.ts b/src/routes/repos/[npub]/[repo]/+page.ts index 3f35814..0e3bd5f 100644 --- a/src/routes/repos/[npub]/[repo]/+page.ts +++ b/src/routes/repos/[npub]/[repo]/+page.ts @@ -93,10 +93,6 @@ export const load: PageLoad = async ({ params, url, parent }) => { .map(t => t[1]) .filter(t => t && typeof t === 'string') as string[]; const website = announcement.tags.find(t => t[0] === 'website')?.[1]; - const isPrivate = announcement.tags.some(t => - (t[0] === 'private' && t[1] === 'true') || - (t[0] === 't' && t[1] === 'private') - ); // Get git domain for constructing URLs const layoutData = await parent(); diff --git a/src/routes/signup/+page.svelte b/src/routes/signup/+page.svelte index ae1747c..9d4de3e 100644 --- a/src/routes/signup/+page.svelte +++ b/src/routes/signup/+page.svelte @@ -434,11 +434,76 @@ ]); const searchLower = query.toLowerCase(); - events = repoEvents.filter(event => { + let filteredEvents = repoEvents.filter(event => { const name = event.tags.find(t => t[0] === 'name')?.[1] || ''; const dTag = event.tags.find(t => t[0] === 'd')?.[1] || ''; return name.toLowerCase().includes(searchLower) || dTag.toLowerCase().includes(searchLower); }); + + // Filter out private repos unless user is authenticated and has access + // For signup page, we'll only show public repos or repos the user owns + let userPubkeyHex: string | null = null; + if (nip07Available) { + try { + const userPubkey = await getPublicKeyWithNIP07(); + try { + const decoded = nip19.decode(userPubkey); + if (decoded.type === 'npub') { + userPubkeyHex = decoded.data as string; + } else { + userPubkeyHex = userPubkey; + } + } catch { + userPubkeyHex = userPubkey; + } + } catch { + // User not authenticated, continue with filtering + } + } + + // Filter private repos + events = await Promise.all( + filteredEvents.map(async (event) => { + const isPrivate = event.tags.some(t => + (t[0] === 'private' && t[1] === 'true') || + (t[0] === 't' && t[1] === 'private') + ); + + // Public repos are always visible + if (!isPrivate) return event; + + // Private repos: only show if user is owner + if (userPubkeyHex && event.pubkey === userPubkeyHex) { + return event; + } + + // For other private repos, check access via API + if (userPubkeyHex) { + try { + const dTag = event.tags.find(t => t[0] === 'd')?.[1]; + if (!dTag) return null; + + // Get npub from pubkey + const ownerNpub = nip19.npubEncode(event.pubkey); + const accessResponse = await fetch(`/api/repos/${ownerNpub}/${dTag}/access`, { + headers: { 'X-User-Pubkey': userPubkeyHex } + }); + + if (accessResponse.ok) { + const accessData = await accessResponse.json(); + if (accessData.canView) { + return event; + } + } + } catch { + // Access check failed, don't show + } + } + + return null; + }) + ); + events = events.filter(e => e !== null) as NostrEvent[]; } if (events.length === 0) {