offwatch 0.5.11 → 0.5.13
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 +132 -178
- package/bin/offwatch.js +6 -7
- package/lib/downloader.js +112 -0
- package/package.json +17 -7
- package/postinstall.js +21 -0
- package/src/__tests__/agent-jwt-env.test.ts +0 -79
- package/src/__tests__/allowed-hostname.test.ts +0 -80
- package/src/__tests__/auth-command-registration.test.ts +0 -16
- package/src/__tests__/board-auth.test.ts +0 -53
- package/src/__tests__/common.test.ts +0 -98
- package/src/__tests__/company-delete.test.ts +0 -95
- package/src/__tests__/company-import-export-e2e.test.ts +0 -502
- package/src/__tests__/company-import-url.test.ts +0 -74
- package/src/__tests__/company-import-zip.test.ts +0 -44
- package/src/__tests__/company.test.ts +0 -599
- package/src/__tests__/context.test.ts +0 -70
- package/src/__tests__/data-dir.test.ts +0 -79
- package/src/__tests__/doctor.test.ts +0 -102
- package/src/__tests__/feedback.test.ts +0 -177
- package/src/__tests__/helpers/embedded-postgres.ts +0 -6
- package/src/__tests__/helpers/zip.ts +0 -87
- package/src/__tests__/home-paths.test.ts +0 -44
- package/src/__tests__/http.test.ts +0 -106
- package/src/__tests__/network-bind.test.ts +0 -62
- package/src/__tests__/onboard.test.ts +0 -166
- package/src/__tests__/routines.test.ts +0 -249
- package/src/__tests__/telemetry.test.ts +0 -117
- package/src/__tests__/worktree-merge-history.test.ts +0 -492
- package/src/__tests__/worktree.test.ts +0 -982
- package/src/adapters/http/format-event.ts +0 -4
- package/src/adapters/http/index.ts +0 -7
- package/src/adapters/index.ts +0 -2
- package/src/adapters/process/format-event.ts +0 -4
- package/src/adapters/process/index.ts +0 -7
- package/src/adapters/registry.ts +0 -63
- package/src/checks/agent-jwt-secret-check.ts +0 -40
- package/src/checks/config-check.ts +0 -33
- package/src/checks/database-check.ts +0 -59
- package/src/checks/deployment-auth-check.ts +0 -88
- package/src/checks/index.ts +0 -18
- package/src/checks/llm-check.ts +0 -82
- package/src/checks/log-check.ts +0 -30
- package/src/checks/path-resolver.ts +0 -1
- package/src/checks/port-check.ts +0 -24
- package/src/checks/secrets-check.ts +0 -146
- package/src/checks/storage-check.ts +0 -51
- package/src/client/board-auth.ts +0 -282
- package/src/client/command-label.ts +0 -4
- package/src/client/context.ts +0 -175
- package/src/client/http.ts +0 -255
- package/src/commands/allowed-hostname.ts +0 -40
- package/src/commands/auth-bootstrap-ceo.ts +0 -138
- package/src/commands/client/activity.ts +0 -71
- package/src/commands/client/agent.ts +0 -315
- package/src/commands/client/approval.ts +0 -259
- package/src/commands/client/auth.ts +0 -113
- package/src/commands/client/common.ts +0 -221
- package/src/commands/client/company.ts +0 -1578
- package/src/commands/client/context.ts +0 -125
- package/src/commands/client/dashboard.ts +0 -34
- package/src/commands/client/feedback.ts +0 -645
- package/src/commands/client/issue.ts +0 -411
- package/src/commands/client/plugin.ts +0 -374
- package/src/commands/client/zip.ts +0 -129
- package/src/commands/configure.ts +0 -201
- package/src/commands/db-backup.ts +0 -102
- package/src/commands/doctor.ts +0 -203
- package/src/commands/env.ts +0 -411
- package/src/commands/heartbeat-run.ts +0 -344
- package/src/commands/onboard.ts +0 -692
- package/src/commands/routines.ts +0 -352
- package/src/commands/run.ts +0 -216
- package/src/commands/worktree-lib.ts +0 -279
- package/src/commands/worktree-merge-history-lib.ts +0 -764
- package/src/commands/worktree.ts +0 -2876
- package/src/config/data-dir.ts +0 -48
- package/src/config/env.ts +0 -125
- package/src/config/home.ts +0 -80
- package/src/config/hostnames.ts +0 -26
- package/src/config/schema.ts +0 -30
- package/src/config/secrets-key.ts +0 -48
- package/src/config/server-bind.ts +0 -183
- package/src/config/store.ts +0 -120
- package/src/index.ts +0 -182
- package/src/prompts/database.ts +0 -157
- package/src/prompts/llm.ts +0 -43
- package/src/prompts/logging.ts +0 -37
- package/src/prompts/secrets.ts +0 -99
- package/src/prompts/server.ts +0 -221
- package/src/prompts/storage.ts +0 -146
- package/src/telemetry.ts +0 -49
- package/src/utils/banner.ts +0 -24
- package/src/utils/net.ts +0 -18
- package/src/utils/path-resolver.ts +0 -25
- package/src/version.ts +0 -10
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
import path from "node:path";
|
|
2
|
-
import * as p from "@clack/prompts";
|
|
3
|
-
import pc from "picocolors";
|
|
4
|
-
import { formatDatabaseBackupResult, runDatabaseBackup } from "@paperclipai/db";
|
|
5
|
-
import {
|
|
6
|
-
expandHomePrefix,
|
|
7
|
-
resolveDefaultBackupDir,
|
|
8
|
-
resolvePaperclipInstanceId,
|
|
9
|
-
} from "../config/home.js";
|
|
10
|
-
import { readConfig, resolveConfigPath } from "../config/store.js";
|
|
11
|
-
import { printPaperclipCliBanner } from "../utils/banner.js";
|
|
12
|
-
|
|
13
|
-
type DbBackupOptions = {
|
|
14
|
-
config?: string;
|
|
15
|
-
dir?: string;
|
|
16
|
-
retentionDays?: number;
|
|
17
|
-
filenamePrefix?: string;
|
|
18
|
-
json?: boolean;
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
function resolveConnectionString(configPath?: string): { value: string; source: string } {
|
|
22
|
-
const envUrl = process.env.DATABASE_URL?.trim();
|
|
23
|
-
if (envUrl) return { value: envUrl, source: "DATABASE_URL" };
|
|
24
|
-
|
|
25
|
-
const config = readConfig(configPath);
|
|
26
|
-
if (config?.database.mode === "postgres" && config.database.connectionString?.trim()) {
|
|
27
|
-
return { value: config.database.connectionString.trim(), source: "config.database.connectionString" };
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const port = config?.database.embeddedPostgresPort ?? 54329;
|
|
31
|
-
return {
|
|
32
|
-
value: `postgres://paperclip:paperclip@127.0.0.1:${port}/paperclip`,
|
|
33
|
-
source: `embedded-postgres@${port}`,
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
function normalizeRetentionDays(value: number | undefined, fallback: number): number {
|
|
38
|
-
const candidate = value ?? fallback;
|
|
39
|
-
if (!Number.isInteger(candidate) || candidate < 1) {
|
|
40
|
-
throw new Error(`Invalid retention days '${String(candidate)}'. Use a positive integer.`);
|
|
41
|
-
}
|
|
42
|
-
return candidate;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function resolveBackupDir(raw: string): string {
|
|
46
|
-
return path.resolve(expandHomePrefix(raw.trim()));
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export async function dbBackupCommand(opts: DbBackupOptions): Promise<void> {
|
|
50
|
-
printPaperclipCliBanner();
|
|
51
|
-
p.intro(pc.bgCyan(pc.black(" paperclip db:backup ")));
|
|
52
|
-
|
|
53
|
-
const configPath = resolveConfigPath(opts.config);
|
|
54
|
-
const config = readConfig(opts.config);
|
|
55
|
-
const connection = resolveConnectionString(opts.config);
|
|
56
|
-
const defaultDir = resolveDefaultBackupDir(resolvePaperclipInstanceId());
|
|
57
|
-
const configuredDir = opts.dir?.trim() || config?.database.backup.dir || defaultDir;
|
|
58
|
-
const backupDir = resolveBackupDir(configuredDir);
|
|
59
|
-
const retentionDays = normalizeRetentionDays(
|
|
60
|
-
opts.retentionDays,
|
|
61
|
-
config?.database.backup.retentionDays ?? 30,
|
|
62
|
-
);
|
|
63
|
-
const filenamePrefix = opts.filenamePrefix?.trim() || "paperclip";
|
|
64
|
-
|
|
65
|
-
p.log.message(pc.dim(`Config: ${configPath}`));
|
|
66
|
-
p.log.message(pc.dim(`Connection source: ${connection.source}`));
|
|
67
|
-
p.log.message(pc.dim(`Backup dir: ${backupDir}`));
|
|
68
|
-
p.log.message(pc.dim(`Retention: ${retentionDays} day(s)`));
|
|
69
|
-
|
|
70
|
-
const spinner = p.spinner();
|
|
71
|
-
spinner.start("Creating database backup...");
|
|
72
|
-
try {
|
|
73
|
-
const result = await runDatabaseBackup({
|
|
74
|
-
connectionString: connection.value,
|
|
75
|
-
backupDir,
|
|
76
|
-
retention: { dailyDays: retentionDays, weeklyWeeks: 4, monthlyMonths: 1 },
|
|
77
|
-
filenamePrefix,
|
|
78
|
-
});
|
|
79
|
-
spinner.stop(`Backup saved: ${formatDatabaseBackupResult(result)}`);
|
|
80
|
-
|
|
81
|
-
if (opts.json) {
|
|
82
|
-
console.log(
|
|
83
|
-
JSON.stringify(
|
|
84
|
-
{
|
|
85
|
-
backupFile: result.backupFile,
|
|
86
|
-
sizeBytes: result.sizeBytes,
|
|
87
|
-
prunedCount: result.prunedCount,
|
|
88
|
-
backupDir,
|
|
89
|
-
retentionDays,
|
|
90
|
-
connectionSource: connection.source,
|
|
91
|
-
},
|
|
92
|
-
null,
|
|
93
|
-
2,
|
|
94
|
-
),
|
|
95
|
-
);
|
|
96
|
-
}
|
|
97
|
-
p.outro(pc.green("Backup completed."));
|
|
98
|
-
} catch (err) {
|
|
99
|
-
spinner.stop(pc.red("Backup failed."));
|
|
100
|
-
throw err;
|
|
101
|
-
}
|
|
102
|
-
}
|
package/src/commands/doctor.ts
DELETED
|
@@ -1,203 +0,0 @@
|
|
|
1
|
-
import * as p from "@clack/prompts";
|
|
2
|
-
import pc from "picocolors";
|
|
3
|
-
import type { PaperclipConfig } from "../config/schema.js";
|
|
4
|
-
import { readConfig, resolveConfigPath } from "../config/store.js";
|
|
5
|
-
import {
|
|
6
|
-
agentJwtSecretCheck,
|
|
7
|
-
configCheck,
|
|
8
|
-
databaseCheck,
|
|
9
|
-
deploymentAuthCheck,
|
|
10
|
-
llmCheck,
|
|
11
|
-
logCheck,
|
|
12
|
-
portCheck,
|
|
13
|
-
secretsCheck,
|
|
14
|
-
storageCheck,
|
|
15
|
-
type CheckResult,
|
|
16
|
-
} from "../checks/index.js";
|
|
17
|
-
import { loadPaperclipEnvFile } from "../config/env.js";
|
|
18
|
-
import { printPaperclipCliBanner } from "../utils/banner.js";
|
|
19
|
-
|
|
20
|
-
const STATUS_ICON = {
|
|
21
|
-
pass: pc.green("✓"),
|
|
22
|
-
warn: pc.yellow("!"),
|
|
23
|
-
fail: pc.red("✗"),
|
|
24
|
-
} as const;
|
|
25
|
-
|
|
26
|
-
export async function doctor(opts: {
|
|
27
|
-
config?: string;
|
|
28
|
-
repair?: boolean;
|
|
29
|
-
yes?: boolean;
|
|
30
|
-
}): Promise<{ passed: number; warned: number; failed: number }> {
|
|
31
|
-
printPaperclipCliBanner();
|
|
32
|
-
p.intro(pc.bgCyan(pc.black(" paperclip doctor ")));
|
|
33
|
-
|
|
34
|
-
const configPath = resolveConfigPath(opts.config);
|
|
35
|
-
loadPaperclipEnvFile(configPath);
|
|
36
|
-
const results: CheckResult[] = [];
|
|
37
|
-
|
|
38
|
-
// 1. Config check (must pass before others)
|
|
39
|
-
const cfgResult = configCheck(opts.config);
|
|
40
|
-
results.push(cfgResult);
|
|
41
|
-
printResult(cfgResult);
|
|
42
|
-
|
|
43
|
-
if (cfgResult.status === "fail") {
|
|
44
|
-
return printSummary(results);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
let config: PaperclipConfig;
|
|
48
|
-
try {
|
|
49
|
-
config = readConfig(opts.config)!;
|
|
50
|
-
} catch (err) {
|
|
51
|
-
const readResult: CheckResult = {
|
|
52
|
-
name: "Config file",
|
|
53
|
-
status: "fail",
|
|
54
|
-
message: `Could not read config: ${err instanceof Error ? err.message : String(err)}`,
|
|
55
|
-
canRepair: false,
|
|
56
|
-
repairHint: "Run `paperclipai configure --section database` or `paperclipai onboard`",
|
|
57
|
-
};
|
|
58
|
-
results.push(readResult);
|
|
59
|
-
printResult(readResult);
|
|
60
|
-
return printSummary(results);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// 2. Deployment/auth mode check
|
|
64
|
-
const deploymentAuthResult = deploymentAuthCheck(config);
|
|
65
|
-
results.push(deploymentAuthResult);
|
|
66
|
-
printResult(deploymentAuthResult);
|
|
67
|
-
|
|
68
|
-
// 3. Agent JWT check
|
|
69
|
-
results.push(
|
|
70
|
-
await runRepairableCheck({
|
|
71
|
-
run: () => agentJwtSecretCheck(opts.config),
|
|
72
|
-
configPath,
|
|
73
|
-
opts,
|
|
74
|
-
}),
|
|
75
|
-
);
|
|
76
|
-
|
|
77
|
-
// 4. Secrets adapter check
|
|
78
|
-
results.push(
|
|
79
|
-
await runRepairableCheck({
|
|
80
|
-
run: () => secretsCheck(config, configPath),
|
|
81
|
-
configPath,
|
|
82
|
-
opts,
|
|
83
|
-
}),
|
|
84
|
-
);
|
|
85
|
-
|
|
86
|
-
// 5. Storage check
|
|
87
|
-
results.push(
|
|
88
|
-
await runRepairableCheck({
|
|
89
|
-
run: () => storageCheck(config, configPath),
|
|
90
|
-
configPath,
|
|
91
|
-
opts,
|
|
92
|
-
}),
|
|
93
|
-
);
|
|
94
|
-
|
|
95
|
-
// 6. Database check
|
|
96
|
-
results.push(
|
|
97
|
-
await runRepairableCheck({
|
|
98
|
-
run: () => databaseCheck(config, configPath),
|
|
99
|
-
configPath,
|
|
100
|
-
opts,
|
|
101
|
-
}),
|
|
102
|
-
);
|
|
103
|
-
|
|
104
|
-
// 7. LLM check
|
|
105
|
-
const llmResult = await llmCheck(config);
|
|
106
|
-
results.push(llmResult);
|
|
107
|
-
printResult(llmResult);
|
|
108
|
-
|
|
109
|
-
// 8. Log directory check
|
|
110
|
-
results.push(
|
|
111
|
-
await runRepairableCheck({
|
|
112
|
-
run: () => logCheck(config, configPath),
|
|
113
|
-
configPath,
|
|
114
|
-
opts,
|
|
115
|
-
}),
|
|
116
|
-
);
|
|
117
|
-
|
|
118
|
-
// 9. Port check
|
|
119
|
-
const portResult = await portCheck(config);
|
|
120
|
-
results.push(portResult);
|
|
121
|
-
printResult(portResult);
|
|
122
|
-
|
|
123
|
-
// Summary
|
|
124
|
-
return printSummary(results);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
function printResult(result: CheckResult): void {
|
|
128
|
-
const icon = STATUS_ICON[result.status];
|
|
129
|
-
p.log.message(`${icon} ${pc.bold(result.name)}: ${result.message}`);
|
|
130
|
-
if (result.status !== "pass" && result.repairHint) {
|
|
131
|
-
p.log.message(` ${pc.dim(result.repairHint)}`);
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
async function maybeRepair(
|
|
136
|
-
result: CheckResult,
|
|
137
|
-
opts: { repair?: boolean; yes?: boolean },
|
|
138
|
-
): Promise<boolean> {
|
|
139
|
-
if (result.status === "pass" || !result.canRepair || !result.repair) return false;
|
|
140
|
-
if (!opts.repair) return false;
|
|
141
|
-
|
|
142
|
-
let shouldRepair = opts.yes;
|
|
143
|
-
if (!shouldRepair) {
|
|
144
|
-
const answer = await p.confirm({
|
|
145
|
-
message: `Repair "${result.name}"?`,
|
|
146
|
-
initialValue: true,
|
|
147
|
-
});
|
|
148
|
-
if (p.isCancel(answer)) return false;
|
|
149
|
-
shouldRepair = answer;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
if (shouldRepair) {
|
|
153
|
-
try {
|
|
154
|
-
await result.repair();
|
|
155
|
-
p.log.success(`Repaired: ${result.name}`);
|
|
156
|
-
return true;
|
|
157
|
-
} catch (err) {
|
|
158
|
-
p.log.error(`Repair failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
return false;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
async function runRepairableCheck(input: {
|
|
165
|
-
run: () => CheckResult | Promise<CheckResult>;
|
|
166
|
-
configPath: string;
|
|
167
|
-
opts: { repair?: boolean; yes?: boolean };
|
|
168
|
-
}): Promise<CheckResult> {
|
|
169
|
-
let result = await input.run();
|
|
170
|
-
printResult(result);
|
|
171
|
-
|
|
172
|
-
const repaired = await maybeRepair(result, input.opts);
|
|
173
|
-
if (!repaired) return result;
|
|
174
|
-
|
|
175
|
-
// Repairs may create/update the adjacent .env file or other local resources.
|
|
176
|
-
loadPaperclipEnvFile(input.configPath);
|
|
177
|
-
result = await input.run();
|
|
178
|
-
printResult(result);
|
|
179
|
-
return result;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
function printSummary(results: CheckResult[]): { passed: number; warned: number; failed: number } {
|
|
183
|
-
const passed = results.filter((r) => r.status === "pass").length;
|
|
184
|
-
const warned = results.filter((r) => r.status === "warn").length;
|
|
185
|
-
const failed = results.filter((r) => r.status === "fail").length;
|
|
186
|
-
|
|
187
|
-
const parts: string[] = [];
|
|
188
|
-
parts.push(pc.green(`${passed} passed`));
|
|
189
|
-
if (warned) parts.push(pc.yellow(`${warned} warnings`));
|
|
190
|
-
if (failed) parts.push(pc.red(`${failed} failed`));
|
|
191
|
-
|
|
192
|
-
p.note(parts.join(", "), "Summary");
|
|
193
|
-
|
|
194
|
-
if (failed > 0) {
|
|
195
|
-
p.outro(pc.red("Some checks failed. Fix the issues above and re-run doctor."));
|
|
196
|
-
} else if (warned > 0) {
|
|
197
|
-
p.outro(pc.yellow("All critical checks passed with some warnings."));
|
|
198
|
-
} else {
|
|
199
|
-
p.outro(pc.green("All checks passed!"));
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
return { passed, warned, failed };
|
|
203
|
-
}
|