botsync 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/README.md +37 -0
- package/dist/cli.d.ts +8 -0
- package/dist/cli.js +102 -0
- package/dist/commands/init.d.ts +13 -0
- package/dist/commands/init.js +151 -0
- package/dist/commands/join.d.ts +13 -0
- package/dist/commands/join.js +106 -0
- package/dist/commands/status.d.ts +6 -0
- package/dist/commands/status.js +81 -0
- package/dist/commands/stop.d.ts +6 -0
- package/dist/commands/stop.js +52 -0
- package/dist/config.d.ts +31 -0
- package/dist/config.js +55 -0
- package/dist/passphrase.d.ts +31 -0
- package/dist/passphrase.js +89 -0
- package/dist/syncthing.d.ts +80 -0
- package/dist/syncthing.js +312 -0
- package/dist/ui.d.ts +47 -0
- package/dist/ui.js +148 -0
- package/package.json +45 -0
package/dist/ui.js
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* ui.ts — Pretty terminal output for botsync.
|
|
4
|
+
*
|
|
5
|
+
* Inspired by Claude Code's minimal, elegant CLI style:
|
|
6
|
+
* - 2-space indent on everything
|
|
7
|
+
* - Muted colors, not a rainbow
|
|
8
|
+
* - Box-drawing for important info (passphrases)
|
|
9
|
+
* - Spinners for async waits
|
|
10
|
+
* - Clean status tables with alignment
|
|
11
|
+
*
|
|
12
|
+
* Uses chalk@4 (CJS-compatible) and ora@5 (CJS-compatible).
|
|
13
|
+
*/
|
|
14
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
15
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
16
|
+
};
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.header = header;
|
|
19
|
+
exports.stepDone = stepDone;
|
|
20
|
+
exports.stepFail = stepFail;
|
|
21
|
+
exports.info = info;
|
|
22
|
+
exports.gap = gap;
|
|
23
|
+
exports.passphraseBox = passphraseBox;
|
|
24
|
+
exports.spinner = spinner;
|
|
25
|
+
exports.paired = paired;
|
|
26
|
+
exports.connected = connected;
|
|
27
|
+
exports.statusTable = statusTable;
|
|
28
|
+
exports.stopped = stopped;
|
|
29
|
+
exports.notRunning = notRunning;
|
|
30
|
+
exports.error = error;
|
|
31
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
32
|
+
const ora_1 = __importDefault(require("ora"));
|
|
33
|
+
// Brand colors
|
|
34
|
+
const brand = chalk_1.default.cyan;
|
|
35
|
+
const success = chalk_1.default.green;
|
|
36
|
+
const dim = chalk_1.default.dim;
|
|
37
|
+
const bold = chalk_1.default.bold;
|
|
38
|
+
const warn = chalk_1.default.yellow;
|
|
39
|
+
const INDENT = " ";
|
|
40
|
+
/** The botsync diamond header — printed once at the top of every command. */
|
|
41
|
+
function header() {
|
|
42
|
+
console.log();
|
|
43
|
+
console.log(`${INDENT}${brand("◆")} ${bold("botsync")}`);
|
|
44
|
+
console.log();
|
|
45
|
+
}
|
|
46
|
+
/** A step that completed successfully. */
|
|
47
|
+
function stepDone(label) {
|
|
48
|
+
console.log(`${INDENT}${success("✓")} ${dim(label)}`);
|
|
49
|
+
}
|
|
50
|
+
/** A step that failed. */
|
|
51
|
+
function stepFail(label) {
|
|
52
|
+
console.log(`${INDENT}${chalk_1.default.red("✗")} ${label}`);
|
|
53
|
+
}
|
|
54
|
+
/** Print an info line (indented, dimmed). */
|
|
55
|
+
function info(text) {
|
|
56
|
+
console.log(`${INDENT}${dim(text)}`);
|
|
57
|
+
}
|
|
58
|
+
/** Print a blank line. */
|
|
59
|
+
function gap() {
|
|
60
|
+
console.log();
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Display the passphrase in a box so it visually pops.
|
|
64
|
+
* The box auto-sizes to the passphrase length (with wrapping for long ones).
|
|
65
|
+
*/
|
|
66
|
+
function passphraseBox(passphrase, command) {
|
|
67
|
+
// Wrap passphrase at ~50 chars for readability
|
|
68
|
+
const maxWidth = 52;
|
|
69
|
+
const lines = [];
|
|
70
|
+
for (let i = 0; i < passphrase.length; i += maxWidth) {
|
|
71
|
+
lines.push(passphrase.substring(i, i + maxWidth));
|
|
72
|
+
}
|
|
73
|
+
const contentWidth = Math.max(maxWidth, command.length + 2);
|
|
74
|
+
const top = `┌${"─".repeat(contentWidth + 2)}┐`;
|
|
75
|
+
const bot = `└${"─".repeat(contentWidth + 2)}┘`;
|
|
76
|
+
const empty = `│${" ".repeat(contentWidth + 2)}│`;
|
|
77
|
+
const pad = (s) => {
|
|
78
|
+
const visible = s.length;
|
|
79
|
+
return `│ ${s}${" ".repeat(Math.max(0, contentWidth - visible))} │`;
|
|
80
|
+
};
|
|
81
|
+
console.log(`${INDENT}${dim(top)}`);
|
|
82
|
+
console.log(`${INDENT}${dim("│")} ${bold("Your passphrase:")}${" ".repeat(Math.max(0, contentWidth - 17))}${dim("│")}`);
|
|
83
|
+
console.log(`${INDENT}${dim(empty)}`);
|
|
84
|
+
for (const line of lines) {
|
|
85
|
+
console.log(`${INDENT}${dim("│")} ${brand(line)}${" ".repeat(Math.max(0, contentWidth - line.length))} ${dim("│")}`);
|
|
86
|
+
}
|
|
87
|
+
console.log(`${INDENT}${dim(empty)}`);
|
|
88
|
+
console.log(`${INDENT}${dim("│")} ${dim("On the other machine:")}${" ".repeat(Math.max(0, contentWidth - 21))}${dim("│")}`);
|
|
89
|
+
console.log(`${INDENT}${dim("│")} ${chalk_1.default.white(command)}${" ".repeat(Math.max(0, contentWidth - command.length))} ${dim("│")}`);
|
|
90
|
+
console.log(`${INDENT}${dim(bot)}`);
|
|
91
|
+
}
|
|
92
|
+
/** Start a spinner. Returns the ora instance so the caller can stop it. */
|
|
93
|
+
function spinner(text) {
|
|
94
|
+
return (0, ora_1.default)({
|
|
95
|
+
text: dim(text),
|
|
96
|
+
prefixText: INDENT,
|
|
97
|
+
spinner: "dots",
|
|
98
|
+
color: "cyan",
|
|
99
|
+
}).start();
|
|
100
|
+
}
|
|
101
|
+
/** Print the "paired" success message. */
|
|
102
|
+
function paired(deviceId) {
|
|
103
|
+
const short = deviceId.substring(0, 7);
|
|
104
|
+
console.log();
|
|
105
|
+
console.log(`${INDENT}${success("✓")} ${bold("Paired with")} ${brand(short)} ${dim("— sync is active")}`);
|
|
106
|
+
console.log();
|
|
107
|
+
}
|
|
108
|
+
/** Print connection success for the join side. */
|
|
109
|
+
function connected(deviceId) {
|
|
110
|
+
const short = deviceId.substring(0, 7);
|
|
111
|
+
console.log(`${INDENT}${success("✓")} ${bold("Connected to")} ${brand(short)}`);
|
|
112
|
+
console.log();
|
|
113
|
+
}
|
|
114
|
+
/** Print the status table. */
|
|
115
|
+
function statusTable(peers, deviceId, folders) {
|
|
116
|
+
header();
|
|
117
|
+
// Peer count with color
|
|
118
|
+
const peerStr = peers > 0 ? success(`${peers} connected`) : warn("0 connected");
|
|
119
|
+
console.log(`${INDENT}${dim("Peers")} ${peerStr}`);
|
|
120
|
+
console.log(`${INDENT}${dim("Device")} ${brand(deviceId.substring(0, 7))}${dim("...")}`);
|
|
121
|
+
console.log();
|
|
122
|
+
// Folder rows — fixed-width columns
|
|
123
|
+
for (const f of folders) {
|
|
124
|
+
const icon = f.synced ? success("✓") : warn("⟳");
|
|
125
|
+
const state = f.synced ? dim(f.state) : warn(f.state);
|
|
126
|
+
const name = f.name.padEnd(18);
|
|
127
|
+
console.log(`${INDENT}${icon} ${name}${state}`);
|
|
128
|
+
}
|
|
129
|
+
console.log();
|
|
130
|
+
}
|
|
131
|
+
/** Stopped message. */
|
|
132
|
+
function stopped() {
|
|
133
|
+
header();
|
|
134
|
+
console.log(`${INDENT}${dim("Daemon stopped.")}`);
|
|
135
|
+
console.log();
|
|
136
|
+
}
|
|
137
|
+
/** Not running message. */
|
|
138
|
+
function notRunning() {
|
|
139
|
+
header();
|
|
140
|
+
console.log(`${INDENT}${warn("Not running.")} ${dim("Run")} ${chalk_1.default.white("botsync init")} ${dim("to start.")}`);
|
|
141
|
+
console.log();
|
|
142
|
+
}
|
|
143
|
+
/** Error message. */
|
|
144
|
+
function error(msg) {
|
|
145
|
+
console.log();
|
|
146
|
+
console.log(`${INDENT}${chalk_1.default.red("✗")} ${msg}`);
|
|
147
|
+
console.log();
|
|
148
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "botsync",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "P2P file sync for AI agents. Syncthing under the hood. Two commands.",
|
|
5
|
+
"bin": {
|
|
6
|
+
"botsync": "./dist/cli.js"
|
|
7
|
+
},
|
|
8
|
+
"scripts": {
|
|
9
|
+
"build": "tsc",
|
|
10
|
+
"prepublishOnly": "npm run build"
|
|
11
|
+
},
|
|
12
|
+
"keywords": [
|
|
13
|
+
"sync",
|
|
14
|
+
"p2p",
|
|
15
|
+
"ai",
|
|
16
|
+
"agents",
|
|
17
|
+
"syncthing"
|
|
18
|
+
],
|
|
19
|
+
"author": "Hashbranch <tom@hashbranch.com> (https://botsync.io)",
|
|
20
|
+
"homepage": "https://botsync.io",
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "https://github.com/hashbranch/botsync"
|
|
24
|
+
},
|
|
25
|
+
"license": "MIT",
|
|
26
|
+
"files": [
|
|
27
|
+
"dist/**/*.js",
|
|
28
|
+
"dist/**/*.d.ts",
|
|
29
|
+
"README.md",
|
|
30
|
+
"LICENSE"
|
|
31
|
+
],
|
|
32
|
+
"type": "commonjs",
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"base-x": "^4.0.1",
|
|
35
|
+
"chalk": "^4.1.2",
|
|
36
|
+
"commander": "^13.1.0",
|
|
37
|
+
"ora": "^5.4.1",
|
|
38
|
+
"tar": "^7.4.3"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@types/chalk": "^0.4.31",
|
|
42
|
+
"@types/node": "^22.13.0",
|
|
43
|
+
"typescript": "^5.7.0"
|
|
44
|
+
}
|
|
45
|
+
}
|