offwatch 0.5.12 → 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 +18 -11
- 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
package/src/index.ts
DELETED
|
@@ -1,182 +0,0 @@
|
|
|
1
|
-
import { Command } from "commander";
|
|
2
|
-
import { onboard } from "./commands/onboard.js";
|
|
3
|
-
import { doctor } from "./commands/doctor.js";
|
|
4
|
-
import { envCommand } from "./commands/env.js";
|
|
5
|
-
import { configure } from "./commands/configure.js";
|
|
6
|
-
import { addAllowedHostname } from "./commands/allowed-hostname.js";
|
|
7
|
-
import { heartbeatRun } from "./commands/heartbeat-run.js";
|
|
8
|
-
import { runCommand } from "./commands/run.js";
|
|
9
|
-
import { bootstrapCeoInvite } from "./commands/auth-bootstrap-ceo.js";
|
|
10
|
-
import { dbBackupCommand } from "./commands/db-backup.js";
|
|
11
|
-
import { registerContextCommands } from "./commands/client/context.js";
|
|
12
|
-
import { registerCompanyCommands } from "./commands/client/company.js";
|
|
13
|
-
import { registerIssueCommands } from "./commands/client/issue.js";
|
|
14
|
-
import { registerAgentCommands } from "./commands/client/agent.js";
|
|
15
|
-
import { registerApprovalCommands } from "./commands/client/approval.js";
|
|
16
|
-
import { registerActivityCommands } from "./commands/client/activity.js";
|
|
17
|
-
import { registerDashboardCommands } from "./commands/client/dashboard.js";
|
|
18
|
-
import { registerRoutineCommands } from "./commands/routines.js";
|
|
19
|
-
import { registerFeedbackCommands } from "./commands/client/feedback.js";
|
|
20
|
-
import { applyDataDirOverride, type DataDirOptionLike } from "./config/data-dir.js";
|
|
21
|
-
import { loadPaperclipEnvFile } from "./config/env.js";
|
|
22
|
-
import { initTelemetryFromConfigFile, flushTelemetry } from "./telemetry.js";
|
|
23
|
-
import { registerWorktreeCommands } from "./commands/worktree.js";
|
|
24
|
-
import { registerPluginCommands } from "./commands/client/plugin.js";
|
|
25
|
-
import { registerClientAuthCommands } from "./commands/client/auth.js";
|
|
26
|
-
import { cliVersion } from "./version.js";
|
|
27
|
-
|
|
28
|
-
const program = new Command();
|
|
29
|
-
const DATA_DIR_OPTION_HELP =
|
|
30
|
-
"Paperclip data directory root (isolates state from ~/.paperclip)";
|
|
31
|
-
|
|
32
|
-
program
|
|
33
|
-
.name("paperclipai")
|
|
34
|
-
.description("Paperclip CLI — setup, diagnose, and configure your instance")
|
|
35
|
-
.version(cliVersion);
|
|
36
|
-
|
|
37
|
-
program.hook("preAction", (_thisCommand, actionCommand) => {
|
|
38
|
-
const options = actionCommand.optsWithGlobals() as DataDirOptionLike;
|
|
39
|
-
const optionNames = new Set(actionCommand.options.map((option) => option.attributeName()));
|
|
40
|
-
applyDataDirOverride(options, {
|
|
41
|
-
hasConfigOption: optionNames.has("config"),
|
|
42
|
-
hasContextOption: optionNames.has("context"),
|
|
43
|
-
});
|
|
44
|
-
loadPaperclipEnvFile(options.config);
|
|
45
|
-
initTelemetryFromConfigFile(options.config);
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
program
|
|
49
|
-
.command("onboard")
|
|
50
|
-
.description("Interactive first-run setup wizard")
|
|
51
|
-
.option("-c, --config <path>", "Path to config file")
|
|
52
|
-
.option("-d, --data-dir <path>", DATA_DIR_OPTION_HELP)
|
|
53
|
-
.option("--bind <mode>", "Quickstart reachability preset (loopback, lan, tailnet)")
|
|
54
|
-
.option("-y, --yes", "Accept quickstart defaults (trusted local loopback unless --bind is set) and start immediately", false)
|
|
55
|
-
.option("--run", "Start Paperclip immediately after saving config", false)
|
|
56
|
-
.action(onboard);
|
|
57
|
-
|
|
58
|
-
program
|
|
59
|
-
.command("doctor")
|
|
60
|
-
.description("Run diagnostic checks on your Paperclip setup")
|
|
61
|
-
.option("-c, --config <path>", "Path to config file")
|
|
62
|
-
.option("-d, --data-dir <path>", DATA_DIR_OPTION_HELP)
|
|
63
|
-
.option("--repair", "Attempt to repair issues automatically")
|
|
64
|
-
.alias("--fix")
|
|
65
|
-
.option("-y, --yes", "Skip repair confirmation prompts")
|
|
66
|
-
.action(async (opts) => {
|
|
67
|
-
await doctor(opts);
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
program
|
|
71
|
-
.command("env")
|
|
72
|
-
.description("Print environment variables for deployment")
|
|
73
|
-
.option("-c, --config <path>", "Path to config file")
|
|
74
|
-
.option("-d, --data-dir <path>", DATA_DIR_OPTION_HELP)
|
|
75
|
-
.action(envCommand);
|
|
76
|
-
|
|
77
|
-
program
|
|
78
|
-
.command("configure")
|
|
79
|
-
.description("Update configuration sections")
|
|
80
|
-
.option("-c, --config <path>", "Path to config file")
|
|
81
|
-
.option("-d, --data-dir <path>", DATA_DIR_OPTION_HELP)
|
|
82
|
-
.option("-s, --section <section>", "Section to configure (llm, database, logging, server, storage, secrets)")
|
|
83
|
-
.action(configure);
|
|
84
|
-
|
|
85
|
-
program
|
|
86
|
-
.command("db:backup")
|
|
87
|
-
.description("Create a one-off database backup using current config")
|
|
88
|
-
.option("-c, --config <path>", "Path to config file")
|
|
89
|
-
.option("-d, --data-dir <path>", DATA_DIR_OPTION_HELP)
|
|
90
|
-
.option("--dir <path>", "Backup output directory (overrides config)")
|
|
91
|
-
.option("--retention-days <days>", "Retention window used for pruning", (value) => Number(value))
|
|
92
|
-
.option("--filename-prefix <prefix>", "Backup filename prefix", "paperclip")
|
|
93
|
-
.option("--json", "Print backup metadata as JSON")
|
|
94
|
-
.action(async (opts) => {
|
|
95
|
-
await dbBackupCommand(opts);
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
program
|
|
99
|
-
.command("allowed-hostname")
|
|
100
|
-
.description("Allow a hostname for authenticated/private mode access")
|
|
101
|
-
.argument("<host>", "Hostname to allow (for example dotta-macbook-pro)")
|
|
102
|
-
.option("-c, --config <path>", "Path to config file")
|
|
103
|
-
.option("-d, --data-dir <path>", DATA_DIR_OPTION_HELP)
|
|
104
|
-
.action(addAllowedHostname);
|
|
105
|
-
|
|
106
|
-
program
|
|
107
|
-
.command("run")
|
|
108
|
-
.description("Bootstrap local setup (onboard + doctor) and run Paperclip")
|
|
109
|
-
.option("-c, --config <path>", "Path to config file")
|
|
110
|
-
.option("-d, --data-dir <path>", DATA_DIR_OPTION_HELP)
|
|
111
|
-
.option("-i, --instance <id>", "Local instance id (default: default)")
|
|
112
|
-
.option("--bind <mode>", "On first run, use onboarding reachability preset (loopback, lan, tailnet)")
|
|
113
|
-
.option("--repair", "Attempt automatic repairs during doctor", true)
|
|
114
|
-
.option("--no-repair", "Disable automatic repairs during doctor")
|
|
115
|
-
.action(runCommand);
|
|
116
|
-
|
|
117
|
-
const heartbeat = program.command("heartbeat").description("Heartbeat utilities");
|
|
118
|
-
|
|
119
|
-
heartbeat
|
|
120
|
-
.command("run")
|
|
121
|
-
.description("Run one agent heartbeat and stream live logs")
|
|
122
|
-
.requiredOption("-a, --agent-id <agentId>", "Agent ID to invoke")
|
|
123
|
-
.option("-c, --config <path>", "Path to config file")
|
|
124
|
-
.option("-d, --data-dir <path>", DATA_DIR_OPTION_HELP)
|
|
125
|
-
.option("--context <path>", "Path to CLI context file")
|
|
126
|
-
.option("--profile <name>", "CLI context profile name")
|
|
127
|
-
.option("--api-base <url>", "Base URL for the Paperclip server API")
|
|
128
|
-
.option("--api-key <token>", "Bearer token for agent-authenticated calls")
|
|
129
|
-
.option(
|
|
130
|
-
"--source <source>",
|
|
131
|
-
"Invocation source (timer | assignment | on_demand | automation)",
|
|
132
|
-
"on_demand",
|
|
133
|
-
)
|
|
134
|
-
.option("--trigger <trigger>", "Trigger detail (manual | ping | callback | system)", "manual")
|
|
135
|
-
.option("--timeout-ms <ms>", "Max time to wait before giving up", "0")
|
|
136
|
-
.option("--json", "Output raw JSON where applicable")
|
|
137
|
-
.option("--debug", "Show raw adapter stdout/stderr JSON chunks")
|
|
138
|
-
.action(heartbeatRun);
|
|
139
|
-
|
|
140
|
-
registerContextCommands(program);
|
|
141
|
-
registerCompanyCommands(program);
|
|
142
|
-
registerIssueCommands(program);
|
|
143
|
-
registerAgentCommands(program);
|
|
144
|
-
registerApprovalCommands(program);
|
|
145
|
-
registerActivityCommands(program);
|
|
146
|
-
registerDashboardCommands(program);
|
|
147
|
-
registerRoutineCommands(program);
|
|
148
|
-
registerFeedbackCommands(program);
|
|
149
|
-
registerWorktreeCommands(program);
|
|
150
|
-
registerPluginCommands(program);
|
|
151
|
-
|
|
152
|
-
const auth = program.command("auth").description("Authentication and bootstrap utilities");
|
|
153
|
-
|
|
154
|
-
auth
|
|
155
|
-
.command("bootstrap-ceo")
|
|
156
|
-
.description("Create a one-time bootstrap invite URL for first instance admin")
|
|
157
|
-
.option("-c, --config <path>", "Path to config file")
|
|
158
|
-
.option("-d, --data-dir <path>", DATA_DIR_OPTION_HELP)
|
|
159
|
-
.option("--force", "Create new invite even if admin already exists", false)
|
|
160
|
-
.option("--expires-hours <hours>", "Invite expiration window in hours", (value) => Number(value))
|
|
161
|
-
.option("--base-url <url>", "Public base URL used to print invite link")
|
|
162
|
-
.action(bootstrapCeoInvite);
|
|
163
|
-
|
|
164
|
-
registerClientAuthCommands(auth);
|
|
165
|
-
|
|
166
|
-
async function main(): Promise<void> {
|
|
167
|
-
let failed = false;
|
|
168
|
-
try {
|
|
169
|
-
await program.parseAsync();
|
|
170
|
-
} catch (err) {
|
|
171
|
-
failed = true;
|
|
172
|
-
console.error(err instanceof Error ? err.message : String(err));
|
|
173
|
-
} finally {
|
|
174
|
-
await flushTelemetry();
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
if (failed) {
|
|
178
|
-
process.exit(1);
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
void main();
|
package/src/prompts/database.ts
DELETED
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
import * as p from "@clack/prompts";
|
|
2
|
-
import type { DatabaseConfig } from "../config/schema.js";
|
|
3
|
-
import {
|
|
4
|
-
resolveDefaultBackupDir,
|
|
5
|
-
resolveDefaultEmbeddedPostgresDir,
|
|
6
|
-
resolvePaperclipInstanceId,
|
|
7
|
-
} from "../config/home.js";
|
|
8
|
-
|
|
9
|
-
export async function promptDatabase(current?: DatabaseConfig): Promise<DatabaseConfig> {
|
|
10
|
-
const instanceId = resolvePaperclipInstanceId();
|
|
11
|
-
const defaultEmbeddedDir = resolveDefaultEmbeddedPostgresDir(instanceId);
|
|
12
|
-
const defaultBackupDir = resolveDefaultBackupDir(instanceId);
|
|
13
|
-
const base: DatabaseConfig = current ?? {
|
|
14
|
-
mode: "embedded-postgres",
|
|
15
|
-
embeddedPostgresDataDir: defaultEmbeddedDir,
|
|
16
|
-
embeddedPostgresPort: 54329,
|
|
17
|
-
backup: {
|
|
18
|
-
enabled: true,
|
|
19
|
-
intervalMinutes: 60,
|
|
20
|
-
retentionDays: 30,
|
|
21
|
-
dir: defaultBackupDir,
|
|
22
|
-
},
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
const mode = await p.select({
|
|
26
|
-
message: "Database mode",
|
|
27
|
-
options: [
|
|
28
|
-
{ value: "embedded-postgres" as const, label: "Embedded PostgreSQL (managed locally)", hint: "recommended" },
|
|
29
|
-
{ value: "postgres" as const, label: "PostgreSQL (external server)" },
|
|
30
|
-
],
|
|
31
|
-
initialValue: base.mode,
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
if (p.isCancel(mode)) {
|
|
35
|
-
p.cancel("Setup cancelled.");
|
|
36
|
-
process.exit(0);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
let connectionString: string | undefined = base.connectionString;
|
|
40
|
-
let embeddedPostgresDataDir = base.embeddedPostgresDataDir || defaultEmbeddedDir;
|
|
41
|
-
let embeddedPostgresPort = base.embeddedPostgresPort || 54329;
|
|
42
|
-
|
|
43
|
-
if (mode === "postgres") {
|
|
44
|
-
const value = await p.text({
|
|
45
|
-
message: "PostgreSQL connection string",
|
|
46
|
-
defaultValue: base.connectionString ?? "",
|
|
47
|
-
placeholder: "postgres://user:pass@localhost:5432/paperclip",
|
|
48
|
-
validate: (val) => {
|
|
49
|
-
if (!val) return "Connection string is required for PostgreSQL mode";
|
|
50
|
-
if (!val.startsWith("postgres")) return "Must be a postgres:// or postgresql:// URL";
|
|
51
|
-
},
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
if (p.isCancel(value)) {
|
|
55
|
-
p.cancel("Setup cancelled.");
|
|
56
|
-
process.exit(0);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
connectionString = value;
|
|
60
|
-
} else {
|
|
61
|
-
const dataDir = await p.text({
|
|
62
|
-
message: "Embedded PostgreSQL data directory",
|
|
63
|
-
defaultValue: base.embeddedPostgresDataDir || defaultEmbeddedDir,
|
|
64
|
-
placeholder: defaultEmbeddedDir,
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
if (p.isCancel(dataDir)) {
|
|
68
|
-
p.cancel("Setup cancelled.");
|
|
69
|
-
process.exit(0);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
embeddedPostgresDataDir = dataDir || defaultEmbeddedDir;
|
|
73
|
-
|
|
74
|
-
const portValue = await p.text({
|
|
75
|
-
message: "Embedded PostgreSQL port",
|
|
76
|
-
defaultValue: String(base.embeddedPostgresPort || 54329),
|
|
77
|
-
placeholder: "54329",
|
|
78
|
-
validate: (val) => {
|
|
79
|
-
const n = Number(val);
|
|
80
|
-
if (!Number.isInteger(n) || n < 1 || n > 65535) return "Port must be an integer between 1 and 65535";
|
|
81
|
-
},
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
if (p.isCancel(portValue)) {
|
|
85
|
-
p.cancel("Setup cancelled.");
|
|
86
|
-
process.exit(0);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
embeddedPostgresPort = Number(portValue || "54329");
|
|
90
|
-
connectionString = undefined;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
const backupEnabled = await p.confirm({
|
|
94
|
-
message: "Enable automatic database backups?",
|
|
95
|
-
initialValue: base.backup.enabled,
|
|
96
|
-
});
|
|
97
|
-
if (p.isCancel(backupEnabled)) {
|
|
98
|
-
p.cancel("Setup cancelled.");
|
|
99
|
-
process.exit(0);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
const backupDirInput = await p.text({
|
|
103
|
-
message: "Backup directory",
|
|
104
|
-
defaultValue: base.backup.dir || defaultBackupDir,
|
|
105
|
-
placeholder: defaultBackupDir,
|
|
106
|
-
validate: (val) => (!val || val.trim().length === 0 ? "Backup directory is required" : undefined),
|
|
107
|
-
});
|
|
108
|
-
if (p.isCancel(backupDirInput)) {
|
|
109
|
-
p.cancel("Setup cancelled.");
|
|
110
|
-
process.exit(0);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
const backupIntervalInput = await p.text({
|
|
114
|
-
message: "Backup interval (minutes)",
|
|
115
|
-
defaultValue: String(base.backup.intervalMinutes || 60),
|
|
116
|
-
placeholder: "60",
|
|
117
|
-
validate: (val) => {
|
|
118
|
-
const n = Number(val);
|
|
119
|
-
if (!Number.isInteger(n) || n < 1) return "Interval must be a positive integer";
|
|
120
|
-
if (n > 10080) return "Interval must be 10080 minutes (7 days) or less";
|
|
121
|
-
return undefined;
|
|
122
|
-
},
|
|
123
|
-
});
|
|
124
|
-
if (p.isCancel(backupIntervalInput)) {
|
|
125
|
-
p.cancel("Setup cancelled.");
|
|
126
|
-
process.exit(0);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
const backupRetentionInput = await p.text({
|
|
130
|
-
message: "Backup retention (days)",
|
|
131
|
-
defaultValue: String(base.backup.retentionDays || 30),
|
|
132
|
-
placeholder: "30",
|
|
133
|
-
validate: (val) => {
|
|
134
|
-
const n = Number(val);
|
|
135
|
-
if (!Number.isInteger(n) || n < 1) return "Retention must be a positive integer";
|
|
136
|
-
if (n > 3650) return "Retention must be 3650 days or less";
|
|
137
|
-
return undefined;
|
|
138
|
-
},
|
|
139
|
-
});
|
|
140
|
-
if (p.isCancel(backupRetentionInput)) {
|
|
141
|
-
p.cancel("Setup cancelled.");
|
|
142
|
-
process.exit(0);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
return {
|
|
146
|
-
mode,
|
|
147
|
-
connectionString,
|
|
148
|
-
embeddedPostgresDataDir,
|
|
149
|
-
embeddedPostgresPort,
|
|
150
|
-
backup: {
|
|
151
|
-
enabled: backupEnabled,
|
|
152
|
-
intervalMinutes: Number(backupIntervalInput || "60"),
|
|
153
|
-
retentionDays: Number(backupRetentionInput || "30"),
|
|
154
|
-
dir: backupDirInput || defaultBackupDir,
|
|
155
|
-
},
|
|
156
|
-
};
|
|
157
|
-
}
|
package/src/prompts/llm.ts
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import * as p from "@clack/prompts";
|
|
2
|
-
import type { LlmConfig } from "../config/schema.js";
|
|
3
|
-
|
|
4
|
-
export async function promptLlm(): Promise<LlmConfig | undefined> {
|
|
5
|
-
const configureLlm = await p.confirm({
|
|
6
|
-
message: "Configure an LLM provider now?",
|
|
7
|
-
initialValue: false,
|
|
8
|
-
});
|
|
9
|
-
|
|
10
|
-
if (p.isCancel(configureLlm)) {
|
|
11
|
-
p.cancel("Setup cancelled.");
|
|
12
|
-
process.exit(0);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
if (!configureLlm) return undefined;
|
|
16
|
-
|
|
17
|
-
const provider = await p.select({
|
|
18
|
-
message: "LLM provider",
|
|
19
|
-
options: [
|
|
20
|
-
{ value: "claude" as const, label: "Claude (Anthropic)" },
|
|
21
|
-
{ value: "openai" as const, label: "OpenAI" },
|
|
22
|
-
],
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
if (p.isCancel(provider)) {
|
|
26
|
-
p.cancel("Setup cancelled.");
|
|
27
|
-
process.exit(0);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const apiKey = await p.password({
|
|
31
|
-
message: `${provider === "claude" ? "Anthropic" : "OpenAI"} API key`,
|
|
32
|
-
validate: (val) => {
|
|
33
|
-
if (!val) return "API key is required";
|
|
34
|
-
},
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
if (p.isCancel(apiKey)) {
|
|
38
|
-
p.cancel("Setup cancelled.");
|
|
39
|
-
process.exit(0);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
return { provider, apiKey };
|
|
43
|
-
}
|
package/src/prompts/logging.ts
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import * as p from "@clack/prompts";
|
|
2
|
-
import type { LoggingConfig } from "../config/schema.js";
|
|
3
|
-
import { resolveDefaultLogsDir, resolvePaperclipInstanceId } from "../config/home.js";
|
|
4
|
-
|
|
5
|
-
export async function promptLogging(): Promise<LoggingConfig> {
|
|
6
|
-
const defaultLogDir = resolveDefaultLogsDir(resolvePaperclipInstanceId());
|
|
7
|
-
const mode = await p.select({
|
|
8
|
-
message: "Logging mode",
|
|
9
|
-
options: [
|
|
10
|
-
{ value: "file" as const, label: "File-based logging", hint: "recommended" },
|
|
11
|
-
{ value: "cloud" as const, label: "Cloud logging", hint: "coming soon" },
|
|
12
|
-
],
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
if (p.isCancel(mode)) {
|
|
16
|
-
p.cancel("Setup cancelled.");
|
|
17
|
-
process.exit(0);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
if (mode === "file") {
|
|
21
|
-
const logDir = await p.text({
|
|
22
|
-
message: "Log directory",
|
|
23
|
-
defaultValue: defaultLogDir,
|
|
24
|
-
placeholder: defaultLogDir,
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
if (p.isCancel(logDir)) {
|
|
28
|
-
p.cancel("Setup cancelled.");
|
|
29
|
-
process.exit(0);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
return { mode: "file", logDir: logDir || defaultLogDir };
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
p.note("Cloud logging is coming soon. Using file-based logging for now.");
|
|
36
|
-
return { mode: "file", logDir: defaultLogDir };
|
|
37
|
-
}
|
package/src/prompts/secrets.ts
DELETED
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
import * as p from "@clack/prompts";
|
|
2
|
-
import type { SecretProvider } from "@paperclipai/shared";
|
|
3
|
-
import type { SecretsConfig } from "../config/schema.js";
|
|
4
|
-
import { resolveDefaultSecretsKeyFilePath, resolvePaperclipInstanceId } from "../config/home.js";
|
|
5
|
-
|
|
6
|
-
function defaultKeyFilePath(): string {
|
|
7
|
-
return resolveDefaultSecretsKeyFilePath(resolvePaperclipInstanceId());
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export function defaultSecretsConfig(): SecretsConfig {
|
|
11
|
-
const keyFilePath = defaultKeyFilePath();
|
|
12
|
-
return {
|
|
13
|
-
provider: "local_encrypted",
|
|
14
|
-
strictMode: false,
|
|
15
|
-
localEncrypted: {
|
|
16
|
-
keyFilePath,
|
|
17
|
-
},
|
|
18
|
-
};
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export async function promptSecrets(current?: SecretsConfig): Promise<SecretsConfig> {
|
|
22
|
-
const base = current ?? defaultSecretsConfig();
|
|
23
|
-
|
|
24
|
-
const provider = await p.select({
|
|
25
|
-
message: "Secrets provider",
|
|
26
|
-
options: [
|
|
27
|
-
{
|
|
28
|
-
value: "local_encrypted" as const,
|
|
29
|
-
label: "Local encrypted (recommended)",
|
|
30
|
-
hint: "best for single-developer installs",
|
|
31
|
-
},
|
|
32
|
-
{
|
|
33
|
-
value: "aws_secrets_manager" as const,
|
|
34
|
-
label: "AWS Secrets Manager",
|
|
35
|
-
hint: "requires external adapter integration",
|
|
36
|
-
},
|
|
37
|
-
{
|
|
38
|
-
value: "gcp_secret_manager" as const,
|
|
39
|
-
label: "GCP Secret Manager",
|
|
40
|
-
hint: "requires external adapter integration",
|
|
41
|
-
},
|
|
42
|
-
{
|
|
43
|
-
value: "vault" as const,
|
|
44
|
-
label: "HashiCorp Vault",
|
|
45
|
-
hint: "requires external adapter integration",
|
|
46
|
-
},
|
|
47
|
-
],
|
|
48
|
-
initialValue: base.provider,
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
if (p.isCancel(provider)) {
|
|
52
|
-
p.cancel("Setup cancelled.");
|
|
53
|
-
process.exit(0);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
const strictMode = await p.confirm({
|
|
57
|
-
message: "Require secret refs for sensitive env vars?",
|
|
58
|
-
initialValue: base.strictMode,
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
if (p.isCancel(strictMode)) {
|
|
62
|
-
p.cancel("Setup cancelled.");
|
|
63
|
-
process.exit(0);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const fallbackDefault = defaultKeyFilePath();
|
|
67
|
-
let keyFilePath = base.localEncrypted.keyFilePath || fallbackDefault;
|
|
68
|
-
if (provider === "local_encrypted") {
|
|
69
|
-
const keyPath = await p.text({
|
|
70
|
-
message: "Local encrypted key file path",
|
|
71
|
-
defaultValue: keyFilePath,
|
|
72
|
-
placeholder: fallbackDefault,
|
|
73
|
-
validate: (value) => {
|
|
74
|
-
if (!value || value.trim().length === 0) return "Key file path is required";
|
|
75
|
-
},
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
if (p.isCancel(keyPath)) {
|
|
79
|
-
p.cancel("Setup cancelled.");
|
|
80
|
-
process.exit(0);
|
|
81
|
-
}
|
|
82
|
-
keyFilePath = keyPath.trim();
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
if (provider !== "local_encrypted") {
|
|
86
|
-
p.note(
|
|
87
|
-
`${provider} is not fully wired in this build yet. Keep local_encrypted unless you are actively implementing that adapter.`,
|
|
88
|
-
"Heads up",
|
|
89
|
-
);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
return {
|
|
93
|
-
provider: provider as SecretProvider,
|
|
94
|
-
strictMode,
|
|
95
|
-
localEncrypted: {
|
|
96
|
-
keyFilePath,
|
|
97
|
-
},
|
|
98
|
-
};
|
|
99
|
-
}
|