@andrestobelem/clone 0.1.3 → 0.2.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.
Files changed (49) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +151 -23
  3. package/app.js +645 -0
  4. package/bin/clone.js +11 -230
  5. package/dist/actors.js +49 -0
  6. package/dist/actors.js.map +1 -0
  7. package/dist/automations.js +57 -0
  8. package/dist/automations.js.map +1 -0
  9. package/dist/cli.js +565 -0
  10. package/dist/cli.js.map +1 -0
  11. package/dist/database.js +62 -0
  12. package/dist/database.js.map +1 -0
  13. package/dist/errors.js +46 -0
  14. package/dist/errors.js.map +1 -0
  15. package/dist/issues.js +264 -0
  16. package/dist/issues.js.map +1 -0
  17. package/dist/paths.js +42 -0
  18. package/dist/paths.js.map +1 -0
  19. package/dist/projects.js +134 -0
  20. package/dist/projects.js.map +1 -0
  21. package/dist/recurring.js +45 -0
  22. package/dist/recurring.js.map +1 -0
  23. package/dist/schema.js +52 -0
  24. package/dist/schema.js.map +1 -0
  25. package/dist/seed.js +498 -0
  26. package/dist/seed.js.map +1 -0
  27. package/dist/server.js +232 -0
  28. package/dist/server.js.map +1 -0
  29. package/dist/sync.js +625 -0
  30. package/dist/sync.js.map +1 -0
  31. package/dist/teams.js +77 -0
  32. package/dist/teams.js.map +1 -0
  33. package/dist/time.js +4 -0
  34. package/dist/time.js.map +1 -0
  35. package/dist/types.js +2 -0
  36. package/dist/types.js.map +1 -0
  37. package/dist/validation.js +254 -0
  38. package/dist/validation.js.map +1 -0
  39. package/dist/workspace-helpers.js +75 -0
  40. package/dist/workspace-helpers.js.map +1 -0
  41. package/dist/workspace-mutations.js +160 -0
  42. package/dist/workspace-mutations.js.map +1 -0
  43. package/dist/workspace-reads.js +62 -0
  44. package/dist/workspace-reads.js.map +1 -0
  45. package/dist/workspace.js +8 -0
  46. package/dist/workspace.js.map +1 -0
  47. package/index.html +73 -0
  48. package/package.json +33 -4
  49. package/styles.css +108 -0
package/bin/clone.js CHANGED
@@ -1,232 +1,13 @@
1
1
  #!/usr/bin/env node
2
- "use strict";
3
2
 
4
- const crypto = require("node:crypto");
5
- const fs = require("node:fs");
6
- const os = require("node:os");
7
- const path = require("node:path");
8
- const { spawn, spawnSync } = require("node:child_process");
9
- const packageMetadata = require("../package.json");
10
-
11
- const RELEASE_ROOT = "https://github.com/andrestobelem/clone/releases/download";
12
- const TARGETS = new Map([
13
- ["darwin-arm64", "clone-darwin-arm64"],
14
- ["darwin-x64", "clone-darwin-x64"],
15
- ["linux-arm64", "clone-linux-arm64"],
16
- ["linux-x64", "clone-linux-x64"],
17
- ["win32-x64", "clone-win32-x64.exe"],
18
- ]);
19
- const BLOCKED_PORTS = new Set([
20
- 1, 7, 9, 11, 13, 15, 17, 19, 20, 21, 22, 23, 25, 37, 42, 43, 53, 69, 77, 79, 87, 95,
21
- 101, 102, 103, 104, 109, 110, 111, 113, 115, 117, 119, 123, 135, 137, 139, 143, 161, 179,
22
- 389, 427, 465, 512, 513, 514, 515, 526, 530, 531, 532, 540, 548, 554, 556, 563, 587, 601,
23
- 636, 989, 990, 993, 995, 1719, 1720, 1723, 2049, 3659, 4045, 4190, 5060, 5061, 6000, 6566,
24
- 6665, 6666, 6667, 6668, 6669, 6697, 10080,
25
- ]);
26
-
27
- function target(platform = process.platform, architecture = process.arch) {
28
- const value = TARGETS.get(`${platform}-${architecture}`);
29
- if (!value) throw new Error(`Clone does not support ${platform}/${architecture}.`);
30
- return value;
31
- }
32
-
33
- function cacheDirectory(platform = process.platform, environment = process.env) {
34
- if (environment.CLONE_CACHE_DIR) return path.resolve(environment.CLONE_CACHE_DIR);
35
- if (platform === "darwin") return path.join(os.homedir(), "Library", "Caches", "Clone");
36
- if (platform === "win32") return path.join(environment.LOCALAPPDATA || os.homedir(), "Clone", "cache");
37
- return path.join(environment.XDG_CACHE_HOME || path.join(os.homedir(), ".cache"), "clone");
38
- }
39
-
40
- function dataDirectory(platform = process.platform, environment = process.env, override = null) {
41
- if (override) return path.resolve(override);
42
- if (environment.CLONE_DATA_DIR) return path.resolve(environment.CLONE_DATA_DIR);
43
- if (platform === "darwin") return path.join(os.homedir(), "Library", "Application Support", "Clone");
44
- if (platform === "win32") return path.join(environment.APPDATA || os.homedir(), "Clone");
45
- return path.join(environment.XDG_DATA_HOME || path.join(os.homedir(), ".local", "share"), "clone");
46
- }
47
-
48
- function parseLauncherArguments(arguments_, workingDirectory = process.cwd()) {
49
- let storage = null;
50
- const forwarded = [];
51
- for (let index = 0; index < arguments_.length; index += 1) {
52
- const value = arguments_[index];
53
- if (value === "--local") {
54
- if (storage) throw new Error("Use only one data directory option.");
55
- storage = path.join(workingDirectory, ".clone");
56
- } else if (value === "--data-dir") {
57
- if (storage) throw new Error("Use only one data directory option.");
58
- const directory = arguments_[++index];
59
- if (!directory) throw new Error("--data-dir requires a path.");
60
- storage = path.resolve(workingDirectory, directory);
61
- } else if (value.startsWith("--data-dir=")) {
62
- if (storage) throw new Error("Use only one data directory option.");
63
- const directory = value.slice(11);
64
- if (!directory) throw new Error("--data-dir requires a path.");
65
- storage = path.resolve(workingDirectory, directory);
66
- } else {
67
- forwarded.push(value);
68
- }
69
- }
70
- return { arguments: forwarded, storage };
71
- }
72
-
73
- async function download(url, destination) {
74
- const response = await fetch(url, { headers: { "user-agent": `clone/${packageMetadata.version}` } });
75
- if (!response.ok) throw new Error(`Download failed (${response.status}): ${url}`);
76
- const temporary = `${destination}.download`;
77
- fs.writeFileSync(temporary, Buffer.from(await response.arrayBuffer()), { mode: 0o755 });
78
- fs.renameSync(temporary, destination);
79
- }
80
-
81
- function checksum(file) {
82
- return crypto.createHash("sha256").update(fs.readFileSync(file)).digest("hex");
83
- }
84
-
85
- async function binaryPath() {
86
- if (process.env.CLONE_BINARY_PATH) return path.resolve(process.env.CLONE_BINARY_PATH);
87
- const filename = target();
88
- const directory = path.join(cacheDirectory(), packageMetadata.version);
89
- const binary = path.join(directory, filename);
90
- const checksums = path.join(directory, "checksums.txt");
91
- fs.mkdirSync(directory, { recursive: true });
92
- const release = `${RELEASE_ROOT}/v${packageMetadata.version}`;
93
- if (!fs.existsSync(checksums)) await download(`${release}/checksums.txt`, checksums);
94
- const expectedLine = fs.readFileSync(checksums, "utf8").split(/\r?\n/).find((line) => line.endsWith(` ${filename}`));
95
- if (!expectedLine) throw new Error(`The release has no checksum for ${filename}.`);
96
- const expected = expectedLine.split(/\s+/)[0];
97
- if (!fs.existsSync(binary) || checksum(binary) !== expected) {
98
- fs.rmSync(binary, { force: true });
99
- await download(`${release}/${filename}`, binary);
100
- }
101
- if (checksum(binary) !== expected) {
102
- fs.rmSync(binary, { force: true });
103
- throw new Error(`Checksum verification failed for ${filename}.`);
104
- }
105
- if (process.platform !== "win32") fs.chmodSync(binary, 0o755);
106
- return binary;
107
- }
108
-
109
- function openBrowser(url) {
110
- const command = process.platform === "darwin" ? ["open", [url]]
111
- : process.platform === "win32" ? ["cmd", ["/d", "/s", "/c", "start", "", url]]
112
- : ["xdg-open", [url]];
113
- const child = spawn(command[0], command[1], { detached: true, stdio: "ignore" });
114
- child.unref();
115
- }
116
-
117
- async function waitForServer(url, child, errorState) {
118
- for (let attempt = 0; attempt < 80; attempt += 1) {
119
- if (errorState.value) throw errorState.value;
120
- if (child.exitCode !== null) throw new Error(`Clone stopped with exit code ${child.exitCode}.`);
121
- try {
122
- const response = await fetch(`${url}/api/health`);
123
- if (response.ok) return;
124
- } catch {}
125
- await new Promise((resolve) => setTimeout(resolve, 250));
126
- }
127
- throw new Error(`Clone did not start at ${url}.`);
128
- }
129
-
130
- function parseStartArguments(arguments_) {
131
- let port = process.env.PORT || "4173";
132
- let open = true;
133
- for (let index = 0; index < arguments_.length; index += 1) {
134
- const value = arguments_[index];
135
- if (value === "--no-open") open = false;
136
- else if (value === "--port") port = arguments_[++index];
137
- else if (value.startsWith("--port=")) port = value.slice(7);
138
- else throw new Error(`Unknown start option: ${value}`);
139
- }
140
- if (!/^\d+$/.test(String(port)) || Number(port) < 1 || Number(port) > 65535) throw new Error("Port must be between 1 and 65535.");
141
- if (BLOCKED_PORTS.has(Number(port))) throw new Error(`Port ${port} is blocked by web browsers.`);
142
- return { port: String(port), open };
143
- }
144
-
145
- function initialize(binary, database, storage) {
146
- if (fs.existsSync(database) || fs.existsSync(path.join(storage, "snapshot"))) return;
147
- fs.mkdirSync(storage, { recursive: true });
148
- const result = spawnSync(binary, ["--db", database, "init"], { encoding: "utf8" });
149
- if (result.error) throw result.error;
150
- if (result.status !== 0) {
151
- if (result.stdout) process.stdout.write(result.stdout);
152
- if (result.stderr) process.stderr.write(result.stderr);
153
- throw new Error(`Clone initialization failed with exit code ${result.status}.`);
154
- }
155
- }
156
-
157
- async function start(binary, arguments_, environment = process.env) {
158
- const options = parseStartArguments(arguments_);
159
- const storage = dataDirectory(process.platform, environment);
160
- const database = path.join(storage, "workspace.sqlite3");
161
- initialize(binary, database, storage);
162
- const url = `http://127.0.0.1:${options.port}`;
163
- const child = spawn(binary, ["--db", database, "serve"], {
164
- env: { ...environment, CLONE_HOST: "127.0.0.1", PORT: options.port },
165
- stdio: "inherit",
166
- });
167
- const errorState = { value: null };
168
- child.once("error", (error) => { errorState.value = error; });
169
- for (const signal of ["SIGINT", "SIGTERM"]) process.once(signal, () => child.kill(signal));
170
- try {
171
- await waitForServer(url, child, errorState);
172
- } catch (error) {
173
- child.kill("SIGTERM");
174
- throw error;
175
- }
176
- console.log(`Open ${url}. Stop with Ctrl+C.`);
177
- if (options.open) openBrowser(url);
178
- return new Promise((resolve) => {
179
- child.once("exit", (code, signal) => resolve(signal ? 1 : (code || 0)));
180
- });
181
- }
182
-
183
- function help(storage = null) {
184
- console.log(`Clone ${packageMetadata.version}
185
-
186
- Usage:
187
- clone [--local | --data-dir PATH] [start] [--port PORT] [--no-open]
188
- clone [--local | --data-dir PATH] <CLI command> [options]
189
-
190
- Examples:
191
- npx @andrestobelem/clone
192
- npx @andrestobelem/clone --local
193
- npx @andrestobelem/clone --data-dir ./project-data
194
- npx @andrestobelem/clone start --port 5000
195
- npx @andrestobelem/clone teams list --json
196
-
197
- Data: ${dataDirectory(process.platform, process.env, storage)}`);
198
- }
199
-
200
- async function main(arguments_ = process.argv.slice(2)) {
201
- const launcher = parseLauncherArguments(arguments_);
202
- arguments_ = launcher.arguments;
203
- if (arguments_.includes("--version") || arguments_.includes("-V")) {
204
- console.log(packageMetadata.version);
205
- return 0;
206
- }
207
- if (arguments_.includes("--help") || arguments_.includes("-h")) {
208
- help(launcher.storage);
209
- return 0;
210
- }
211
- const binary = await binaryPath();
212
- const command = arguments_[0];
213
- if (!command || command === "start") {
214
- const environment = launcher.storage ? { ...process.env, CLONE_DATA_DIR: launcher.storage } : process.env;
215
- return start(binary, command ? arguments_.slice(1) : arguments_, environment);
216
- }
217
- const storage = dataDirectory(process.platform, process.env, launcher.storage);
218
- const database = path.join(storage, "workspace.sqlite3");
219
- initialize(binary, database, storage);
220
- const result = spawnSync(binary, ["--db", database, ...arguments_], { stdio: "inherit" });
221
- if (result.error) throw result.error;
222
- return result.status || 0;
223
- }
224
-
225
- if (require.main === module) {
226
- main().then((code) => { process.exitCode = code; }).catch((error) => {
227
- console.error(`Clone: ${error.message}`);
228
- process.exitCode = 1;
229
- });
230
- }
231
-
232
- module.exports = { cacheDirectory, dataDirectory, parseLauncherArguments, parseStartArguments, target };
3
+ import("../dist/cli.js")
4
+ .then(({ main }) => main(process.argv.slice(2)))
5
+ .then(
6
+ (code) => {
7
+ process.exitCode = code;
8
+ },
9
+ (error) => {
10
+ console.error(error instanceof Error ? error.message : String(error));
11
+ process.exitCode = 4;
12
+ },
13
+ );
package/dist/actors.js ADDED
@@ -0,0 +1,49 @@
1
+ import { lastInsertId, one, rows, run, sql, } from "./database.js";
2
+ import { InvalidInputError, RelationshipConflictError } from "./errors.js";
3
+ import { fail, text } from "./workspace-helpers.js";
4
+ export function mutateAgent(database, method, route, data, stamp) {
5
+ if (route === "/api/agents" && method === "POST") {
6
+ const key = text(data.key, "Agent key is required");
7
+ const name = text(data.name, "Agent name is required");
8
+ run(database, "INSERT INTO actors(kind,name,key,created_at) VALUES('agent',?,?,?)", name, key, stamp);
9
+ const agentId = lastInsertId(database);
10
+ if (data.teamId !== undefined)
11
+ run(database, "INSERT INTO team_members(team_id,member_id,role) VALUES(?,?,'Member')", sql(data.teamId), agentId);
12
+ return { agent: actorRecord(database, agentId), _status: 201 };
13
+ }
14
+ const match = route.match(/^\/api\/agents\/(\d+)(?:\/(deactivate|restore))?$/);
15
+ if (!match)
16
+ return null;
17
+ const agentId = Number(match[1]);
18
+ const target = actorRecord(database, agentId);
19
+ if (!target || target.kind !== "agent")
20
+ fail("Agent not found");
21
+ if (match[2] && method === "POST")
22
+ run(database, "UPDATE actors SET active=? WHERE id=?", match[2] === "restore" ? 1 : 0, agentId);
23
+ else if (!match[2] && method === "PATCH") {
24
+ if ("key" in data)
25
+ fail("Agent key cannot change");
26
+ run(database, "UPDATE actors SET name=? WHERE id=?", text(data.name, "Agent name is required"), agentId);
27
+ }
28
+ else
29
+ return { error: "Not found", _status: 404 };
30
+ return { agent: actorRecord(database, agentId) };
31
+ }
32
+ export function actorRecord(database, actorId) {
33
+ return (one(database, `SELECT a.*,m.email,m.role FROM actors a
34
+ LEFT JOIN members m ON m.id=a.member_id WHERE a.id=?`, actorId) ?? null);
35
+ }
36
+ export function actorRecords(database, kind = null, includeInactive = false) {
37
+ return rows(database, "SELECT id FROM actors WHERE (? IS NULL OR kind=?) AND (? OR active=1) ORDER BY id", kind, kind, includeInactive ? 1 : 0)
38
+ .map((row) => actorRecord(database, Number(row.id)))
39
+ .filter((row) => row !== null);
40
+ }
41
+ export function requireActor(database, actorId) {
42
+ if (!Number.isInteger(actorId))
43
+ throw new InvalidInputError("Actor ID must be an integer");
44
+ const record = actorRecord(database, Number(actorId));
45
+ if (!record || !record.active)
46
+ throw new RelationshipConflictError("Actor not found or inactive");
47
+ return Number(actorId);
48
+ }
49
+ //# sourceMappingURL=actors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"actors.js","sourceRoot":"","sources":["../src/actors.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,57 @@
1
+ import { requireActor } from "./actors.js";
2
+ import { one, rows, run, sql } from "./database.js";
3
+ import { priorities } from "./schema.js";
4
+ import { now } from "./time.js";
5
+ import { event, parseJson } from "./workspace-helpers.js";
6
+ export function applyAutomations(database, teamId, issueId, eventName, actor) {
7
+ const issue = one(database, "SELECT i.*,s.name AS status FROM issues i JOIN issue_statuses s ON s.id=i.status_id WHERE i.id=?", issueId);
8
+ if (!issue)
9
+ return;
10
+ const labels = new Set(rows(database, "SELECT l.name FROM labels l JOIN issue_labels il ON il.label_id=l.id WHERE il.issue_id=?", issueId).map((row) => String(row.name)));
11
+ for (const rule of rows(database, "SELECT * FROM automations WHERE team_id=? AND enabled=1 ORDER BY id", teamId)) {
12
+ const trigger = parseJson(rule.trigger_json, {});
13
+ const condition = parseJson(rule.condition_json, {});
14
+ const action = parseJson(rule.action_json, {});
15
+ if (trigger.event !== eventName)
16
+ continue;
17
+ if (![null, "", "Any", undefined].includes(condition.priority) &&
18
+ priorities[Number(issue.priority)] !== condition.priority)
19
+ continue;
20
+ if (![null, "", "Any", undefined].includes(condition.label) &&
21
+ !labels.has(String(condition.label)))
22
+ continue;
23
+ const name = String(action.name ?? "");
24
+ const changes = [];
25
+ if (action.assignTo !== undefined) {
26
+ const id = requireActor(database, action.assignTo);
27
+ run(database, "UPDATE issues SET assignee_id=?,updated_at=? WHERE id=?", id, now(), issueId);
28
+ changes.push({ field: "assignee_id", value: id });
29
+ }
30
+ else if (name === "Assign to me") {
31
+ run(database, "UPDATE issues SET assignee_id=?,updated_at=? WHERE id=?", actor, now(), issueId);
32
+ changes.push({ field: "assignee_id", value: actor });
33
+ }
34
+ else if (name.startsWith("Add ") && name.endsWith(" label")) {
35
+ const labelName = name.slice(4, -6).trim();
36
+ const label = one(database, "SELECT id FROM labels WHERE name=? AND (team_id=? OR team_id IS NULL) ORDER BY team_id DESC LIMIT 1", labelName, teamId);
37
+ if (label && !labels.has(labelName)) {
38
+ run(database, "INSERT OR IGNORE INTO issue_labels(issue_id,label_id) VALUES(?,?)", issueId, sql(label.id));
39
+ labels.add(labelName);
40
+ changes.push({ field: "label", value: labelName });
41
+ }
42
+ }
43
+ else if (name.startsWith("Set status: ")) {
44
+ const status = one(database, "SELECT id FROM issue_statuses WHERE team_id=? AND name=?", teamId, name.split(":", 2)[1].trim());
45
+ if (status) {
46
+ run(database, "UPDATE issues SET status_id=?,updated_at=? WHERE id=?", sql(status.id), now(), issueId);
47
+ changes.push({ field: "status_id", value: Number(status.id) });
48
+ }
49
+ }
50
+ if (changes.length)
51
+ event(database, "issue", issueId, actor, "automation_applied", {
52
+ automation: String(rule.name),
53
+ changes,
54
+ });
55
+ }
56
+ }
57
+ //# sourceMappingURL=automations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"automations.js","sourceRoot":"","sources":["../src/automations.ts"],"names":[],"mappings":"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"}