git-daemon 0.1.1 → 0.1.2

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/dist/deps.js ADDED
@@ -0,0 +1,101 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.installDeps = void 0;
7
+ const path_1 = __importDefault(require("path"));
8
+ const fs_1 = require("fs");
9
+ const process_1 = require("./process");
10
+ const workspace_1 = require("./workspace");
11
+ const tools_1 = require("./tools");
12
+ const installDeps = async (ctx, workspaceRoot, request) => {
13
+ const repoPath = await (0, workspace_1.resolveInsideWorkspace)(workspaceRoot, request.repoPath);
14
+ await fs_1.promises.access(path_1.default.join(repoPath, "package.json"));
15
+ const manager = await selectManager(repoPath, request.manager);
16
+ const { command, args } = await buildInstallCommand(repoPath, manager, request.mode, request.safer);
17
+ ctx.progress({ kind: "deps", detail: `${command} ${args.join(" ")}` });
18
+ await (0, process_1.runCommand)(ctx, command, args, { cwd: repoPath });
19
+ };
20
+ exports.installDeps = installDeps;
21
+ const selectManager = async (repoPath, requested) => {
22
+ if (requested !== "auto") {
23
+ const installed = await (0, tools_1.isToolInstalled)(requested);
24
+ if (!installed) {
25
+ throw new Error(`${requested} is not installed.`);
26
+ }
27
+ return requested;
28
+ }
29
+ const packageManager = await readPackageManager(repoPath);
30
+ if (packageManager) {
31
+ const name = packageManager.split("@")[0];
32
+ if (name === "pnpm" || name === "yarn" || name === "npm") {
33
+ const installed = await (0, tools_1.isToolInstalled)(name);
34
+ if (installed) {
35
+ return name;
36
+ }
37
+ }
38
+ }
39
+ if (await fileExists(path_1.default.join(repoPath, "pnpm-lock.yaml"))) {
40
+ return "pnpm";
41
+ }
42
+ if (await fileExists(path_1.default.join(repoPath, "yarn.lock"))) {
43
+ return "yarn";
44
+ }
45
+ if (await fileExists(path_1.default.join(repoPath, "package-lock.json"))) {
46
+ return "npm";
47
+ }
48
+ return "npm";
49
+ };
50
+ const readPackageManager = async (repoPath) => {
51
+ try {
52
+ const raw = await fs_1.promises.readFile(path_1.default.join(repoPath, "package.json"), "utf8");
53
+ const parsed = JSON.parse(raw);
54
+ return parsed.packageManager;
55
+ }
56
+ catch {
57
+ return null;
58
+ }
59
+ };
60
+ const buildInstallCommand = async (repoPath, manager, mode, safer) => {
61
+ const lockfileExists = await hasAnyLockfile(repoPath);
62
+ const useCi = mode === "ci" || (mode === "auto" && lockfileExists);
63
+ if (manager === "pnpm") {
64
+ const args = ["install"];
65
+ if (useCi) {
66
+ args.push("--frozen-lockfile");
67
+ }
68
+ if (safer) {
69
+ args.push("--ignore-scripts");
70
+ }
71
+ return { command: "pnpm", args };
72
+ }
73
+ if (manager === "yarn") {
74
+ const args = ["install"];
75
+ const isBerry = await fileExists(path_1.default.join(repoPath, ".yarnrc.yml"));
76
+ if (useCi || isBerry) {
77
+ args.push("--immutable");
78
+ }
79
+ if (safer) {
80
+ args.push("--ignore-scripts");
81
+ }
82
+ return { command: "yarn", args };
83
+ }
84
+ const args = [useCi ? "ci" : "install"];
85
+ if (safer) {
86
+ args.push("--ignore-scripts");
87
+ }
88
+ return { command: "npm", args };
89
+ };
90
+ const hasAnyLockfile = async (repoPath) => (await fileExists(path_1.default.join(repoPath, "pnpm-lock.yaml"))) ||
91
+ (await fileExists(path_1.default.join(repoPath, "yarn.lock"))) ||
92
+ (await fileExists(path_1.default.join(repoPath, "package-lock.json")));
93
+ const fileExists = async (target) => {
94
+ try {
95
+ await fs_1.promises.access(target);
96
+ return true;
97
+ }
98
+ catch {
99
+ return false;
100
+ }
101
+ };
package/dist/errors.js ADDED
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.internalError = exports.timeoutError = exports.pathNotFound = exports.repoNotFound = exports.jobNotFound = exports.capabilityNotGranted = exports.invalidRepoUrl = exports.pathOutsideWorkspace = exports.workspaceRequired = exports.rateLimited = exports.originNotAllowed = exports.authInvalid = exports.authRequired = exports.errorBody = exports.ApiError = void 0;
4
+ class ApiError extends Error {
5
+ constructor(status, body) {
6
+ super(body.message);
7
+ this.status = status;
8
+ this.body = body;
9
+ }
10
+ }
11
+ exports.ApiError = ApiError;
12
+ const errorBody = (errorCode, message, details) => ({
13
+ errorCode,
14
+ message,
15
+ ...(details ? { details } : {}),
16
+ });
17
+ exports.errorBody = errorBody;
18
+ const authRequired = () => new ApiError(401, (0, exports.errorBody)("auth_required", "Bearer token required."));
19
+ exports.authRequired = authRequired;
20
+ const authInvalid = () => new ApiError(401, (0, exports.errorBody)("auth_invalid", "Bearer token invalid or expired."));
21
+ exports.authInvalid = authInvalid;
22
+ const originNotAllowed = () => new ApiError(403, (0, exports.errorBody)("origin_not_allowed", "Origin not allowed."));
23
+ exports.originNotAllowed = originNotAllowed;
24
+ const rateLimited = () => new ApiError(429, (0, exports.errorBody)("rate_limited", "Too many requests."));
25
+ exports.rateLimited = rateLimited;
26
+ const workspaceRequired = () => new ApiError(409, (0, exports.errorBody)("workspace_required", "Workspace root not configured."));
27
+ exports.workspaceRequired = workspaceRequired;
28
+ const pathOutsideWorkspace = () => new ApiError(409, (0, exports.errorBody)("path_outside_workspace", "Path is outside the workspace root."));
29
+ exports.pathOutsideWorkspace = pathOutsideWorkspace;
30
+ const invalidRepoUrl = () => new ApiError(422, (0, exports.errorBody)("invalid_repo_url", "Repository URL is invalid."));
31
+ exports.invalidRepoUrl = invalidRepoUrl;
32
+ const capabilityNotGranted = () => new ApiError(409, (0, exports.errorBody)("capability_not_granted", "Capability approval required."));
33
+ exports.capabilityNotGranted = capabilityNotGranted;
34
+ const jobNotFound = () => new ApiError(404, (0, exports.errorBody)("job_not_found", "Job not found."));
35
+ exports.jobNotFound = jobNotFound;
36
+ const repoNotFound = () => new ApiError(404, (0, exports.errorBody)("internal_error", "Repository not found."));
37
+ exports.repoNotFound = repoNotFound;
38
+ const pathNotFound = () => new ApiError(404, (0, exports.errorBody)("internal_error", "Path not found."));
39
+ exports.pathNotFound = pathNotFound;
40
+ const timeoutError = () => new ApiError(500, (0, exports.errorBody)("timeout", "Job timed out."));
41
+ exports.timeoutError = timeoutError;
42
+ const internalError = (message = "Unexpected error.") => new ApiError(500, (0, exports.errorBody)("internal_error", message));
43
+ exports.internalError = internalError;
package/dist/git.js ADDED
@@ -0,0 +1,156 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.resolveRepoPath = exports.getRepoStatus = exports.fetchRepo = exports.cloneRepo = exports.RepoNotFoundError = void 0;
40
+ const path_1 = __importDefault(require("path"));
41
+ const fs_1 = require("fs");
42
+ const process_1 = require("./process");
43
+ const workspace_1 = require("./workspace");
44
+ class RepoNotFoundError extends Error {
45
+ }
46
+ exports.RepoNotFoundError = RepoNotFoundError;
47
+ const cloneRepo = async (ctx, workspaceRoot, repoUrl, destRelative, options) => {
48
+ (0, workspace_1.ensureRelative)(destRelative);
49
+ const destPath = await (0, workspace_1.resolveInsideWorkspace)(workspaceRoot, destRelative, true);
50
+ const args = ["clone", repoUrl, destPath];
51
+ if (options?.branch) {
52
+ args.splice(1, 0, "--branch", options.branch);
53
+ }
54
+ if (options?.depth) {
55
+ args.splice(1, 0, "--depth", options.depth.toString());
56
+ }
57
+ await (0, process_1.runCommand)(ctx, "git", args, { cwd: workspaceRoot });
58
+ };
59
+ exports.cloneRepo = cloneRepo;
60
+ const fetchRepo = async (ctx, workspaceRoot, repoPath, remote = "origin", prune = false) => {
61
+ const resolved = await (0, exports.resolveRepoPath)(workspaceRoot, repoPath);
62
+ const args = ["-C", resolved, "fetch", remote];
63
+ if (prune) {
64
+ args.push("--prune");
65
+ }
66
+ await (0, process_1.runCommand)(ctx, "git", args);
67
+ };
68
+ exports.fetchRepo = fetchRepo;
69
+ const getRepoStatus = async (workspaceRoot, repoPath) => {
70
+ const resolved = await (0, exports.resolveRepoPath)(workspaceRoot, repoPath);
71
+ const { execa } = await Promise.resolve().then(() => __importStar(require("execa")));
72
+ const result = await execa("git", [
73
+ "-C",
74
+ resolved,
75
+ "status",
76
+ "--porcelain=2",
77
+ "-b",
78
+ ]);
79
+ return parseStatus(result.stdout);
80
+ };
81
+ exports.getRepoStatus = getRepoStatus;
82
+ const resolveRepoPath = async (workspaceRoot, repoPath) => {
83
+ const resolved = await (0, workspace_1.resolveInsideWorkspace)(workspaceRoot, repoPath);
84
+ await assertRepoExists(resolved);
85
+ return resolved;
86
+ };
87
+ exports.resolveRepoPath = resolveRepoPath;
88
+ const assertRepoExists = async (repoPath) => {
89
+ const stats = await fs_1.promises.stat(repoPath);
90
+ if (!stats.isDirectory()) {
91
+ throw new RepoNotFoundError("Repository path is not a directory.");
92
+ }
93
+ const gitPath = path_1.default.join(repoPath, ".git");
94
+ try {
95
+ await fs_1.promises.access(gitPath);
96
+ }
97
+ catch {
98
+ throw new RepoNotFoundError("Repository .git directory not found.");
99
+ }
100
+ };
101
+ const parseStatus = (output) => {
102
+ let branch = "";
103
+ let ahead = 0;
104
+ let behind = 0;
105
+ let stagedCount = 0;
106
+ let unstagedCount = 0;
107
+ let untrackedCount = 0;
108
+ let conflictsCount = 0;
109
+ const lines = output.split(/\r?\n/);
110
+ for (const line of lines) {
111
+ if (line.startsWith("# branch.head")) {
112
+ branch = line.split(" ").slice(2).join(" ").trim();
113
+ continue;
114
+ }
115
+ if (line.startsWith("# branch.ab")) {
116
+ const parts = line.split(" ");
117
+ const aheadPart = parts.find((part) => part.startsWith("+"));
118
+ const behindPart = parts.find((part) => part.startsWith("-"));
119
+ ahead = aheadPart ? Number(aheadPart.slice(1)) : 0;
120
+ behind = behindPart ? Number(behindPart.slice(1)) : 0;
121
+ continue;
122
+ }
123
+ if (line.startsWith("?")) {
124
+ untrackedCount += 1;
125
+ continue;
126
+ }
127
+ if (line.startsWith("u")) {
128
+ conflictsCount += 1;
129
+ continue;
130
+ }
131
+ if (line.startsWith("1 ") || line.startsWith("2 ")) {
132
+ const x = line[2];
133
+ const y = line[3];
134
+ if (x && x !== ".") {
135
+ stagedCount += 1;
136
+ }
137
+ if (y && y !== ".") {
138
+ unstagedCount += 1;
139
+ }
140
+ }
141
+ }
142
+ const clean = stagedCount === 0 &&
143
+ unstagedCount === 0 &&
144
+ untrackedCount === 0 &&
145
+ conflictsCount === 0;
146
+ return {
147
+ branch,
148
+ ahead,
149
+ behind,
150
+ stagedCount,
151
+ unstagedCount,
152
+ untrackedCount,
153
+ conflictsCount,
154
+ clean,
155
+ };
156
+ };
package/dist/jobs.js ADDED
@@ -0,0 +1,163 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.JobManager = exports.Job = void 0;
7
+ const events_1 = require("events");
8
+ const crypto_1 = __importDefault(require("crypto"));
9
+ const errors_1 = require("./errors");
10
+ const MAX_EVENTS = 2000;
11
+ class Job {
12
+ constructor() {
13
+ this.state = "queued";
14
+ this.createdAt = new Date().toISOString();
15
+ this.events = [];
16
+ this.emitter = new events_1.EventEmitter();
17
+ this.cancelRequested = false;
18
+ this.id = crypto_1.default.randomUUID();
19
+ }
20
+ setCancel(fn) {
21
+ this.cancelFn = fn;
22
+ }
23
+ async cancel() {
24
+ this.cancelRequested = true;
25
+ if (this.cancelFn) {
26
+ await this.cancelFn();
27
+ }
28
+ }
29
+ emit(event) {
30
+ this.events.push(event);
31
+ if (this.events.length > MAX_EVENTS) {
32
+ this.events.shift();
33
+ }
34
+ this.emitter.emit("event", event);
35
+ }
36
+ snapshot() {
37
+ return {
38
+ id: this.id,
39
+ state: this.state,
40
+ createdAt: this.createdAt,
41
+ startedAt: this.startedAt,
42
+ finishedAt: this.finishedAt,
43
+ error: this.error,
44
+ };
45
+ }
46
+ }
47
+ exports.Job = Job;
48
+ class JobManager {
49
+ constructor(maxConcurrent, timeoutSeconds) {
50
+ this.running = 0;
51
+ this.queue = [];
52
+ this.jobs = new Map();
53
+ this.history = [];
54
+ this.maxConcurrent = maxConcurrent;
55
+ this.timeoutMs = timeoutSeconds * 1000;
56
+ }
57
+ enqueue(run) {
58
+ const job = new Job();
59
+ this.jobs.set(job.id, job);
60
+ this.queue.push({ job, run });
61
+ this.track(job);
62
+ this.drain();
63
+ return job;
64
+ }
65
+ get(id) {
66
+ return this.jobs.get(id);
67
+ }
68
+ cancel(id) {
69
+ const queuedIndex = this.queue.findIndex((entry) => entry.job.id === id);
70
+ if (queuedIndex >= 0) {
71
+ const [entry] = this.queue.splice(queuedIndex, 1);
72
+ entry.job.state = "cancelled";
73
+ entry.job.finishedAt = new Date().toISOString();
74
+ entry.job.emit({ type: "state", state: "cancelled" });
75
+ return true;
76
+ }
77
+ const runningJob = this.jobs.get(id);
78
+ if (!runningJob) {
79
+ return false;
80
+ }
81
+ if (runningJob.state !== "running") {
82
+ return false;
83
+ }
84
+ void runningJob.cancel();
85
+ runningJob.state = "cancelled";
86
+ runningJob.finishedAt = new Date().toISOString();
87
+ runningJob.emit({ type: "state", state: "cancelled" });
88
+ return true;
89
+ }
90
+ listRecent() {
91
+ return this.history.map((job) => job.snapshot());
92
+ }
93
+ track(job) {
94
+ this.history.push(job);
95
+ if (this.history.length > 100) {
96
+ this.history.shift();
97
+ }
98
+ }
99
+ drain() {
100
+ while (this.running < this.maxConcurrent && this.queue.length > 0) {
101
+ const entry = this.queue.shift();
102
+ if (!entry) {
103
+ return;
104
+ }
105
+ this.runJob(entry.job, entry.run);
106
+ }
107
+ }
108
+ runJob(job, run) {
109
+ this.running += 1;
110
+ job.state = "running";
111
+ job.startedAt = new Date().toISOString();
112
+ job.emit({ type: "state", state: "running" });
113
+ let timeoutHandle;
114
+ if (this.timeoutMs > 0) {
115
+ timeoutHandle = setTimeout(async () => {
116
+ if (job.state !== "running") {
117
+ return;
118
+ }
119
+ job.error = (0, errors_1.timeoutError)().body;
120
+ await job.cancel();
121
+ job.state = "error";
122
+ job.finishedAt = new Date().toISOString();
123
+ job.emit({ type: "state", state: "error", message: "Timed out" });
124
+ }, this.timeoutMs);
125
+ }
126
+ const ctx = {
127
+ logStdout: (line) => job.emit({ type: "log", stream: "stdout", line }),
128
+ logStderr: (line) => job.emit({ type: "log", stream: "stderr", line }),
129
+ progress: (event) => job.emit({ type: "progress", ...event }),
130
+ setCancel: (fn) => job.setCancel(fn),
131
+ isCancelled: () => job.cancelRequested,
132
+ };
133
+ run(ctx)
134
+ .then(() => {
135
+ if (job.state !== "running") {
136
+ return;
137
+ }
138
+ job.state = "done";
139
+ job.finishedAt = new Date().toISOString();
140
+ job.emit({ type: "state", state: "done" });
141
+ })
142
+ .catch((err) => {
143
+ if (job.state !== "running") {
144
+ return;
145
+ }
146
+ job.state = "error";
147
+ job.finishedAt = new Date().toISOString();
148
+ job.error = {
149
+ errorCode: "internal_error",
150
+ message: err instanceof Error ? err.message : "Job failed.",
151
+ };
152
+ job.emit({ type: "state", state: "error", message: job.error.message });
153
+ })
154
+ .finally(() => {
155
+ if (timeoutHandle) {
156
+ clearTimeout(timeoutHandle);
157
+ }
158
+ this.running -= 1;
159
+ this.drain();
160
+ });
161
+ }
162
+ }
163
+ exports.JobManager = JobManager;
package/dist/logger.js ADDED
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.createHttpLogger = exports.createLogger = void 0;
40
+ const path_1 = __importDefault(require("path"));
41
+ const fs_1 = require("fs");
42
+ const pino_1 = __importDefault(require("pino"));
43
+ const pino_http_1 = __importDefault(require("pino-http"));
44
+ const rotating_file_stream_1 = require("rotating-file-stream");
45
+ const createLogger = async (configDir, logging, enabled = true) => {
46
+ const level = process.env.GIT_DAEMON_LOG_LEVEL || "info";
47
+ const logToStdout = process.env.GIT_DAEMON_LOG_STDOUT === "1";
48
+ const prettyStdout = logToStdout && process.env.GIT_DAEMON_LOG_PRETTY !== "0";
49
+ const logDir = path_1.default.join(configDir, logging.directory);
50
+ await fs_1.promises.mkdir(logDir, { recursive: true });
51
+ const stream = (0, rotating_file_stream_1.createStream)("daemon.log", {
52
+ size: `${logging.maxBytes}B`,
53
+ maxFiles: logging.maxFiles,
54
+ path: logDir,
55
+ });
56
+ if (!logToStdout) {
57
+ return (0, pino_1.default)({ enabled, level }, stream);
58
+ }
59
+ const streams = [{ stream }];
60
+ if (prettyStdout) {
61
+ const { default: pretty } = await Promise.resolve().then(() => __importStar(require("pino-pretty")));
62
+ streams.push({
63
+ stream: pretty({
64
+ colorize: true,
65
+ translateTime: "SYS:standard",
66
+ ignore: "pid,hostname",
67
+ }),
68
+ });
69
+ }
70
+ else {
71
+ streams.push({ stream: process.stdout });
72
+ }
73
+ return (0, pino_1.default)({ enabled, level }, pino_1.default.multistream(streams));
74
+ };
75
+ exports.createLogger = createLogger;
76
+ const createHttpLogger = (logger) => (0, pino_http_1.default)({ logger: logger });
77
+ exports.createHttpLogger = createHttpLogger;
package/dist/os.js ADDED
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.openTarget = void 0;
4
+ const execa_1 = require("execa");
5
+ const openTarget = async (target, resolvedPath) => {
6
+ const platform = process.platform;
7
+ if (target === "folder") {
8
+ if (platform === "darwin") {
9
+ await (0, execa_1.execa)("open", [resolvedPath]);
10
+ return;
11
+ }
12
+ if (platform === "win32") {
13
+ await (0, execa_1.execa)("cmd", ["/c", "start", "", resolvedPath]);
14
+ return;
15
+ }
16
+ await (0, execa_1.execa)("xdg-open", [resolvedPath]);
17
+ return;
18
+ }
19
+ if (target === "terminal") {
20
+ if (platform === "darwin") {
21
+ await (0, execa_1.execa)("open", ["-a", "Terminal", resolvedPath]);
22
+ return;
23
+ }
24
+ if (platform === "win32") {
25
+ await (0, execa_1.execa)("cmd", [
26
+ "/c",
27
+ "start",
28
+ "",
29
+ "cmd.exe",
30
+ "/k",
31
+ "cd",
32
+ "/d",
33
+ resolvedPath,
34
+ ]);
35
+ return;
36
+ }
37
+ await (0, execa_1.execa)("x-terminal-emulator", ["--working-directory", resolvedPath]);
38
+ return;
39
+ }
40
+ await (0, execa_1.execa)("code", [resolvedPath]);
41
+ };
42
+ exports.openTarget = openTarget;
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.PairingManager = void 0;
7
+ const crypto_1 = __importDefault(require("crypto"));
8
+ const PAIRING_TTL_MS = 10 * 60 * 1000;
9
+ class PairingManager {
10
+ constructor(tokenStore, ttlDays) {
11
+ this.codes = new Map();
12
+ this.tokenStore = tokenStore;
13
+ this.ttlDays = ttlDays;
14
+ }
15
+ start(origin) {
16
+ const code = crypto_1.default.randomBytes(4).toString("hex");
17
+ const expiresAt = Date.now() + PAIRING_TTL_MS;
18
+ this.codes.set(origin, { code, expiresAt });
19
+ return {
20
+ step: "start",
21
+ instructions: "Enter this code in the Git Daemon pairing prompt within 10 minutes.",
22
+ code,
23
+ expiresAt: new Date(expiresAt).toISOString(),
24
+ };
25
+ }
26
+ async confirm(origin, code) {
27
+ const entry = this.codes.get(origin);
28
+ if (!entry || entry.code !== code || entry.expiresAt < Date.now()) {
29
+ return null;
30
+ }
31
+ this.codes.delete(origin);
32
+ const { token, expiresAt } = await this.tokenStore.issueToken(origin, this.ttlDays);
33
+ return {
34
+ step: "confirm",
35
+ accessToken: token,
36
+ tokenType: "Bearer",
37
+ expiresAt,
38
+ };
39
+ }
40
+ }
41
+ exports.PairingManager = PairingManager;
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.runCommand = void 0;
7
+ const execa_1 = require("execa");
8
+ const tree_kill_1 = __importDefault(require("tree-kill"));
9
+ const attachLineReader = (stream, onLine) => {
10
+ if (!stream) {
11
+ return;
12
+ }
13
+ let buffer = "";
14
+ stream.on("data", (chunk) => {
15
+ buffer += chunk.toString();
16
+ const lines = buffer.split(/\r?\n/);
17
+ buffer = lines.pop() ?? "";
18
+ for (const line of lines) {
19
+ if (line.length > 0) {
20
+ onLine(line);
21
+ }
22
+ }
23
+ });
24
+ stream.on("end", () => {
25
+ if (buffer.length > 0) {
26
+ onLine(buffer);
27
+ }
28
+ });
29
+ };
30
+ const runCommand = async (ctx, command, args, options) => {
31
+ const subprocess = (0, execa_1.execa)(command, args, {
32
+ ...options,
33
+ stdout: "pipe",
34
+ stderr: "pipe",
35
+ });
36
+ const pid = subprocess.pid;
37
+ if (pid) {
38
+ ctx.setCancel(() => new Promise((resolve) => {
39
+ (0, tree_kill_1.default)(pid, "SIGTERM", () => resolve());
40
+ }));
41
+ }
42
+ attachLineReader(subprocess.stdout, ctx.logStdout);
43
+ attachLineReader(subprocess.stderr, ctx.logStderr);
44
+ await subprocess;
45
+ };
46
+ exports.runCommand = runCommand;