repoview 0.5.1 → 0.6.1
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/CHANGELOG.md +87 -0
- package/CONTRIBUTING.md +4 -3
- package/DEVELOPMENT.md +84 -16
- package/README.md +71 -5
- package/dist/api.js +58 -0
- package/dist/api.js.map +1 -0
- package/dist/cli.js +454 -0
- package/dist/cli.js.map +1 -0
- package/dist/csv.js +64 -0
- package/dist/csv.js.map +1 -0
- package/dist/format.js +25 -0
- package/dist/format.js.map +1 -0
- package/dist/gist-router.js +153 -0
- package/dist/gist-router.js.map +1 -0
- package/dist/gists.js +130 -0
- package/dist/gists.js.map +1 -0
- package/dist/git.js +67 -0
- package/dist/git.js.map +1 -0
- package/dist/gitignore.js +34 -0
- package/dist/gitignore.js.map +1 -0
- package/dist/linkcheck.js +310 -0
- package/dist/linkcheck.js.map +1 -0
- package/dist/markdown.js +493 -0
- package/dist/markdown.js.map +1 -0
- package/dist/net.js +10 -0
- package/dist/net.js.map +1 -0
- package/dist/paths.js +59 -0
- package/dist/paths.js.map +1 -0
- package/dist/reload.js +55 -0
- package/dist/reload.js.map +1 -0
- package/dist/repo-context.js +80 -0
- package/dist/repo-context.js.map +1 -0
- package/dist/repo-router.js +810 -0
- package/dist/repo-router.js.map +1 -0
- package/dist/review-cli.js +228 -0
- package/dist/review-cli.js.map +1 -0
- package/dist/server.js +122 -0
- package/dist/server.js.map +1 -0
- package/dist/session.js +86 -0
- package/dist/session.js.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/views.js +780 -0
- package/dist/views.js.map +1 -0
- package/package.json +20 -9
- package/public/app.css +113 -0
- package/public/app.js +26 -3
- package/public/gist.js +60 -0
- package/public/review.js +9 -6
- package/public/session.js +61 -0
- package/src/cli.js +0 -91
- package/src/gitignore.js +0 -34
- package/src/linkcheck.js +0 -312
- package/src/markdown.js +0 -518
- package/src/review-cli.js +0 -245
- package/src/server.js +0 -1126
- package/src/views.js +0 -657
package/dist/cli.js
ADDED
|
@@ -0,0 +1,454 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import process from "node:process";
|
|
4
|
+
import { startServer } from "./server.js";
|
|
5
|
+
import { handleReviewCommand } from "./review-cli.js";
|
|
6
|
+
function printHelp() {
|
|
7
|
+
// Keep this in sync with README.md
|
|
8
|
+
process.stdout.write(`repoview — browse local Git repos as a GitHub-like website, and publish
|
|
9
|
+
ephemeral file previews ("gists"). Built to be driven by humans and agents.
|
|
10
|
+
|
|
11
|
+
SESSION MODEL (like tmux)
|
|
12
|
+
Invocations on the same port share ONE session (daemon). The FIRST run starts
|
|
13
|
+
the daemon and KEEPS RUNNING in the foreground (it is the server). LATER runs
|
|
14
|
+
on that port just register their repo and exit 0 immediately. So you never have
|
|
15
|
+
to remember a port per repo. Each repo is served at /r/<id>/...
|
|
16
|
+
Default port: 7376. Use --port for independent sessions.
|
|
17
|
+
Agent tip: background the first run (e.g. \`repoview … &\` or nohup); once it
|
|
18
|
+
prints "listening:", the daemon is up and all other commands below will work.
|
|
19
|
+
|
|
20
|
+
START / JOIN A SESSION
|
|
21
|
+
repoview [--repo PATH] [--host HOST] [--port N] [--no-watch]
|
|
22
|
+
If no daemon is on --port: becomes the daemon (blocks/foreground).
|
|
23
|
+
If a daemon is already there: registers the repo, prints its URL, exits 0.
|
|
24
|
+
|
|
25
|
+
Options:
|
|
26
|
+
--repo <path> Repo root (default: $REPO_ROOT or current dir)
|
|
27
|
+
--host <host> Bind address (default: 0.0.0.0; use 127.0.0.1 for local-only)
|
|
28
|
+
--port <port> Session port (default: 7376)
|
|
29
|
+
--no-watch Disable live reload for this repo
|
|
30
|
+
-h, --help Show this help
|
|
31
|
+
|
|
32
|
+
MANAGE THE SESSION (require a running daemon on --port)
|
|
33
|
+
repoview ls List repos: "<id> <branch> <path>" + each URL
|
|
34
|
+
repoview rm <id|path> Unregister a repo
|
|
35
|
+
repoview stop Shut the session daemon down
|
|
36
|
+
|
|
37
|
+
GISTS (ephemeral file previews; default TTL 24h, gone on restart, editable)
|
|
38
|
+
Need a running daemon on --port (or --url for a remote server's API).
|
|
39
|
+
repoview gist <file> [--title "T"] [--ttl 24h] [--filename name.md] [--url URL]
|
|
40
|
+
Publish; prints ONE line: the URL.
|
|
41
|
+
cat report.md | repoview gist --filename report.md Publish from stdin
|
|
42
|
+
repoview gist edit <id> [file] [--title] [--filename] [--ttl] Update a gist
|
|
43
|
+
repoview gist delete <id> Delete a gist
|
|
44
|
+
repoview gist list List gists
|
|
45
|
+
--ttl accepts 30m/24h/7d/seconds (1m–7d). --title is the page/list label
|
|
46
|
+
only; the rendered H1 comes from the file's own first Markdown heading.
|
|
47
|
+
|
|
48
|
+
CODE REVIEW THREADS (pure filesystem, NO daemon — operate on a repo's .repoview/)
|
|
49
|
+
Add --repo <path> to EVERY review command (default: $REPO_ROOT or cwd — NOT the
|
|
50
|
+
session's served repo). --port/--host are ignored here.
|
|
51
|
+
repoview review new --repo R --title "Title" Create (prints id)
|
|
52
|
+
repoview review post --repo R <id> --role agent --body "…" Post a message
|
|
53
|
+
repoview review post --repo R <id> --role agent --file F Post from file/stdin
|
|
54
|
+
repoview review read --repo R <id> Print thread JSON
|
|
55
|
+
repoview review list --repo R List threads (JSON)
|
|
56
|
+
|
|
57
|
+
HTTP API (for agents / remote use — base = http://<host>:<port>)
|
|
58
|
+
GET /api/session {app, version, repos:[{id,name,path,branch}]}
|
|
59
|
+
GET /api/repos {repos:[…]}
|
|
60
|
+
POST /api/repos {path, watch?} → {id, url} (localhost only)
|
|
61
|
+
DELETE /api/repos/:id → {ok} (localhost only)
|
|
62
|
+
POST /api/shutdown → {ok} (localhost only)
|
|
63
|
+
GET /api/gists {gists:[{id,filename,title,url,expiresAt}]}
|
|
64
|
+
POST /api/gists {content, filename?, title?, ttlSeconds?}
|
|
65
|
+
→ {id, url, rawUrl, expiresAt}
|
|
66
|
+
PATCH /api/gists/:id {content?, filename?, title?, ttlSeconds?} → gist
|
|
67
|
+
DELETE /api/gists/:id → {ok}
|
|
68
|
+
Examples:
|
|
69
|
+
curl -s $BASE/api/session
|
|
70
|
+
curl -s -X POST $BASE/api/gists -H 'content-type: application/json' \\
|
|
71
|
+
-d '{"content":"# Hi","filename":"hi.md","ttlSeconds":3600}'
|
|
72
|
+
|
|
73
|
+
PAGES
|
|
74
|
+
/ → default repo /session manage repos (add/remove)
|
|
75
|
+
/r/<id>/tree/ browse a repo /gists list of active gists
|
|
76
|
+
/r/<id>/diff working-tree diff /gist/<id> a gist preview (+ /raw)
|
|
77
|
+
/r/<id>/review/ review threads
|
|
78
|
+
|
|
79
|
+
ENVIRONMENT
|
|
80
|
+
REPO_ROOT Default repo when --repo is omitted
|
|
81
|
+
HOST, PORT Default bind host / session port
|
|
82
|
+
REPOVIEW_BASE_URL Absolute origin used in returned gist URLs. Read by the
|
|
83
|
+
SERVER/daemon at request time — set it when STARTING the
|
|
84
|
+
daemon, not on the gist client. Falls back to the request
|
|
85
|
+
Host header. (e.g. when the server runs remotely)
|
|
86
|
+
`);
|
|
87
|
+
}
|
|
88
|
+
function parseArgs(argv) {
|
|
89
|
+
const args = { watch: true };
|
|
90
|
+
const rest = [];
|
|
91
|
+
for (let i = 0; i < argv.length; i++) {
|
|
92
|
+
const value = argv[i];
|
|
93
|
+
if (value === "-h" || value === "--help")
|
|
94
|
+
args.help = true;
|
|
95
|
+
if (value === "--watch")
|
|
96
|
+
args.watch = true;
|
|
97
|
+
else if (value === "--no-watch")
|
|
98
|
+
args.watch = false;
|
|
99
|
+
else if (value === "--repo")
|
|
100
|
+
args.repo = argv[++i];
|
|
101
|
+
else if (value === "--port")
|
|
102
|
+
args.port = Number(argv[++i]);
|
|
103
|
+
else if (value === "--host")
|
|
104
|
+
args.host = argv[++i];
|
|
105
|
+
else
|
|
106
|
+
rest.push(value);
|
|
107
|
+
}
|
|
108
|
+
return { ...args, rest };
|
|
109
|
+
}
|
|
110
|
+
/** Address to connect to when joining a local daemon (0.0.0.0 isn't routable). */
|
|
111
|
+
function connectHost(host) {
|
|
112
|
+
if (host === "0.0.0.0" || host === "::" || host === "")
|
|
113
|
+
return "127.0.0.1";
|
|
114
|
+
return host;
|
|
115
|
+
}
|
|
116
|
+
async function fetchJson(url, init) {
|
|
117
|
+
try {
|
|
118
|
+
const res = await fetch(url, init);
|
|
119
|
+
if (!res.ok) {
|
|
120
|
+
const body = (await res.json().catch(() => ({})));
|
|
121
|
+
throw new Error(body.error || `HTTP ${res.status}`);
|
|
122
|
+
}
|
|
123
|
+
return await res.json();
|
|
124
|
+
}
|
|
125
|
+
catch (e) {
|
|
126
|
+
if (e instanceof Error && /HTTP \d|error/i.test(e.message) && !/fetch failed|ECONNREFUSED/i.test(e.message)) {
|
|
127
|
+
throw e;
|
|
128
|
+
}
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
async function probeSession(base) {
|
|
133
|
+
return (await fetchJson(`${base}/api/session`));
|
|
134
|
+
}
|
|
135
|
+
async function registerRepo(base, repoRoot, watch) {
|
|
136
|
+
const result = await fetchJson(`${base}/api/repos`, {
|
|
137
|
+
method: "POST",
|
|
138
|
+
headers: { "Content-Type": "application/json" },
|
|
139
|
+
body: JSON.stringify({ path: repoRoot, watch }),
|
|
140
|
+
});
|
|
141
|
+
if (!result)
|
|
142
|
+
throw new Error("Failed to register repo with the session");
|
|
143
|
+
return result;
|
|
144
|
+
}
|
|
145
|
+
function printRepoTable(repos, port, host) {
|
|
146
|
+
if (!repos.length) {
|
|
147
|
+
process.stdout.write("(no repos registered)\n");
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
const open = connectHost(host);
|
|
151
|
+
for (const r of repos) {
|
|
152
|
+
process.stdout.write(`${r.id.padEnd(20)} ${(r.branch || "no-git").padEnd(16)} ${r.path}\n` +
|
|
153
|
+
`${" ".repeat(20)} http://${open}:${port}/r/${r.id}/tree/\n`);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
async function runSubcommand(sub, args, base, port, host) {
|
|
157
|
+
if (sub === "ls") {
|
|
158
|
+
const info = await probeSession(base);
|
|
159
|
+
if (!info) {
|
|
160
|
+
process.stderr.write(`No repoview session on ${base}\n`);
|
|
161
|
+
return 1;
|
|
162
|
+
}
|
|
163
|
+
printRepoTable(info.repos || [], port, host);
|
|
164
|
+
return 0;
|
|
165
|
+
}
|
|
166
|
+
if (sub === "stop") {
|
|
167
|
+
const info = await probeSession(base);
|
|
168
|
+
if (!info) {
|
|
169
|
+
process.stderr.write(`No repoview session on ${base}\n`);
|
|
170
|
+
return 1;
|
|
171
|
+
}
|
|
172
|
+
await fetchJson(`${base}/api/shutdown`, { method: "POST" });
|
|
173
|
+
process.stdout.write(`Stopped session on port ${port}\n`);
|
|
174
|
+
return 0;
|
|
175
|
+
}
|
|
176
|
+
if (sub === "rm") {
|
|
177
|
+
const target = args.rest[1];
|
|
178
|
+
if (!target) {
|
|
179
|
+
process.stderr.write("Usage: repoview rm <id|path>\n");
|
|
180
|
+
return 1;
|
|
181
|
+
}
|
|
182
|
+
const info = await probeSession(base);
|
|
183
|
+
if (!info) {
|
|
184
|
+
process.stderr.write(`No repoview session on ${base}\n`);
|
|
185
|
+
return 1;
|
|
186
|
+
}
|
|
187
|
+
const repos = info.repos || [];
|
|
188
|
+
let real = target;
|
|
189
|
+
try {
|
|
190
|
+
real = path.resolve(target);
|
|
191
|
+
}
|
|
192
|
+
catch {
|
|
193
|
+
// keep as-is
|
|
194
|
+
}
|
|
195
|
+
const match = repos.find((r) => r.id === target || r.path === real || r.path === target);
|
|
196
|
+
if (!match) {
|
|
197
|
+
process.stderr.write(`Repo not found in session: ${target}\n`);
|
|
198
|
+
return 1;
|
|
199
|
+
}
|
|
200
|
+
const res = await fetchJson(`${base}/api/repos/${encodeURIComponent(match.id)}`, {
|
|
201
|
+
method: "DELETE",
|
|
202
|
+
});
|
|
203
|
+
if (!res) {
|
|
204
|
+
process.stderr.write(`Failed to remove ${match.id}\n`);
|
|
205
|
+
return 1;
|
|
206
|
+
}
|
|
207
|
+
process.stdout.write(`Removed ${match.id}\n`);
|
|
208
|
+
return 0;
|
|
209
|
+
}
|
|
210
|
+
process.stderr.write(`Unknown command: ${sub}\n`);
|
|
211
|
+
printHelp();
|
|
212
|
+
return 1;
|
|
213
|
+
}
|
|
214
|
+
/** Parse "24h" / "30m" / "7d" / "3600" into seconds. */
|
|
215
|
+
function parseDuration(text) {
|
|
216
|
+
const m = String(text).trim().match(/^(\d+)\s*([smhd]?)$/i);
|
|
217
|
+
if (!m)
|
|
218
|
+
return undefined;
|
|
219
|
+
const n = Number(m[1]);
|
|
220
|
+
const unit = m[2].toLowerCase();
|
|
221
|
+
const mult = unit === "d" ? 86400 : unit === "h" ? 3600 : unit === "m" ? 60 : 1;
|
|
222
|
+
return n * mult;
|
|
223
|
+
}
|
|
224
|
+
function parseGistArgs(args) {
|
|
225
|
+
const flags = {};
|
|
226
|
+
const positional = [];
|
|
227
|
+
for (let i = 0; i < args.length; i++) {
|
|
228
|
+
const v = args[i];
|
|
229
|
+
if (v === "--title")
|
|
230
|
+
flags.title = args[++i];
|
|
231
|
+
else if (v === "--ttl")
|
|
232
|
+
flags.ttl = args[++i];
|
|
233
|
+
else if (v === "--filename")
|
|
234
|
+
flags.filename = args[++i];
|
|
235
|
+
else if (v === "--url")
|
|
236
|
+
flags.url = args[++i];
|
|
237
|
+
else
|
|
238
|
+
positional.push(v);
|
|
239
|
+
}
|
|
240
|
+
return { flags, positional };
|
|
241
|
+
}
|
|
242
|
+
/** Read content from a file path, else stdin if piped, else undefined. */
|
|
243
|
+
async function readGistContent(file) {
|
|
244
|
+
if (file) {
|
|
245
|
+
const fs = await import("node:fs/promises");
|
|
246
|
+
return fs.readFile(file, "utf8");
|
|
247
|
+
}
|
|
248
|
+
if (!process.stdin.isTTY) {
|
|
249
|
+
const chunks = [];
|
|
250
|
+
for await (const chunk of process.stdin)
|
|
251
|
+
chunks.push(chunk);
|
|
252
|
+
return Buffer.concat(chunks).toString("utf8");
|
|
253
|
+
}
|
|
254
|
+
return undefined;
|
|
255
|
+
}
|
|
256
|
+
function ttlSecondsFrom(flags) {
|
|
257
|
+
if (!flags.ttl)
|
|
258
|
+
return undefined;
|
|
259
|
+
const s = parseDuration(flags.ttl);
|
|
260
|
+
if (s == null) {
|
|
261
|
+
process.stderr.write(`Invalid --ttl: ${flags.ttl} (use e.g. 30m, 24h, 7d)\n`);
|
|
262
|
+
return null; // signal error
|
|
263
|
+
}
|
|
264
|
+
return s;
|
|
265
|
+
}
|
|
266
|
+
function gistTarget(flags, localBase) {
|
|
267
|
+
return flags.url ? flags.url.replace(/\/+$/, "") : localBase;
|
|
268
|
+
}
|
|
269
|
+
function noSession(target) {
|
|
270
|
+
process.stderr.write(`No repoview session at ${target}. Start one with \`repoview\` first, or pass --url.\n`);
|
|
271
|
+
return 1;
|
|
272
|
+
}
|
|
273
|
+
async function runGist(restArgs, localBase) {
|
|
274
|
+
const sub = restArgs[0];
|
|
275
|
+
if (sub === "edit")
|
|
276
|
+
return runGistEdit(restArgs.slice(1), localBase);
|
|
277
|
+
if (sub === "delete" || sub === "rm")
|
|
278
|
+
return runGistDelete(restArgs.slice(1), localBase);
|
|
279
|
+
if (sub === "list" || sub === "ls")
|
|
280
|
+
return runGistList(restArgs.slice(1), localBase);
|
|
281
|
+
return runGistCreate(sub === "create" ? restArgs.slice(1) : restArgs, localBase);
|
|
282
|
+
}
|
|
283
|
+
async function runGistCreate(args, localBase) {
|
|
284
|
+
const { flags, positional } = parseGistArgs(args);
|
|
285
|
+
const file = positional[0];
|
|
286
|
+
const content = await readGistContent(file);
|
|
287
|
+
if (!content || !content.trim()) {
|
|
288
|
+
process.stderr.write("Error: no content (pass a file or pipe via stdin)\n");
|
|
289
|
+
return 1;
|
|
290
|
+
}
|
|
291
|
+
const ttlSeconds = ttlSecondsFrom(flags);
|
|
292
|
+
if (ttlSeconds === null)
|
|
293
|
+
return 1;
|
|
294
|
+
const filename = flags.filename || (file ? path.basename(file) : "gist.md");
|
|
295
|
+
const target = gistTarget(flags, localBase);
|
|
296
|
+
let result;
|
|
297
|
+
try {
|
|
298
|
+
result = (await fetchJson(`${target}/api/gists`, {
|
|
299
|
+
method: "POST",
|
|
300
|
+
headers: { "Content-Type": "application/json" },
|
|
301
|
+
body: JSON.stringify({ content, filename, title: flags.title, ttlSeconds }),
|
|
302
|
+
}));
|
|
303
|
+
}
|
|
304
|
+
catch (e) {
|
|
305
|
+
process.stderr.write(`Error: ${e.message}\n`);
|
|
306
|
+
return 1;
|
|
307
|
+
}
|
|
308
|
+
if (!result)
|
|
309
|
+
return noSession(target);
|
|
310
|
+
process.stdout.write(`${result.url}\n`);
|
|
311
|
+
return 0;
|
|
312
|
+
}
|
|
313
|
+
async function runGistEdit(args, localBase) {
|
|
314
|
+
const { flags, positional } = parseGistArgs(args);
|
|
315
|
+
const id = positional[0];
|
|
316
|
+
if (!id) {
|
|
317
|
+
process.stderr.write("Usage: repoview gist edit <id> [file] [--title] [--filename] [--ttl]\n");
|
|
318
|
+
return 1;
|
|
319
|
+
}
|
|
320
|
+
const content = await readGistContent(positional[1]);
|
|
321
|
+
const ttlSeconds = ttlSecondsFrom(flags);
|
|
322
|
+
if (ttlSeconds === null)
|
|
323
|
+
return 1;
|
|
324
|
+
const body = {};
|
|
325
|
+
if (content !== undefined)
|
|
326
|
+
body.content = content;
|
|
327
|
+
if (flags.filename !== undefined)
|
|
328
|
+
body.filename = flags.filename;
|
|
329
|
+
if (flags.title !== undefined)
|
|
330
|
+
body.title = flags.title;
|
|
331
|
+
if (ttlSeconds !== undefined)
|
|
332
|
+
body.ttlSeconds = ttlSeconds;
|
|
333
|
+
if (Object.keys(body).length === 0) {
|
|
334
|
+
process.stderr.write("Nothing to update (pass new content, --title, --filename, or --ttl)\n");
|
|
335
|
+
return 1;
|
|
336
|
+
}
|
|
337
|
+
const target = gistTarget(flags, localBase);
|
|
338
|
+
let result;
|
|
339
|
+
try {
|
|
340
|
+
result = (await fetchJson(`${target}/api/gists/${encodeURIComponent(id)}`, {
|
|
341
|
+
method: "PATCH",
|
|
342
|
+
headers: { "Content-Type": "application/json" },
|
|
343
|
+
body: JSON.stringify(body),
|
|
344
|
+
}));
|
|
345
|
+
}
|
|
346
|
+
catch (e) {
|
|
347
|
+
process.stderr.write(`Error: ${e.message}\n`);
|
|
348
|
+
return 1;
|
|
349
|
+
}
|
|
350
|
+
if (!result)
|
|
351
|
+
return noSession(target);
|
|
352
|
+
process.stdout.write(`${result.url}\n`);
|
|
353
|
+
return 0;
|
|
354
|
+
}
|
|
355
|
+
async function runGistDelete(args, localBase) {
|
|
356
|
+
const { flags, positional } = parseGistArgs(args);
|
|
357
|
+
const id = positional[0];
|
|
358
|
+
if (!id) {
|
|
359
|
+
process.stderr.write("Usage: repoview gist delete <id>\n");
|
|
360
|
+
return 1;
|
|
361
|
+
}
|
|
362
|
+
const target = gistTarget(flags, localBase);
|
|
363
|
+
try {
|
|
364
|
+
const result = await fetchJson(`${target}/api/gists/${encodeURIComponent(id)}`, {
|
|
365
|
+
method: "DELETE",
|
|
366
|
+
});
|
|
367
|
+
if (!result)
|
|
368
|
+
return noSession(target);
|
|
369
|
+
}
|
|
370
|
+
catch (e) {
|
|
371
|
+
process.stderr.write(`Error: ${e.message}\n`);
|
|
372
|
+
return 1;
|
|
373
|
+
}
|
|
374
|
+
process.stdout.write(`Deleted ${id}\n`);
|
|
375
|
+
return 0;
|
|
376
|
+
}
|
|
377
|
+
async function runGistList(args, localBase) {
|
|
378
|
+
const { flags } = parseGistArgs(args);
|
|
379
|
+
const target = gistTarget(flags, localBase);
|
|
380
|
+
const result = (await fetchJson(`${target}/api/gists`));
|
|
381
|
+
if (!result)
|
|
382
|
+
return noSession(target);
|
|
383
|
+
const gists = result.gists || [];
|
|
384
|
+
if (!gists.length) {
|
|
385
|
+
process.stdout.write("(no active gists)\n");
|
|
386
|
+
return 0;
|
|
387
|
+
}
|
|
388
|
+
for (const g of gists) {
|
|
389
|
+
process.stdout.write(`${g.id.padEnd(14)} ${(g.title || g.filename).padEnd(28)} ${g.url || ""}\n`);
|
|
390
|
+
}
|
|
391
|
+
return 0;
|
|
392
|
+
}
|
|
393
|
+
const parsed = parseArgs(process.argv.slice(2));
|
|
394
|
+
const { repo, port: portArg, host: hostArg, watch, help } = parsed;
|
|
395
|
+
if (help) {
|
|
396
|
+
printHelp();
|
|
397
|
+
process.exit(0);
|
|
398
|
+
}
|
|
399
|
+
// Review subcommand (pure filesystem, no daemon).
|
|
400
|
+
if (parsed.rest[0] === "review") {
|
|
401
|
+
const repoRootForReview = repo ?? process.env.REPO_ROOT ?? process.cwd();
|
|
402
|
+
await handleReviewCommand(parsed.rest.slice(1), repoRootForReview);
|
|
403
|
+
process.exit(0);
|
|
404
|
+
}
|
|
405
|
+
if (portArg != null && !Number.isFinite(portArg)) {
|
|
406
|
+
process.stderr.write("Invalid --port value\n");
|
|
407
|
+
process.exit(2);
|
|
408
|
+
}
|
|
409
|
+
const port = portArg || Number(process.env.PORT) || 7376;
|
|
410
|
+
const host = hostArg || process.env.HOST || "0.0.0.0";
|
|
411
|
+
const base = `http://${connectHost(host)}:${port}`;
|
|
412
|
+
// Session-management subcommands target the running daemon.
|
|
413
|
+
if (["ls", "rm", "stop"].includes(parsed.rest[0])) {
|
|
414
|
+
const code = await runSubcommand(parsed.rest[0], parsed, base, port, host);
|
|
415
|
+
process.exit(code);
|
|
416
|
+
}
|
|
417
|
+
// Publish an ephemeral gist to the session daemon.
|
|
418
|
+
if (parsed.rest[0] === "gist") {
|
|
419
|
+
const code = await runGist(parsed.rest.slice(1), base);
|
|
420
|
+
process.exit(code);
|
|
421
|
+
}
|
|
422
|
+
const repoRoot = repo ?? process.env.REPO_ROOT ?? process.cwd();
|
|
423
|
+
const repoRootAbs = path.resolve(repoRoot);
|
|
424
|
+
async function joinExisting() {
|
|
425
|
+
const info = await probeSession(base);
|
|
426
|
+
if (!info)
|
|
427
|
+
return false;
|
|
428
|
+
if (info.app !== "repoview") {
|
|
429
|
+
process.stderr.write(`Port ${port} is in use by something that isn't repoview. Use --port to pick another.\n`);
|
|
430
|
+
process.exit(1);
|
|
431
|
+
}
|
|
432
|
+
const registered = await registerRepo(base, repoRootAbs, watch);
|
|
433
|
+
process.stdout.write(`Joined repoview session on port ${port}\n` +
|
|
434
|
+
`${registered.name} → http://${connectHost(host)}:${port}${registered.url}\n`);
|
|
435
|
+
return true;
|
|
436
|
+
}
|
|
437
|
+
// Try to join an existing session first; otherwise become the daemon.
|
|
438
|
+
if (await joinExisting()) {
|
|
439
|
+
process.exit(0);
|
|
440
|
+
}
|
|
441
|
+
try {
|
|
442
|
+
await startServer({ repoRoot: repoRootAbs, port, host, watch });
|
|
443
|
+
}
|
|
444
|
+
catch (e) {
|
|
445
|
+
if (e.code === "EADDRINUSE") {
|
|
446
|
+
// Lost a startup race — another daemon just bound the port. Join it.
|
|
447
|
+
if (await joinExisting())
|
|
448
|
+
process.exit(0);
|
|
449
|
+
process.stderr.write(`Port ${port} is already in use.\n`);
|
|
450
|
+
process.exit(1);
|
|
451
|
+
}
|
|
452
|
+
throw e;
|
|
453
|
+
}
|
|
454
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/csv.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
export function parseCsv(text, delimiter = ",") {
|
|
2
|
+
const rows = [];
|
|
3
|
+
let current = [];
|
|
4
|
+
let cell = "";
|
|
5
|
+
let inQuotes = false;
|
|
6
|
+
for (let i = 0; i < text.length; i++) {
|
|
7
|
+
const ch = text[i];
|
|
8
|
+
if (inQuotes) {
|
|
9
|
+
if (ch === '"' && text[i + 1] === '"') {
|
|
10
|
+
cell += '"';
|
|
11
|
+
i++;
|
|
12
|
+
}
|
|
13
|
+
else if (ch === '"') {
|
|
14
|
+
inQuotes = false;
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
cell += ch;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
if (ch === '"') {
|
|
22
|
+
inQuotes = true;
|
|
23
|
+
}
|
|
24
|
+
else if (ch === delimiter) {
|
|
25
|
+
current.push(cell);
|
|
26
|
+
cell = "";
|
|
27
|
+
}
|
|
28
|
+
else if (ch === "\n" || (ch === "\r" && text[i + 1] === "\n")) {
|
|
29
|
+
if (ch === "\r")
|
|
30
|
+
i++;
|
|
31
|
+
current.push(cell);
|
|
32
|
+
rows.push(current);
|
|
33
|
+
current = [];
|
|
34
|
+
cell = "";
|
|
35
|
+
}
|
|
36
|
+
else if (ch === "\r") {
|
|
37
|
+
current.push(cell);
|
|
38
|
+
rows.push(current);
|
|
39
|
+
current = [];
|
|
40
|
+
cell = "";
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
cell += ch;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
if (cell || current.length) {
|
|
48
|
+
current.push(cell);
|
|
49
|
+
rows.push(current);
|
|
50
|
+
}
|
|
51
|
+
return rows;
|
|
52
|
+
}
|
|
53
|
+
export function renderCsvTable(rows, escFn) {
|
|
54
|
+
if (!rows.length)
|
|
55
|
+
return "<p>Empty file</p>";
|
|
56
|
+
const header = rows[0];
|
|
57
|
+
const body = rows.slice(1);
|
|
58
|
+
const ths = header.map((h) => `<th>${escFn(h)}</th>`).join("");
|
|
59
|
+
const trs = body
|
|
60
|
+
.map((row) => `<tr>${row.map((c) => `<td>${escFn(c)}</td>`).join("")}</tr>`)
|
|
61
|
+
.join("\n");
|
|
62
|
+
return `<div class="csv-table-wrap"><table class="csv-table"><thead><tr>${ths}</tr></thead><tbody>${trs}</tbody></table></div>`;
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=csv.js.map
|
package/dist/csv.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"csv.js","sourceRoot":"","sources":["../src/csv.ts"],"names":[],"mappings":"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"}
|
package/dist/format.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export function formatBytes(bytes) {
|
|
2
|
+
if (!Number.isFinite(bytes))
|
|
3
|
+
return "";
|
|
4
|
+
if (bytes < 1024)
|
|
5
|
+
return `${bytes} B`;
|
|
6
|
+
const units = ["KB", "MB", "GB", "TB"];
|
|
7
|
+
let value = bytes / 1024;
|
|
8
|
+
let unit = 0;
|
|
9
|
+
while (value >= 1024 && unit < units.length - 1) {
|
|
10
|
+
value /= 1024;
|
|
11
|
+
unit++;
|
|
12
|
+
}
|
|
13
|
+
return `${value.toFixed(value < 10 ? 1 : 0)} ${units[unit]}`;
|
|
14
|
+
}
|
|
15
|
+
export function formatDate(ms) {
|
|
16
|
+
const d = new Date(ms);
|
|
17
|
+
return d.toLocaleString(undefined, {
|
|
18
|
+
year: "numeric",
|
|
19
|
+
month: "short",
|
|
20
|
+
day: "2-digit",
|
|
21
|
+
hour: "2-digit",
|
|
22
|
+
minute: "2-digit",
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=format.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.js","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,WAAW,CAAC,KAAa;IACvC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IACvC,IAAI,KAAK,GAAG,IAAI;QAAE,OAAO,GAAG,KAAK,IAAI,CAAC;IACtC,MAAM,KAAK,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IACvC,IAAI,KAAK,GAAG,KAAK,GAAG,IAAI,CAAC;IACzB,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,OAAO,KAAK,IAAI,IAAI,IAAI,IAAI,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAChD,KAAK,IAAI,IAAI,CAAC;QACd,IAAI,EAAE,CAAC;IACT,CAAC;IACD,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;AAC/D,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,EAAU;IACnC,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,EAAE,CAAC,CAAC;IACvB,OAAO,CAAC,CAAC,cAAc,CAAC,SAAS,EAAE;QACjC,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,OAAO;QACd,GAAG,EAAE,SAAS;QACd,IAAI,EAAE,SAAS;QACf,MAAM,EAAE,SAAS;KAClB,CAAC,CAAC;AACL,CAAC"}
|