@ai-coders/installer 0.3.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.
Files changed (127) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/LICENSE +18 -0
  3. package/README.md +64 -0
  4. package/dist/callback-page.d.ts +11 -0
  5. package/dist/callback-page.js +230 -0
  6. package/dist/callback-page.js.map +1 -0
  7. package/dist/clerk-auth.d.ts +18 -0
  8. package/dist/clerk-auth.js +296 -0
  9. package/dist/clerk-auth.js.map +1 -0
  10. package/dist/cli-command.d.ts +10 -0
  11. package/dist/cli-command.js +17 -0
  12. package/dist/cli-command.js.map +1 -0
  13. package/dist/cli.d.ts +2 -0
  14. package/dist/cli.js +84 -0
  15. package/dist/cli.js.map +1 -0
  16. package/dist/i18n.d.ts +52 -0
  17. package/dist/i18n.js +163 -0
  18. package/dist/i18n.js.map +1 -0
  19. package/dist/product-manifest.d.ts +43 -0
  20. package/dist/product-manifest.js +140 -0
  21. package/dist/product-manifest.js.map +1 -0
  22. package/dist/products/second-brain/apply.d.ts +86 -0
  23. package/dist/products/second-brain/apply.js +277 -0
  24. package/dist/products/second-brain/apply.js.map +1 -0
  25. package/dist/products/second-brain/bearer.d.ts +29 -0
  26. package/dist/products/second-brain/bearer.js +78 -0
  27. package/dist/products/second-brain/bearer.js.map +1 -0
  28. package/dist/products/second-brain/bootstrap.d.ts +33 -0
  29. package/dist/products/second-brain/bootstrap.js +39 -0
  30. package/dist/products/second-brain/bootstrap.js.map +1 -0
  31. package/dist/products/second-brain/envfile.d.ts +35 -0
  32. package/dist/products/second-brain/envfile.js +136 -0
  33. package/dist/products/second-brain/envfile.js.map +1 -0
  34. package/dist/products/second-brain/github.d.ts +77 -0
  35. package/dist/products/second-brain/github.js +195 -0
  36. package/dist/products/second-brain/github.js.map +1 -0
  37. package/dist/products/second-brain/hostinger.d.ts +140 -0
  38. package/dist/products/second-brain/hostinger.js +607 -0
  39. package/dist/products/second-brain/hostinger.js.map +1 -0
  40. package/dist/products/second-brain/i18n.d.ts +887 -0
  41. package/dist/products/second-brain/i18n.js +587 -0
  42. package/dist/products/second-brain/i18n.js.map +1 -0
  43. package/dist/products/second-brain/keys.d.ts +5 -0
  44. package/dist/products/second-brain/keys.js +16 -0
  45. package/dist/products/second-brain/keys.js.map +1 -0
  46. package/dist/products/second-brain/main.d.ts +3 -0
  47. package/dist/products/second-brain/main.js +78 -0
  48. package/dist/products/second-brain/main.js.map +1 -0
  49. package/dist/products/second-brain/ports.d.ts +34 -0
  50. package/dist/products/second-brain/ports.js +77 -0
  51. package/dist/products/second-brain/ports.js.map +1 -0
  52. package/dist/products/second-brain/recovery.d.ts +50 -0
  53. package/dist/products/second-brain/recovery.js +96 -0
  54. package/dist/products/second-brain/recovery.js.map +1 -0
  55. package/dist/products/second-brain/sealed-box.d.ts +1 -0
  56. package/dist/products/second-brain/sealed-box.js +11 -0
  57. package/dist/products/second-brain/sealed-box.js.map +1 -0
  58. package/dist/products/second-brain/server.d.ts +143 -0
  59. package/dist/products/second-brain/server.js +280 -0
  60. package/dist/products/second-brain/server.js.map +1 -0
  61. package/dist/products/second-brain/service.d.ts +26 -0
  62. package/dist/products/second-brain/service.js +806 -0
  63. package/dist/products/second-brain/service.js.map +1 -0
  64. package/dist/products/second-brain/ssh.d.ts +35 -0
  65. package/dist/products/second-brain/ssh.js +140 -0
  66. package/dist/products/second-brain/ssh.js.map +1 -0
  67. package/dist/products/second-brain/state.d.ts +27 -0
  68. package/dist/products/second-brain/state.js +60 -0
  69. package/dist/products/second-brain/state.js.map +1 -0
  70. package/dist/products/second-brain/ui/assets/index-BoXpakUt.css +2 -0
  71. package/dist/products/second-brain/ui/assets/index-MgfOpW_R.js +66 -0
  72. package/dist/products/second-brain/ui/index.html +15 -0
  73. package/dist/products/second-brain/verify.d.ts +23 -0
  74. package/dist/products/second-brain/verify.js +59 -0
  75. package/dist/products/second-brain/verify.js.map +1 -0
  76. package/dist/products/severino/apply.d.ts +87 -0
  77. package/dist/products/severino/apply.js +250 -0
  78. package/dist/products/severino/apply.js.map +1 -0
  79. package/dist/products/severino/domain.d.ts +6 -0
  80. package/dist/products/severino/domain.js +20 -0
  81. package/dist/products/severino/domain.js.map +1 -0
  82. package/dist/products/severino/envfile.d.ts +20 -0
  83. package/dist/products/severino/envfile.js +89 -0
  84. package/dist/products/severino/envfile.js.map +1 -0
  85. package/dist/products/severino/github.d.ts +77 -0
  86. package/dist/products/severino/github.js +195 -0
  87. package/dist/products/severino/github.js.map +1 -0
  88. package/dist/products/severino/hostinger.d.ts +140 -0
  89. package/dist/products/severino/hostinger.js +607 -0
  90. package/dist/products/severino/hostinger.js.map +1 -0
  91. package/dist/products/severino/i18n.d.ts +887 -0
  92. package/dist/products/severino/i18n.js +587 -0
  93. package/dist/products/severino/i18n.js.map +1 -0
  94. package/dist/products/severino/keys.d.ts +5 -0
  95. package/dist/products/severino/keys.js +16 -0
  96. package/dist/products/severino/keys.js.map +1 -0
  97. package/dist/products/severino/main.d.ts +3 -0
  98. package/dist/products/severino/main.js +78 -0
  99. package/dist/products/severino/main.js.map +1 -0
  100. package/dist/products/severino/recovery.d.ts +50 -0
  101. package/dist/products/severino/recovery.js +96 -0
  102. package/dist/products/severino/recovery.js.map +1 -0
  103. package/dist/products/severino/sealed-box.d.ts +1 -0
  104. package/dist/products/severino/sealed-box.js +11 -0
  105. package/dist/products/severino/sealed-box.js.map +1 -0
  106. package/dist/products/severino/server.d.ts +123 -0
  107. package/dist/products/severino/server.js +274 -0
  108. package/dist/products/severino/server.js.map +1 -0
  109. package/dist/products/severino/service.d.ts +28 -0
  110. package/dist/products/severino/service.js +752 -0
  111. package/dist/products/severino/service.js.map +1 -0
  112. package/dist/products/severino/slack-manifest.d.ts +3 -0
  113. package/dist/products/severino/slack-manifest.js +45 -0
  114. package/dist/products/severino/slack-manifest.js.map +1 -0
  115. package/dist/products/severino/ssh.d.ts +35 -0
  116. package/dist/products/severino/ssh.js +140 -0
  117. package/dist/products/severino/ssh.js.map +1 -0
  118. package/dist/products/severino/state.d.ts +26 -0
  119. package/dist/products/severino/state.js +61 -0
  120. package/dist/products/severino/state.js.map +1 -0
  121. package/dist/products/severino/ui/assets/index-7S8Hl4jq.js +96 -0
  122. package/dist/products/severino/ui/assets/index-D5kql1Bh.css +2 -0
  123. package/dist/products/severino/ui/index.html +15 -0
  124. package/dist/products/severino/verify.d.ts +22 -0
  125. package/dist/products/severino/verify.js +149 -0
  126. package/dist/products/severino/verify.js.map +1 -0
  127. package/package.json +53 -0
@@ -0,0 +1,15 @@
1
+ <!doctype html>
2
+ <html lang="pt-BR" data-visual-identity="ai-coders">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <meta name="color-scheme" content="dark" />
7
+ <meta name="theme-color" content="#070707" />
8
+ <title>Instalador do Second Brain</title>
9
+ <script type="module" crossorigin src="./assets/index-MgfOpW_R.js"></script>
10
+ <link rel="stylesheet" crossorigin href="./assets/index-BoXpakUt.css">
11
+ </head>
12
+ <body>
13
+ <div id="root"></div>
14
+ </body>
15
+ </html>
@@ -0,0 +1,23 @@
1
+ import { inspectMcpOAuth } from "@invokta/mcp";
2
+ export interface DnsCheckResult {
3
+ readonly matches: boolean;
4
+ readonly domainAddresses: readonly string[];
5
+ readonly vpsAddresses: readonly string[];
6
+ }
7
+ export interface DnsResolver {
8
+ resolve4(hostname: string): Promise<string[]>;
9
+ }
10
+ export declare function checkDns(domain: string, vpsHost: string, resolver?: DnsResolver): Promise<DnsCheckResult>;
11
+ export interface VerificationStep {
12
+ readonly name: string;
13
+ readonly outcome: "ok" | "failed" | "skipped";
14
+ readonly summary: string;
15
+ readonly hint?: string;
16
+ }
17
+ export interface VerificationResult {
18
+ readonly ready: boolean;
19
+ readonly steps: readonly VerificationStep[];
20
+ }
21
+ type Inspector = typeof inspectMcpOAuth;
22
+ export declare function verifyDeployment(publicUrl: string, inspect?: Inspector): Promise<VerificationResult>;
23
+ export {};
@@ -0,0 +1,59 @@
1
+ /**
2
+ * External verification: DNS pointing at the VPS and the public MCP endpoint
3
+ * passing OAuth discovery, via the production dependency @invokta/mcp.
4
+ */
5
+ import dns from "node:dns";
6
+ import { inspectMcpOAuth } from "@invokta/mcp";
7
+ function isIpAddress(value) {
8
+ return /^\d{1,3}(\.\d{1,3}){3}$/.test(value);
9
+ }
10
+ async function resolveSafe(resolver, name) {
11
+ try {
12
+ return await resolver.resolve4(name);
13
+ }
14
+ catch {
15
+ return [];
16
+ }
17
+ }
18
+ export async function checkDns(domain, vpsHost, resolver = dns.promises) {
19
+ const domainAddresses = await resolveSafe(resolver, domain.trim());
20
+ const vpsAddresses = isIpAddress(vpsHost)
21
+ ? [vpsHost]
22
+ : await resolveSafe(resolver, vpsHost);
23
+ const matches = domainAddresses.length > 0 &&
24
+ domainAddresses.some((address) => vpsAddresses.includes(address));
25
+ return { matches, domainAddresses, vpsAddresses };
26
+ }
27
+ export async function verifyDeployment(publicUrl, inspect = inspectMcpOAuth) {
28
+ try {
29
+ const inspection = await inspect({
30
+ transport: "http",
31
+ url: `${publicUrl.replace(/\/$/, "")}/mcp`,
32
+ authentication: { type: "oauth" },
33
+ });
34
+ return {
35
+ ready: inspection.ready,
36
+ steps: inspection.steps.map((step) => ({
37
+ name: step.name,
38
+ outcome: step.outcome,
39
+ summary: step.summary,
40
+ ...(step.hint === undefined ? {} : { hint: step.hint }),
41
+ })),
42
+ };
43
+ }
44
+ catch (error) {
45
+ return {
46
+ ready: false,
47
+ steps: [
48
+ {
49
+ name: "connection",
50
+ outcome: "failed",
51
+ summary: error instanceof Error
52
+ ? error.message
53
+ : "The server could not be reached.",
54
+ },
55
+ ],
56
+ };
57
+ }
58
+ }
59
+ //# sourceMappingURL=verify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify.js","sourceRoot":"","sources":["../../../packages/second-brain/src/verify.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,GAAG,MAAM,UAAU,CAAC;AAE3B,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAY/C,SAAS,WAAW,CAAC,KAAa;IAChC,OAAO,yBAAyB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC/C,CAAC;AAED,KAAK,UAAU,WAAW,CACxB,QAAqB,EACrB,IAAY;IAEZ,IAAI,CAAC;QACH,OAAO,MAAM,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACvC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,MAAc,EACd,OAAe,EACf,QAAQ,GAAgB,GAAG,CAAC,QAAQ;IAEpC,MAAM,eAAe,GAAG,MAAM,WAAW,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;IACnE,MAAM,YAAY,GAAG,WAAW,CAAC,OAAO,CAAC;QACvC,CAAC,CAAC,CAAC,OAAO,CAAC;QACX,CAAC,CAAC,MAAM,WAAW,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACzC,MAAM,OAAO,GACX,eAAe,CAAC,MAAM,GAAG,CAAC;QAC1B,eAAe,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,YAAY,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;IACpE,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,CAAC;AACpD,CAAC;AAgBD,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,SAAiB,EACjB,OAAO,GAAc,eAAe;IAEpC,IAAI,CAAC;QACH,MAAM,UAAU,GAAG,MAAM,OAAO,CAAC;YAC/B,SAAS,EAAE,MAAM;YACjB,GAAG,EAAE,GAAG,SAAS,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM;YAC1C,cAAc,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE;SAClC,CAAC,CAAC;QACH,OAAO;YACL,KAAK,EAAE,UAAU,CAAC,KAAK;YACvB,KAAK,EAAE,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;gBACrC,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,OAAO,EAAE,IAAI,CAAC,OAAO;gBACrB,OAAO,EAAE,IAAI,CAAC,OAAO;gBACrB,GAAG,CAAC,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC;aACxD,CAAC,CAAC;SACJ,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO;YACL,KAAK,EAAE,KAAK;YACZ,KAAK,EAAE;gBACL;oBACE,IAAI,EAAE,YAAY;oBAClB,OAAO,EAAE,QAAQ;oBACjB,OAAO,EACL,KAAK,YAAY,KAAK;wBACpB,CAAC,CAAC,KAAK,CAAC,OAAO;wBACf,CAAC,CAAC,kCAAkC;iBACzC;aACF;SACF,CAAC;IACJ,CAAC;AACH,CAAC"}
@@ -0,0 +1,87 @@
1
+ /**
2
+ * The install pipelines. The install runs entirely from the local machine:
3
+ * it uploads the source tree over SFTP and builds on the VPS, so no registry
4
+ * or GitHub credential is involved. Every effect is injected so the sequences
5
+ * are unit-testable; the server wires real implementations.
6
+ */
7
+ import type { DeployKeyPair } from "./keys.js";
8
+ import type { InstallerLanguage } from "./i18n.js";
9
+ import type { InstallerState } from "./state.js";
10
+ import type { SshCommandResult } from "./ssh.js";
11
+ import type { VerificationResult } from "./verify.js";
12
+ export type InstallStepId = "generate-key" | "connect-vps" | "authorize-key" | "write-env" | "upload-source" | "build-deploy" | "verify-key" | "verify-agent" | "save-state";
13
+ export declare const installStepIds: readonly InstallStepId[];
14
+ export declare const localDeployStepIds: readonly InstallStepId[];
15
+ export type InstallStepStatus = "pending" | "running" | "ok" | "failed" | "skipped";
16
+ export interface InstallStepReport {
17
+ readonly id: InstallStepId;
18
+ status: InstallStepStatus;
19
+ note?: string;
20
+ link?: string;
21
+ }
22
+ export interface InstallInput {
23
+ readonly language: InstallerLanguage;
24
+ readonly repository?: {
25
+ readonly owner: string;
26
+ readonly repo: string;
27
+ } | undefined;
28
+ readonly vps: {
29
+ readonly host: string;
30
+ readonly port: number;
31
+ readonly username: string;
32
+ };
33
+ readonly vpsAuth: {
34
+ readonly kind: "password";
35
+ readonly password: string;
36
+ } | {
37
+ readonly kind: "key";
38
+ readonly privateKey: string;
39
+ };
40
+ readonly domain: string;
41
+ readonly openRouterApiKey: string;
42
+ readonly routeAuthUsername: string;
43
+ readonly routeAuthPassword: string;
44
+ readonly slackBotToken: string;
45
+ readonly slackSigningSecret: string;
46
+ readonly mcpServerUrl: string;
47
+ readonly mcpServerDescription: string;
48
+ readonly mcpConnectorUid: string;
49
+ readonly mcpBearerToken: string;
50
+ }
51
+ export interface LocalDeployInput {
52
+ readonly vps: {
53
+ readonly host: string;
54
+ readonly port: number;
55
+ readonly username: string;
56
+ };
57
+ readonly privateKey: string;
58
+ readonly domain: string;
59
+ }
60
+ export interface SshLike {
61
+ exec(command: string, input?: string): Promise<SshCommandResult>;
62
+ readFileIfExists(path: string): Promise<string | null>;
63
+ writeFile(path: string, content: string | Buffer, mode?: number): Promise<void>;
64
+ close(): void;
65
+ }
66
+ export interface InstallDependencies {
67
+ readonly generateKey: () => Promise<DeployKeyPair>;
68
+ readonly connectSsh: (credentials: {
69
+ host: string;
70
+ port: number;
71
+ username: string;
72
+ auth: InstallInput["vpsAuth"];
73
+ }) => Promise<SshLike>;
74
+ readonly archiveSource: () => Promise<Buffer>;
75
+ readonly isSourceDirty?: (() => Promise<boolean>) | undefined;
76
+ readonly verifyDeployment: (publicUrl: string) => Promise<VerificationResult>;
77
+ readonly saveState: (state: InstallerState) => Promise<void>;
78
+ readonly now: () => Date;
79
+ readonly sleep: (ms: number) => Promise<void>;
80
+ }
81
+ export interface InstallOutcome {
82
+ readonly ok: boolean;
83
+ readonly steps: readonly InstallStepReport[];
84
+ readonly verification?: VerificationResult;
85
+ }
86
+ export declare function runInstall(input: InstallInput, deps: InstallDependencies, onProgress?: (steps: readonly InstallStepReport[]) => void): Promise<InstallOutcome>;
87
+ export declare function runLocalDeploy(input: LocalDeployInput, deps: InstallDependencies, onProgress?: (steps: readonly InstallStepReport[]) => void): Promise<InstallOutcome>;
@@ -0,0 +1,250 @@
1
+ import { mergeVpsEnv } from "./envfile.js";
2
+ import { buildAuthorizedKeysCommand } from "./ssh.js";
3
+ export const installStepIds = [
4
+ "generate-key",
5
+ "connect-vps",
6
+ "authorize-key",
7
+ "write-env",
8
+ "upload-source",
9
+ "build-deploy",
10
+ "verify-key",
11
+ "verify-agent",
12
+ "save-state",
13
+ ];
14
+ export const localDeployStepIds = [
15
+ "connect-vps",
16
+ "upload-source",
17
+ "build-deploy",
18
+ "verify-agent",
19
+ ];
20
+ const envPath = "/opt/severino/.env";
21
+ const tarballPath = "/opt/severino/source.tar.gz";
22
+ const verifyAttempts = 6;
23
+ const verifyDelayMs = 20_000;
24
+ function createStepRunner(ids, onProgress) {
25
+ const steps = ids.map((id) => ({
26
+ id,
27
+ status: "pending",
28
+ }));
29
+ const report = () => onProgress?.(steps.map((item) => ({ ...item })));
30
+ const step = (id) => {
31
+ const found = steps.find((candidate) => candidate.id === id);
32
+ if (found === undefined)
33
+ throw new Error(`Unknown step ${id}`);
34
+ return found;
35
+ };
36
+ return {
37
+ steps,
38
+ step,
39
+ report,
40
+ skip(id, note) {
41
+ const skipped = step(id);
42
+ skipped.status = "skipped";
43
+ if (note !== undefined)
44
+ skipped.note = note;
45
+ report();
46
+ },
47
+ fail(id, message, link) {
48
+ const failed = step(id);
49
+ failed.status = "failed";
50
+ failed.note = message;
51
+ if (link !== undefined)
52
+ failed.link = link;
53
+ for (const remaining of steps) {
54
+ if (remaining.status === "pending")
55
+ remaining.status = "skipped";
56
+ }
57
+ report();
58
+ return { ok: false, steps };
59
+ },
60
+ async run(id, action) {
61
+ step(id).status = "running";
62
+ report();
63
+ try {
64
+ const value = await action();
65
+ step(id).status = "ok";
66
+ report();
67
+ return { ok: true, value };
68
+ }
69
+ catch (error) {
70
+ return {
71
+ ok: false,
72
+ message: error instanceof Error ? error.message : String(error),
73
+ link: error instanceof Error
74
+ ? error.link
75
+ : undefined,
76
+ };
77
+ }
78
+ },
79
+ };
80
+ }
81
+ async function execOrThrow(ssh, command, fallbackMessage) {
82
+ const result = await ssh.exec(command);
83
+ if (result.code !== 0) {
84
+ throw new Error(result.stderr.trim() || fallbackMessage);
85
+ }
86
+ }
87
+ async function uploadSource(ssh, tarball) {
88
+ await execOrThrow(ssh, "mkdir -p /opt/severino", "mkdir failed.");
89
+ await ssh.writeFile(tarballPath, tarball, 0o600);
90
+ // Remove directories the repo owns before extracting so files deleted
91
+ // from the repo cannot linger and end up inside the next image build.
92
+ // The VPS .env is not in the tarball and is never touched.
93
+ await execOrThrow(ssh, "rm -rf /opt/severino/agent /opt/severino/deploy /opt/severino/evals" +
94
+ ` && tar -xzf ${tarballPath} -C /opt/severino && rm -f ${tarballPath}`, "The source upload could not be extracted.");
95
+ }
96
+ async function buildDeploy(ssh) {
97
+ const result = await ssh.exec("SEVERINO_DEPLOY_MODE=build bash /opt/severino/deploy/deploy.sh");
98
+ if (result.code !== 0) {
99
+ // deploy.sh dumps compose status and service logs to stdout on failure,
100
+ // while Docker's pull/build progress floods stderr. Keep the stdout tail
101
+ // (the diagnosis) large and the stderr tail (the compose error line)
102
+ // small so the progress panel shows what actually broke.
103
+ const tail = (text, max) => text.length > max ? text.slice(-max) : text;
104
+ const output = `${tail(result.stdout, 3400)}\n${tail(result.stderr, 600)}`.trim();
105
+ throw new Error(output || "The build on the server failed.");
106
+ }
107
+ }
108
+ async function verifyWithRetries(deps, domain) {
109
+ let verification;
110
+ for (let attempt = 1; attempt <= verifyAttempts; attempt += 1) {
111
+ verification = await deps.verifyDeployment(`https://${domain}`);
112
+ if (verification.ready)
113
+ return verification;
114
+ if (attempt < verifyAttempts)
115
+ await deps.sleep(verifyDelayMs);
116
+ }
117
+ throw new Error(verification?.steps.find((item) => item.outcome === "failed")?.summary ??
118
+ "The server did not pass verification.");
119
+ }
120
+ export async function runInstall(input, deps, onProgress) {
121
+ const runner = createStepRunner(installStepIds, onProgress);
122
+ const generated = await runner.run("generate-key", () => deps.generateKey());
123
+ if (!generated.ok)
124
+ return runner.fail("generate-key", generated.message);
125
+ const keys = generated.value;
126
+ const connected = await runner.run("connect-vps", () => deps.connectSsh({ ...input.vps, auth: input.vpsAuth }));
127
+ if (!connected.ok)
128
+ return runner.fail("connect-vps", connected.message);
129
+ const ssh = connected.value;
130
+ try {
131
+ const authorized = await runner.run("authorize-key", () => execOrThrow(ssh, buildAuthorizedKeysCommand(keys.publicKey), "authorized_keys update failed."));
132
+ if (!authorized.ok)
133
+ return runner.fail("authorize-key", authorized.message);
134
+ const wroteEnv = await runner.run("write-env", async () => {
135
+ const existing = await ssh.readFileIfExists(envPath);
136
+ const merged = mergeVpsEnv({
137
+ existingContent: existing ?? undefined,
138
+ domain: input.domain,
139
+ openRouterApiKey: input.openRouterApiKey,
140
+ routeAuthUsername: input.routeAuthUsername,
141
+ routeAuthPassword: input.routeAuthPassword,
142
+ slackBotToken: input.slackBotToken,
143
+ slackSigningSecret: input.slackSigningSecret,
144
+ mcpServerUrl: input.mcpServerUrl,
145
+ mcpServerDescription: input.mcpServerDescription,
146
+ mcpConnectorUid: input.mcpConnectorUid,
147
+ mcpBearerToken: input.mcpBearerToken,
148
+ });
149
+ await execOrThrow(ssh, "mkdir -p /opt/severino", "mkdir failed.");
150
+ await ssh.writeFile(envPath, merged.content, 0o600);
151
+ });
152
+ if (!wroteEnv.ok)
153
+ return runner.fail("write-env", wroteEnv.message);
154
+ const uploaded = await runner.run("upload-source", async () => {
155
+ const tarball = await deps.archiveSource();
156
+ await uploadSource(ssh, tarball);
157
+ // The archive ships HEAD; uncommitted local edits stay behind. Warn so
158
+ // a member never wonders why a change did not reach the server.
159
+ if ((await deps.isSourceDirty?.()) === true) {
160
+ runner.step("upload-source").note = "uncommitted-changes";
161
+ }
162
+ });
163
+ if (!uploaded.ok)
164
+ return runner.fail("upload-source", uploaded.message);
165
+ const built = await runner.run("build-deploy", () => buildDeploy(ssh));
166
+ if (!built.ok)
167
+ return runner.fail("build-deploy", built.message);
168
+ const keyWorks = await runner.run("verify-key", async () => {
169
+ const session = await deps.connectSsh({
170
+ ...input.vps,
171
+ auth: { kind: "key", privateKey: keys.privateKey },
172
+ });
173
+ session.close();
174
+ });
175
+ if (!keyWorks.ok)
176
+ return runner.fail("verify-key", keyWorks.message);
177
+ let verification;
178
+ const verified = await runner.run("verify-agent", async () => {
179
+ verification = await verifyWithRetries(deps, input.domain);
180
+ });
181
+ if (!verified.ok)
182
+ return runner.fail("verify-agent", verified.message);
183
+ const saved = await runner.run("save-state", async () => {
184
+ const timestamp = deps.now().toISOString();
185
+ await deps.saveState({
186
+ version: 1,
187
+ language: input.language,
188
+ ...(input.repository === undefined
189
+ ? {}
190
+ : { repository: input.repository }),
191
+ vps: input.vps,
192
+ deployKey: keys,
193
+ domain: input.domain,
194
+ installedAt: timestamp,
195
+ updatedAt: timestamp,
196
+ });
197
+ });
198
+ if (!saved.ok)
199
+ return runner.fail("save-state", saved.message);
200
+ runner.report();
201
+ return {
202
+ ok: true,
203
+ steps: runner.steps,
204
+ ...(verification === undefined ? {} : { verification }),
205
+ };
206
+ }
207
+ finally {
208
+ ssh.close();
209
+ }
210
+ }
211
+ export async function runLocalDeploy(input, deps, onProgress) {
212
+ const runner = createStepRunner(localDeployStepIds, onProgress);
213
+ const connected = await runner.run("connect-vps", () => deps.connectSsh({
214
+ ...input.vps,
215
+ auth: { kind: "key", privateKey: input.privateKey },
216
+ }));
217
+ if (!connected.ok)
218
+ return runner.fail("connect-vps", connected.message);
219
+ const ssh = connected.value;
220
+ try {
221
+ const uploaded = await runner.run("upload-source", async () => {
222
+ const tarball = await deps.archiveSource();
223
+ await uploadSource(ssh, tarball);
224
+ if ((await deps.isSourceDirty?.()) === true) {
225
+ runner.step("upload-source").note = "uncommitted-changes";
226
+ }
227
+ });
228
+ if (!uploaded.ok)
229
+ return runner.fail("upload-source", uploaded.message);
230
+ const built = await runner.run("build-deploy", () => buildDeploy(ssh));
231
+ if (!built.ok)
232
+ return runner.fail("build-deploy", built.message);
233
+ let verification;
234
+ const verified = await runner.run("verify-agent", async () => {
235
+ verification = await verifyWithRetries(deps, input.domain);
236
+ });
237
+ if (!verified.ok)
238
+ return runner.fail("verify-agent", verified.message);
239
+ runner.report();
240
+ return {
241
+ ok: true,
242
+ steps: runner.steps,
243
+ ...(verification === undefined ? {} : { verification }),
244
+ };
245
+ }
246
+ finally {
247
+ ssh.close();
248
+ }
249
+ }
250
+ //# sourceMappingURL=apply.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apply.js","sourceRoot":"","sources":["../../../packages/severino/src/apply.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Members paste domains in every shape — with https://, trailing slashes,
3
+ * paths, uppercase. Traefik host routing and the public URL both need a
4
+ * clean hostname, so normalize here.
5
+ */
6
+ export declare function normalizeDomain(value: string): string;
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Members paste domains in every shape — with https://, trailing slashes,
3
+ * paths, uppercase. Traefik host routing and the public URL both need a
4
+ * clean hostname, so normalize here.
5
+ */
6
+ export function normalizeDomain(value) {
7
+ let domain = value.trim().toLowerCase();
8
+ // Strip a leading scheme, tolerating the missing-colon typo (https//x).
9
+ domain = domain.replace(/^[a-z][a-z0-9+.-]*:?\/\//, "");
10
+ domain = domain.split("/")[0] ?? "";
11
+ domain = domain.replace(/\.+$/, "");
12
+ // Requiring a dot rejects scheme fragments such as "https" that would
13
+ // otherwise pass as a syntactically valid single-label hostname.
14
+ if (!domain.includes(".") ||
15
+ !/^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$/.test(domain)) {
16
+ throw new Error("The domain must be a hostname like severino.example.com.");
17
+ }
18
+ return domain;
19
+ }
20
+ //# sourceMappingURL=domain.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"domain.js","sourceRoot":"","sources":["../../../packages/severino/src/domain.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,KAAa;IAC3C,IAAI,MAAM,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACxC,wEAAwE;IACxE,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,0BAA0B,EAAE,EAAE,CAAC,CAAC;IACxD,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACpC,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACpC,sEAAsE;IACtE,iEAAiE;IACjE,IACE,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC;QACrB,CAAC,kCAAkC,CAAC,IAAI,CAAC,MAAM,CAAC,EAChD,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,0DAA0D,CAAC,CAAC;IAC9E,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,20 @@
1
+ import { normalizeDomain } from "./domain.js";
2
+ export { normalizeDomain };
3
+ export declare function parseEnvContent(text: string): Record<string, string>;
4
+ export interface MergeVpsEnvInput {
5
+ readonly existingContent?: string | undefined;
6
+ readonly domain: string;
7
+ readonly openRouterApiKey: string;
8
+ readonly routeAuthUsername: string;
9
+ readonly routeAuthPassword: string;
10
+ readonly slackBotToken: string;
11
+ readonly slackSigningSecret: string;
12
+ readonly mcpServerUrl: string;
13
+ readonly mcpServerDescription: string;
14
+ readonly mcpConnectorUid: string;
15
+ readonly mcpBearerToken: string;
16
+ }
17
+ export interface MergeVpsEnvResult {
18
+ readonly content: string;
19
+ }
20
+ export declare function mergeVpsEnv(input: MergeVpsEnvInput): MergeVpsEnvResult;
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Renders and merges the VPS /opt/severino/.env file. Merging preserves the
3
+ * deploy-managed image pins and passes through unknown operator-added
4
+ * variables such as OPENROUTER_MODEL.
5
+ */
6
+ import { parseEnv } from "node:util";
7
+ import { normalizeDomain } from "./domain.js";
8
+ export { normalizeDomain };
9
+ export function parseEnvContent(text) {
10
+ return { ...parseEnv(text) };
11
+ }
12
+ const managedKeys = [
13
+ "OPENROUTER_API_KEY",
14
+ "SEVERINO_PUBLIC_URL",
15
+ "SEVERINO_PUBLIC_HOST",
16
+ "ROUTE_AUTH_BASIC_USER",
17
+ "ROUTE_AUTH_BASIC_PASSWORD",
18
+ "MCP_SERVER_URL",
19
+ "MCP_SERVER_DESCRIPTION",
20
+ "MCP_CONNECTOR_UID",
21
+ "MCP_BEARER_TOKEN",
22
+ "SLACK_BOT_TOKEN",
23
+ "SLACK_SIGNING_SECRET",
24
+ "SEVERINO_IMAGE",
25
+ "SEVERINO_IMAGE_TAG",
26
+ ];
27
+ function assertSafeValue(name, value) {
28
+ if (value.includes("\n") || value.includes("\r") || value.includes("\0")) {
29
+ throw new Error(`The value for ${name} must not contain line breaks.`);
30
+ }
31
+ }
32
+ export function mergeVpsEnv(input) {
33
+ const existing = input.existingContent === undefined
34
+ ? {}
35
+ : parseEnvContent(input.existingContent);
36
+ const domain = normalizeDomain(input.domain);
37
+ const values = {
38
+ OPENROUTER_API_KEY: input.openRouterApiKey,
39
+ SEVERINO_PUBLIC_URL: `https://${domain}`,
40
+ SEVERINO_PUBLIC_HOST: domain,
41
+ ROUTE_AUTH_BASIC_USER: input.routeAuthUsername,
42
+ ROUTE_AUTH_BASIC_PASSWORD: input.routeAuthPassword,
43
+ MCP_SERVER_URL: input.mcpServerUrl,
44
+ MCP_SERVER_DESCRIPTION: input.mcpServerDescription,
45
+ MCP_CONNECTOR_UID: input.mcpConnectorUid,
46
+ MCP_BEARER_TOKEN: input.mcpBearerToken,
47
+ SLACK_BOT_TOKEN: input.slackBotToken,
48
+ SLACK_SIGNING_SECRET: input.slackSigningSecret,
49
+ SEVERINO_IMAGE: existing["SEVERINO_IMAGE"] ?? "severino",
50
+ SEVERINO_IMAGE_TAG: existing["SEVERINO_IMAGE_TAG"] ?? "local",
51
+ };
52
+ for (const [name, value] of Object.entries(values)) {
53
+ assertSafeValue(name, value);
54
+ }
55
+ const unknownEntries = Object.entries(existing).filter(([key]) => !managedKeys.includes(key));
56
+ for (const [name, value] of unknownEntries) {
57
+ assertSafeValue(name, value);
58
+ }
59
+ const lines = [
60
+ "# Required — full variable reference: .env.example in the repo.",
61
+ `OPENROUTER_API_KEY=${values["OPENROUTER_API_KEY"]}`,
62
+ `SEVERINO_PUBLIC_URL=${values["SEVERINO_PUBLIC_URL"]}`,
63
+ `SEVERINO_PUBLIC_HOST=${values["SEVERINO_PUBLIC_HOST"]}`,
64
+ `ROUTE_AUTH_BASIC_USER=${values["ROUTE_AUTH_BASIC_USER"]}`,
65
+ `ROUTE_AUTH_BASIC_PASSWORD=${values["ROUTE_AUTH_BASIC_PASSWORD"]}`,
66
+ "",
67
+ "# Optional integrations — empty disables each one:",
68
+ `MCP_SERVER_URL=${values["MCP_SERVER_URL"]}`,
69
+ `MCP_SERVER_DESCRIPTION=${values["MCP_SERVER_DESCRIPTION"]}`,
70
+ `MCP_CONNECTOR_UID=${values["MCP_CONNECTOR_UID"]}`,
71
+ `MCP_BEARER_TOKEN=${values["MCP_BEARER_TOKEN"]}`,
72
+ `SLACK_BOT_TOKEN=${values["SLACK_BOT_TOKEN"]}`,
73
+ `SLACK_SIGNING_SECRET=${values["SLACK_SIGNING_SECRET"]}`,
74
+ "",
75
+ "# Managed by deploys — do not edit:",
76
+ `SEVERINO_IMAGE=${values["SEVERINO_IMAGE"]}`,
77
+ `SEVERINO_IMAGE_TAG=${values["SEVERINO_IMAGE_TAG"]}`,
78
+ ];
79
+ if (unknownEntries.length > 0) {
80
+ lines.push("");
81
+ for (const [name, value] of unknownEntries) {
82
+ lines.push(`${name}=${value}`);
83
+ }
84
+ }
85
+ return {
86
+ content: `${lines.join("\n")}\n`,
87
+ };
88
+ }
89
+ //# sourceMappingURL=envfile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"envfile.js","sourceRoot":"","sources":["../../../packages/severino/src/envfile.ts"],"names":[],"mappings":"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"}