git-daemon 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/.eslintrc.cjs ADDED
@@ -0,0 +1,18 @@
1
+ module.exports = {
2
+ root: true,
3
+ env: {
4
+ node: true,
5
+ es2020: true
6
+ },
7
+ parser: "@typescript-eslint/parser",
8
+ plugins: ["@typescript-eslint", "prettier"],
9
+ extends: [
10
+ "eslint:recommended",
11
+ "plugin:@typescript-eslint/recommended",
12
+ "plugin:prettier/recommended"
13
+ ],
14
+ rules: {
15
+ "@typescript-eslint/no-unused-vars": ["error", { argsIgnorePattern: "^_" }]
16
+ },
17
+ ignorePatterns: ["dist/", "node_modules/"]
18
+ };
package/README.md ADDED
@@ -0,0 +1,143 @@
1
+ # Git Daemon
2
+
3
+ ![Git Daemon logo](logo.png)
4
+
5
+ Git Daemon is a local Node.js service that exposes a small, authenticated HTTP API for a trusted web UI to perform Git and developer convenience actions on your machine. It is designed to run on `127.0.0.1` only, enforce a strict Origin allowlist, and sandbox all filesystem access to a configured workspace root.
6
+
7
+ ## What it does
8
+
9
+ - Clone, fetch, and read Git status using your system Git credentials
10
+ - Stream long-running job logs via Server-Sent Events (SSE)
11
+ - Open a repo in the OS file browser, terminal, or VS Code (with approvals)
12
+ - Install dependencies with safer defaults (`--ignore-scripts` by default)
13
+
14
+ ## Security model (high level)
15
+
16
+ - **Loopback-only**: binds to `127.0.0.1`
17
+ - **Origin allowlist**: every request must include a matching `Origin`
18
+ - **DNS rebinding protections**: verifies `Host` and remote loopback address
19
+ - **Pairing token**: required for all non-public endpoints
20
+ - **Workspace sandbox**: all paths must resolve inside the configured root
21
+ - **Capability approvals**: required for open-terminal/open-vscode/deps install
22
+
23
+ ## Requirements
24
+
25
+ - Node.js (for running the daemon)
26
+ - Git (for clone/fetch/status)
27
+ - Optional: `code` CLI for VS Code, `pnpm`/`yarn` for dependency installs
28
+
29
+ ## Install
30
+
31
+ ```bash
32
+ npm install
33
+ ```
34
+
35
+ ## Run the daemon
36
+
37
+ ```bash
38
+ npm run daemon
39
+ ```
40
+
41
+ The daemon listens on `http://127.0.0.1:8787` by default.
42
+
43
+ ## Pairing flow
44
+
45
+ Pairing is required before using protected endpoints.
46
+
47
+ 1. Start pairing:
48
+
49
+ ```bash
50
+ curl -H "Origin: https://app.example.com" \
51
+ -H "Content-Type: application/json" \
52
+ -d '{"step":"start"}' \
53
+ http://127.0.0.1:8787/v1/pair
54
+ ```
55
+
56
+ 2. Confirm pairing with the code:
57
+
58
+ ```bash
59
+ curl -H "Origin: https://app.example.com" \
60
+ -H "Content-Type: application/json" \
61
+ -d '{"step":"confirm","code":"<CODE>"}' \
62
+ http://127.0.0.1:8787/v1/pair
63
+ ```
64
+
65
+ The response includes `accessToken` to use as `Authorization: Bearer <token>`.
66
+
67
+ ## Example usage
68
+
69
+ Check meta:
70
+
71
+ ```bash
72
+ curl -H "Origin: https://app.example.com" \
73
+ http://127.0.0.1:8787/v1/meta
74
+ ```
75
+
76
+ Clone a repo (job):
77
+
78
+ ```bash
79
+ curl -X POST \
80
+ -H "Origin: https://app.example.com" \
81
+ -H "Authorization: Bearer <TOKEN>" \
82
+ -H "Content-Type: application/json" \
83
+ -d '{"repoUrl":"git@github.com:owner/repo.git","destRelative":"owner/repo"}' \
84
+ http://127.0.0.1:8787/v1/git/clone
85
+ ```
86
+
87
+ Stream job logs (SSE):
88
+
89
+ ```bash
90
+ curl -N \
91
+ -H "Origin: https://app.example.com" \
92
+ -H "Authorization: Bearer <TOKEN>" \
93
+ http://127.0.0.1:8787/v1/jobs/<JOB_ID>/stream
94
+ ```
95
+
96
+ ## Configuration
97
+
98
+ Config is stored in OS-specific directories:
99
+
100
+ - macOS: `~/Library/Application Support/Git Daemon`
101
+ - Linux: `~/.config/git-daemon`
102
+ - Windows: `%APPDATA%\\Git Daemon`
103
+
104
+ You can override the config directory with:
105
+
106
+ ```bash
107
+ GIT_DAEMON_CONFIG_DIR=/path/to/config npm run daemon
108
+ ```
109
+
110
+ Key settings live in `config.json`:
111
+
112
+ - `originAllowlist`: array of allowed UI origins
113
+ - `workspaceRoot`: absolute path to the workspace root
114
+ - `deps.defaultSafer`: defaults to `true` for `--ignore-scripts`
115
+ - `jobs.maxConcurrent` and `jobs.timeoutSeconds`
116
+
117
+ Tokens are stored (hashed) in `tokens.json`. Logs are written under the configured `logging.directory` with rotation.
118
+
119
+ ## Development
120
+
121
+ Run tests:
122
+
123
+ ```bash
124
+ npm test
125
+ ```
126
+
127
+ Lint:
128
+
129
+ ```bash
130
+ npm run lint
131
+ ```
132
+
133
+ ## API reference
134
+
135
+ See `openapi.yaml` for the full contract.
136
+
137
+ ## UI developer resources
138
+
139
+ This repo already includes the artifacts needed to build or test a UI client:
140
+
141
+ - `openapi.yaml`: full HTTP contract (routes, schemas, error codes).
142
+ - `design.md`: security model, runtime decisions, and behavior expectations.
143
+ - `config.schema.json`: shape of the daemon config (useful for tooling or UI settings screens).
@@ -0,0 +1,180 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://example.com/schemas/git-daemon-config.schema.json",
4
+ "title": "Git Daemon Config",
5
+ "type": "object",
6
+ "additionalProperties": false,
7
+ "required": [
8
+ "configVersion",
9
+ "server",
10
+ "originAllowlist",
11
+ "logging",
12
+ "jobs",
13
+ "deps",
14
+ "pairing",
15
+ "approvals"
16
+ ],
17
+ "properties": {
18
+ "configVersion": {
19
+ "type": "integer",
20
+ "minimum": 1
21
+ },
22
+ "server": {
23
+ "type": "object",
24
+ "additionalProperties": false,
25
+ "required": [
26
+ "host",
27
+ "port"
28
+ ],
29
+ "properties": {
30
+ "host": {
31
+ "type": "string",
32
+ "default": "127.0.0.1"
33
+ },
34
+ "port": {
35
+ "type": "integer",
36
+ "minimum": 1,
37
+ "maximum": 65535,
38
+ "default": 8787
39
+ }
40
+ }
41
+ },
42
+ "originAllowlist": {
43
+ "type": "array",
44
+ "minItems": 1,
45
+ "items": {
46
+ "type": "string",
47
+ "format": "uri"
48
+ }
49
+ },
50
+ "workspaceRoot": {
51
+ "type": [
52
+ "string",
53
+ "null"
54
+ ],
55
+ "description": "Absolute path to the workspace root. Null means not yet configured."
56
+ },
57
+ "pairing": {
58
+ "type": "object",
59
+ "additionalProperties": false,
60
+ "required": [
61
+ "tokenTtlDays"
62
+ ],
63
+ "properties": {
64
+ "tokenTtlDays": {
65
+ "type": "integer",
66
+ "minimum": 1,
67
+ "maximum": 365,
68
+ "default": 30
69
+ }
70
+ }
71
+ },
72
+ "jobs": {
73
+ "type": "object",
74
+ "additionalProperties": false,
75
+ "required": [
76
+ "maxConcurrent",
77
+ "timeoutSeconds"
78
+ ],
79
+ "properties": {
80
+ "maxConcurrent": {
81
+ "type": "integer",
82
+ "minimum": 1,
83
+ "default": 1
84
+ },
85
+ "timeoutSeconds": {
86
+ "type": "integer",
87
+ "minimum": 60,
88
+ "default": 3600
89
+ }
90
+ }
91
+ },
92
+ "deps": {
93
+ "type": "object",
94
+ "additionalProperties": false,
95
+ "required": [
96
+ "defaultSafer"
97
+ ],
98
+ "properties": {
99
+ "defaultSafer": {
100
+ "type": "boolean",
101
+ "default": true
102
+ }
103
+ }
104
+ },
105
+ "logging": {
106
+ "type": "object",
107
+ "additionalProperties": false,
108
+ "required": [
109
+ "directory",
110
+ "maxFiles",
111
+ "maxBytes"
112
+ ],
113
+ "properties": {
114
+ "directory": {
115
+ "type": "string",
116
+ "default": "logs"
117
+ },
118
+ "maxFiles": {
119
+ "type": "integer",
120
+ "minimum": 1,
121
+ "default": 5
122
+ },
123
+ "maxBytes": {
124
+ "type": "integer",
125
+ "minimum": 1024,
126
+ "default": 5242880
127
+ }
128
+ }
129
+ },
130
+ "approvals": {
131
+ "type": "object",
132
+ "additionalProperties": false,
133
+ "required": [
134
+ "entries"
135
+ ],
136
+ "properties": {
137
+ "entries": {
138
+ "type": "array",
139
+ "default": [],
140
+ "items": {
141
+ "type": "object",
142
+ "additionalProperties": false,
143
+ "required": [
144
+ "origin",
145
+ "repoPath",
146
+ "capabilities",
147
+ "approvedAt"
148
+ ],
149
+ "properties": {
150
+ "origin": {
151
+ "type": "string",
152
+ "format": "uri"
153
+ },
154
+ "repoPath": {
155
+ "type": "string"
156
+ },
157
+ "capabilities": {
158
+ "type": "array",
159
+ "minItems": 1,
160
+ "uniqueItems": true,
161
+ "items": {
162
+ "type": "string",
163
+ "enum": [
164
+ "open-terminal",
165
+ "open-vscode",
166
+ "deps/install"
167
+ ]
168
+ }
169
+ },
170
+ "approvedAt": {
171
+ "type": "string",
172
+ "format": "date-time"
173
+ }
174
+ }
175
+ }
176
+ }
177
+ }
178
+ }
179
+ }
180
+ }