@knowzai/cli 0.4.0 → 0.5.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 +68 -0
- package/assets/portable/releases.json +11 -2
- package/assets/selfhosted/docker-compose.yml +8 -2
- package/assets/selfhosted/releases.json +97 -5
- package/bin/run.js +2 -0
- package/dist/.tsbuildinfo +1 -1
- package/dist/base-command.d.ts +2 -0
- package/dist/base-command.d.ts.map +1 -1
- package/dist/base-command.js +11 -1
- package/dist/base-command.js.map +1 -1
- package/dist/commands/ask.d.ts.map +1 -1
- package/dist/commands/ask.js +2 -0
- package/dist/commands/ask.js.map +1 -1
- package/dist/commands/backup.d.ts +1 -0
- package/dist/commands/backup.d.ts.map +1 -1
- package/dist/commands/backup.js +29 -10
- package/dist/commands/backup.js.map +1 -1
- package/dist/commands/chat.d.ts +2 -1
- package/dist/commands/chat.d.ts.map +1 -1
- package/dist/commands/chat.js +10 -4
- package/dist/commands/chat.js.map +1 -1
- package/dist/commands/down.d.ts +14 -27
- package/dist/commands/down.d.ts.map +1 -1
- package/dist/commands/down.js +6 -31
- package/dist/commands/down.js.map +1 -1
- package/dist/commands/knowledge/amend.d.ts +2 -2
- package/dist/commands/knowledge/amend.d.ts.map +1 -1
- package/dist/commands/knowledge/amend.js +5 -0
- package/dist/commands/knowledge/amend.js.map +1 -1
- package/dist/commands/login.d.ts +4 -0
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +21 -2
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/menu.js +1 -1
- package/dist/commands/menu.js.map +1 -1
- package/dist/commands/platform/destroy.d.ts +15 -5
- package/dist/commands/platform/destroy.d.ts.map +1 -1
- package/dist/commands/platform/destroy.js +6 -33
- package/dist/commands/platform/destroy.js.map +1 -1
- package/dist/commands/platform/doctor.d.ts +18 -3
- package/dist/commands/platform/doctor.d.ts.map +1 -1
- package/dist/commands/platform/doctor.js +4 -10
- package/dist/commands/platform/doctor.js.map +1 -1
- package/dist/commands/platform/down.d.ts +15 -15
- package/dist/commands/platform/down.d.ts.map +1 -1
- package/dist/commands/platform/down.js +4 -8
- package/dist/commands/platform/down.js.map +1 -1
- package/dist/commands/platform/logs.d.ts +15 -14
- package/dist/commands/platform/logs.d.ts.map +1 -1
- package/dist/commands/platform/logs.js +5 -16
- package/dist/commands/platform/logs.js.map +1 -1
- package/dist/commands/platform/reset.d.ts +16 -13
- package/dist/commands/platform/reset.d.ts.map +1 -1
- package/dist/commands/platform/reset.js +7 -36
- package/dist/commands/platform/reset.js.map +1 -1
- package/dist/commands/platform/setup.d.ts +1 -0
- package/dist/commands/platform/setup.d.ts.map +1 -1
- package/dist/commands/platform/setup.js +1 -1
- package/dist/commands/platform/setup.js.map +1 -1
- package/dist/commands/platform/status.d.ts +14 -16
- package/dist/commands/platform/status.d.ts.map +1 -1
- package/dist/commands/platform/status.js +4 -29
- package/dist/commands/platform/status.js.map +1 -1
- package/dist/commands/restore.d.ts +10 -1
- package/dist/commands/restore.d.ts.map +1 -1
- package/dist/commands/restore.js +56 -13
- package/dist/commands/restore.js.map +1 -1
- package/dist/commands/runtime/destroy.d.ts +29 -0
- package/dist/commands/runtime/destroy.d.ts.map +1 -0
- package/dist/commands/runtime/destroy.js +13 -0
- package/dist/commands/runtime/destroy.js.map +1 -0
- package/dist/commands/runtime/doctor.d.ts +27 -0
- package/dist/commands/runtime/doctor.d.ts.map +1 -0
- package/dist/commands/runtime/doctor.js +11 -0
- package/dist/commands/runtime/doctor.js.map +1 -0
- package/dist/commands/runtime/logs.d.ts +28 -0
- package/dist/commands/runtime/logs.d.ts.map +1 -0
- package/dist/commands/runtime/logs.js +12 -0
- package/dist/commands/runtime/logs.js.map +1 -0
- package/dist/commands/runtime/status.d.ts +27 -0
- package/dist/commands/runtime/status.d.ts.map +1 -0
- package/dist/commands/runtime/status.js +11 -0
- package/dist/commands/runtime/status.js.map +1 -0
- package/dist/commands/runtime/upgrade.d.ts +28 -0
- package/dist/commands/runtime/upgrade.d.ts.map +1 -0
- package/dist/commands/runtime/upgrade.js +12 -0
- package/dist/commands/runtime/upgrade.js.map +1 -0
- package/dist/commands/setup.d.ts +1 -0
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/commands/setup.js +1 -1
- package/dist/commands/transfer.js +1 -1
- package/dist/commands/transfer.js.map +1 -1
- package/dist/commands/up.d.ts +3 -11
- package/dist/commands/up.d.ts.map +1 -1
- package/dist/commands/up.js +48 -37
- package/dist/commands/up.js.map +1 -1
- package/dist/commands/whoami.js +1 -1
- package/dist/commands/whoami.js.map +1 -1
- package/dist/hooks/init/launch-menu.d.ts.map +1 -1
- package/dist/hooks/init/launch-menu.js +2 -0
- package/dist/hooks/init/launch-menu.js.map +1 -1
- package/dist/lib/anonymous-registry.d.ts +3 -0
- package/dist/lib/anonymous-registry.d.ts.map +1 -0
- package/dist/lib/anonymous-registry.js +25 -0
- package/dist/lib/anonymous-registry.js.map +1 -0
- package/dist/lib/async-process.d.ts +15 -0
- package/dist/lib/async-process.d.ts.map +1 -0
- package/dist/lib/async-process.js +145 -0
- package/dist/lib/async-process.js.map +1 -0
- package/dist/lib/backup-process.d.ts +4 -0
- package/dist/lib/backup-process.d.ts.map +1 -0
- package/dist/lib/backup-process.js +20 -0
- package/dist/lib/backup-process.js.map +1 -0
- package/dist/lib/brand.d.ts +25 -0
- package/dist/lib/brand.d.ts.map +1 -0
- package/dist/lib/brand.js +105 -0
- package/dist/lib/brand.js.map +1 -0
- package/dist/lib/chat.d.ts +1 -0
- package/dist/lib/chat.d.ts.map +1 -1
- package/dist/lib/chat.js +12 -3
- package/dist/lib/chat.js.map +1 -1
- package/dist/lib/compose-status.d.ts +14 -0
- package/dist/lib/compose-status.d.ts.map +1 -0
- package/dist/lib/compose-status.js +31 -0
- package/dist/lib/compose-status.js.map +1 -0
- package/dist/lib/container-engine.js +2 -2
- package/dist/lib/container-engine.js.map +1 -1
- package/dist/lib/local-engine-context.d.ts +16 -0
- package/dist/lib/local-engine-context.d.ts.map +1 -0
- package/dist/lib/local-engine-context.js +123 -0
- package/dist/lib/local-engine-context.js.map +1 -0
- package/dist/lib/login-guided.d.ts.map +1 -1
- package/dist/lib/login-guided.js +2 -1
- package/dist/lib/login-guided.js.map +1 -1
- package/dist/lib/login.d.ts +3 -0
- package/dist/lib/login.d.ts.map +1 -1
- package/dist/lib/login.js +25 -5
- package/dist/lib/login.js.map +1 -1
- package/dist/lib/oci-registry-probe.d.ts +43 -0
- package/dist/lib/oci-registry-probe.d.ts.map +1 -0
- package/dist/lib/oci-registry-probe.js +110 -0
- package/dist/lib/oci-registry-probe.js.map +1 -0
- package/dist/lib/peer-command.d.ts.map +1 -1
- package/dist/lib/peer-command.js +3 -1
- package/dist/lib/peer-command.js.map +1 -1
- package/dist/lib/platform-acquisition.d.ts +27 -0
- package/dist/lib/platform-acquisition.d.ts.map +1 -0
- package/dist/lib/platform-acquisition.js +21 -0
- package/dist/lib/platform-acquisition.js.map +1 -0
- package/dist/lib/platform-backup.d.ts +1 -0
- package/dist/lib/platform-backup.d.ts.map +1 -1
- package/dist/lib/platform-backup.js +375 -157
- package/dist/lib/platform-backup.js.map +1 -1
- package/dist/lib/platform-command-shared.d.ts +2 -0
- package/dist/lib/platform-command-shared.d.ts.map +1 -1
- package/dist/lib/platform-command-shared.js +13 -5
- package/dist/lib/platform-command-shared.js.map +1 -1
- package/dist/lib/platform-edition.d.ts +3 -6
- package/dist/lib/platform-edition.d.ts.map +1 -1
- package/dist/lib/platform-edition.js +9 -17
- package/dist/lib/platform-edition.js.map +1 -1
- package/dist/lib/platform-frontdoor-runtime.d.ts.map +1 -1
- package/dist/lib/platform-frontdoor-runtime.js +42 -10
- package/dist/lib/platform-frontdoor-runtime.js.map +1 -1
- package/dist/lib/platform-frontdoor.d.ts +30 -3
- package/dist/lib/platform-frontdoor.d.ts.map +1 -1
- package/dist/lib/platform-frontdoor.js +248 -170
- package/dist/lib/platform-frontdoor.js.map +1 -1
- package/dist/lib/platform-image-admission.d.ts +16 -0
- package/dist/lib/platform-image-admission.d.ts.map +1 -0
- package/dist/lib/platform-image-admission.js +73 -0
- package/dist/lib/platform-image-admission.js.map +1 -0
- package/dist/lib/platform-image-source.d.ts.map +1 -1
- package/dist/lib/platform-image-source.js +2 -0
- package/dist/lib/platform-image-source.js.map +1 -1
- package/dist/lib/platform-lifecycle.d.ts +4 -0
- package/dist/lib/platform-lifecycle.d.ts.map +1 -1
- package/dist/lib/platform-lifecycle.js +42 -8
- package/dist/lib/platform-lifecycle.js.map +1 -1
- package/dist/lib/platform-onboarding.d.ts.map +1 -1
- package/dist/lib/platform-onboarding.js +1 -1
- package/dist/lib/platform-onboarding.js.map +1 -1
- package/dist/lib/platform-preflight.d.ts +6 -3
- package/dist/lib/platform-preflight.d.ts.map +1 -1
- package/dist/lib/platform-preflight.js +52 -19
- package/dist/lib/platform-preflight.js.map +1 -1
- package/dist/lib/platform-release-manifest.d.ts +6 -1
- package/dist/lib/platform-release-manifest.d.ts.map +1 -1
- package/dist/lib/platform-release-manifest.js +10 -0
- package/dist/lib/platform-release-manifest.js.map +1 -1
- package/dist/lib/platform-runtime.d.ts +5 -2
- package/dist/lib/platform-runtime.d.ts.map +1 -1
- package/dist/lib/platform-runtime.js +7 -40
- package/dist/lib/platform-runtime.js.map +1 -1
- package/dist/lib/portable-release-digests.d.ts +5 -0
- package/dist/lib/portable-release-digests.d.ts.map +1 -0
- package/dist/lib/portable-release-digests.js +53 -0
- package/dist/lib/portable-release-digests.js.map +1 -0
- package/dist/lib/release-pin-matrix.d.ts +29 -0
- package/dist/lib/release-pin-matrix.d.ts.map +1 -0
- package/dist/lib/release-pin-matrix.js +67 -0
- package/dist/lib/release-pin-matrix.js.map +1 -0
- package/dist/lib/runtime-backup-archive.d.ts +20 -0
- package/dist/lib/runtime-backup-archive.d.ts.map +1 -0
- package/dist/lib/runtime-backup-archive.js +269 -0
- package/dist/lib/runtime-backup-archive.js.map +1 -0
- package/dist/lib/runtime-command.d.ts +37 -0
- package/dist/lib/runtime-command.d.ts.map +1 -0
- package/dist/lib/runtime-command.js +50 -0
- package/dist/lib/runtime-command.js.map +1 -0
- package/dist/lib/runtime-discovery.d.ts +18 -0
- package/dist/lib/runtime-discovery.d.ts.map +1 -0
- package/dist/lib/runtime-discovery.js +56 -0
- package/dist/lib/runtime-discovery.js.map +1 -0
- package/dist/lib/runtime-lock.d.ts +3 -0
- package/dist/lib/runtime-lock.d.ts.map +1 -0
- package/dist/lib/runtime-lock.js +50 -0
- package/dist/lib/runtime-lock.js.map +1 -0
- package/dist/lib/runtime-operations.d.ts +98 -0
- package/dist/lib/runtime-operations.d.ts.map +1 -0
- package/dist/lib/runtime-operations.js +182 -0
- package/dist/lib/runtime-operations.js.map +1 -0
- package/dist/lib/runtime-provider.d.ts +17 -0
- package/dist/lib/runtime-provider.d.ts.map +1 -0
- package/dist/lib/runtime-provider.js +52 -0
- package/dist/lib/runtime-provider.js.map +1 -0
- package/dist/lib/runtime-status.d.ts +24 -0
- package/dist/lib/runtime-status.d.ts.map +1 -0
- package/dist/lib/runtime-status.js +128 -0
- package/dist/lib/runtime-status.js.map +1 -0
- package/dist/lib/selfhosted-backup.d.ts +37 -0
- package/dist/lib/selfhosted-backup.d.ts.map +1 -0
- package/dist/lib/selfhosted-backup.js +446 -0
- package/dist/lib/selfhosted-backup.js.map +1 -0
- package/dist/lib/selfhosted-keyring.d.ts +19 -0
- package/dist/lib/selfhosted-keyring.d.ts.map +1 -0
- package/dist/lib/selfhosted-keyring.js +193 -0
- package/dist/lib/selfhosted-keyring.js.map +1 -0
- package/dist/lib/selfhosted-lifecycle.d.ts +45 -7
- package/dist/lib/selfhosted-lifecycle.d.ts.map +1 -1
- package/dist/lib/selfhosted-lifecycle.js +214 -31
- package/dist/lib/selfhosted-lifecycle.js.map +1 -1
- package/dist/lib/selfhosted-login.d.ts +34 -0
- package/dist/lib/selfhosted-login.d.ts.map +1 -0
- package/dist/lib/selfhosted-login.js +116 -0
- package/dist/lib/selfhosted-login.js.map +1 -0
- package/dist/lib/selfhosted-readiness.d.ts +3 -0
- package/dist/lib/selfhosted-readiness.d.ts.map +1 -0
- package/dist/lib/selfhosted-readiness.js +24 -0
- package/dist/lib/selfhosted-readiness.js.map +1 -0
- package/dist/lib/setup-capabilities.d.ts +15 -0
- package/dist/lib/setup-capabilities.d.ts.map +1 -0
- package/dist/lib/setup-capabilities.js +21 -0
- package/dist/lib/setup-capabilities.js.map +1 -0
- package/dist/lib/setup-console.d.ts +8 -0
- package/dist/lib/setup-console.d.ts.map +1 -1
- package/dist/lib/setup-console.js +104 -74
- package/dist/lib/setup-console.js.map +1 -1
- package/dist/lib/setup-page.d.ts +12 -0
- package/dist/lib/setup-page.d.ts.map +1 -1
- package/dist/lib/setup-page.js +40 -22
- package/dist/lib/setup-page.js.map +1 -1
- package/dist/lib/setup-plan.d.ts +1 -0
- package/dist/lib/setup-plan.d.ts.map +1 -1
- package/dist/lib/setup-plan.js +3 -0
- package/dist/lib/setup-plan.js.map +1 -1
- package/dist/lib/setup-server.d.ts +11 -2
- package/dist/lib/setup-server.d.ts.map +1 -1
- package/dist/lib/setup-server.js +139 -28
- package/dist/lib/setup-server.js.map +1 -1
- package/dist/lib/ui.d.ts +3 -1
- package/dist/lib/ui.d.ts.map +1 -1
- package/dist/lib/ui.js +39 -7
- package/dist/lib/ui.js.map +1 -1
- package/dist/lib/up-result.d.ts +3 -0
- package/dist/lib/up-result.d.ts.map +1 -1
- package/dist/lib/up-result.js.map +1 -1
- package/dist/menu/run.js +1 -1
- package/dist/menu/run.js.map +1 -1
- package/dist/menu/should-launch.d.ts +0 -14
- package/dist/menu/should-launch.d.ts.map +1 -1
- package/dist/menu/should-launch.js +5 -1
- package/dist/menu/should-launch.js.map +1 -1
- package/oclif.manifest.json +5490 -3263
- package/package.json +13 -10
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { observePlatformVersions } from './platform-lifecycle.js';
|
|
4
|
+
function requirements(runtime) {
|
|
5
|
+
if (runtime.edition === 'selfhosted')
|
|
6
|
+
return [
|
|
7
|
+
{ id: 'db', health: true },
|
|
8
|
+
{ id: 'api', health: true },
|
|
9
|
+
{ id: 'web', health: false },
|
|
10
|
+
...(runtime.state.components?.mcp === false ? [] : [{ id: 'mcp', health: true }]),
|
|
11
|
+
...(runtime.state.version.startsWith('0.15.')
|
|
12
|
+
? [{ id: 'lmstudio-bridge', health: true }]
|
|
13
|
+
: []),
|
|
14
|
+
];
|
|
15
|
+
const document = JSON.parse(readFileSync(join(runtime.paths.runtimeDir, 'runtime-contract.json'), 'utf8'));
|
|
16
|
+
const result = (document.services ?? [])
|
|
17
|
+
.filter((service) => service.required ||
|
|
18
|
+
(service.profile === 'mcp' && runtime.state.components?.mcp !== false) ||
|
|
19
|
+
(service.profile === 'public-site' && runtime.state.components?.publicSite))
|
|
20
|
+
.filter((service) => service.id !== 'object-storage' || runtime.state.storage === 'minio')
|
|
21
|
+
.map((service) => ({
|
|
22
|
+
id: service.id === 'object-storage' ? 'minio' : service.id,
|
|
23
|
+
health: service.health !== 'compose-process',
|
|
24
|
+
}));
|
|
25
|
+
if (!result.length)
|
|
26
|
+
throw new Error('Runtime contract has no required services. Restore the installed runtime contract.');
|
|
27
|
+
return result;
|
|
28
|
+
}
|
|
29
|
+
export function runtimeHealth(runtime, environment, rows) {
|
|
30
|
+
const checks = requirements(runtime).map((requirement) => {
|
|
31
|
+
const instances = rows.filter((row) => row.Service === requirement.id);
|
|
32
|
+
const ok = instances.length > 0 &&
|
|
33
|
+
instances.every((row) => row.State?.toLowerCase() === 'running' &&
|
|
34
|
+
(!requirement.health || row.Health?.toLowerCase() === 'healthy'));
|
|
35
|
+
return {
|
|
36
|
+
name: `Service ${requirement.id}`,
|
|
37
|
+
ok,
|
|
38
|
+
detail: instances.length
|
|
39
|
+
? instances.map((row) => `${row.State ?? 'unknown'} ${row.Health ?? ''}`.trim()).join(', ')
|
|
40
|
+
: 'missing',
|
|
41
|
+
};
|
|
42
|
+
});
|
|
43
|
+
const versions = observePlatformVersions(runtime.state, {
|
|
44
|
+
...environment,
|
|
45
|
+
KNOWZ_VERSION: (runtime.edition === 'selfhosted'
|
|
46
|
+
? environment.KNOWZ_SELFHOSTED_VERSION
|
|
47
|
+
: environment.KNOWZ_VERSION) ?? '',
|
|
48
|
+
}, rows);
|
|
49
|
+
checks.push({
|
|
50
|
+
name: 'Runtime versions',
|
|
51
|
+
ok: versions.versionConsistent,
|
|
52
|
+
detail: `Installed ${runtime.state.version}; environment ${versions.versionSources.environment ?? 'missing'}; running ${JSON.stringify(versions.versionSources.running)}`,
|
|
53
|
+
});
|
|
54
|
+
if (runtime.hasHealthyState === false ||
|
|
55
|
+
(runtime.attemptStatus && runtime.attemptStatus !== 'ready')) {
|
|
56
|
+
checks.push({
|
|
57
|
+
name: 'Last attempt',
|
|
58
|
+
ok: false,
|
|
59
|
+
detail: `Last runtime attempt: ${runtime.attemptStatus ?? 'incomplete'}; ${runtime.hasHealthyState === false ? 'no verified installation has been committed' : 'the prior installed release is preserved'}. Retry setup or inspect runtime logs.`,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
const allStopped = rows.length > 0 && rows.every((row) => row.State?.toLowerCase() !== 'running');
|
|
63
|
+
const status = rows.length === 0
|
|
64
|
+
? 'missing'
|
|
65
|
+
: allStopped
|
|
66
|
+
? 'stopped'
|
|
67
|
+
: checks.every((check) => check.ok)
|
|
68
|
+
? 'ready'
|
|
69
|
+
: 'partial';
|
|
70
|
+
const attemptPath = join(runtime.paths.runtimeDir, 'attempt.json');
|
|
71
|
+
let desiredVersion;
|
|
72
|
+
if (existsSync(attemptPath)) {
|
|
73
|
+
try {
|
|
74
|
+
const attempted = JSON.parse(readFileSync(attemptPath, 'utf8'));
|
|
75
|
+
if (typeof attempted.version === 'string' &&
|
|
76
|
+
/^\d+\.\d+\.\d+(?:[-+][\w.-]+)?$/.test(attempted.version))
|
|
77
|
+
desiredVersion = attempted.version;
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
checks.push({
|
|
81
|
+
name: 'Last attempt',
|
|
82
|
+
ok: false,
|
|
83
|
+
detail: 'Invalid attempt metadata; inspect the runtime directory.',
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
const provider = providerReadiness(runtime, environment);
|
|
88
|
+
checks.push({ name: 'Provider configuration', ok: provider.configured, detail: provider.detail });
|
|
89
|
+
return {
|
|
90
|
+
status,
|
|
91
|
+
checks,
|
|
92
|
+
services: rows,
|
|
93
|
+
...versions,
|
|
94
|
+
...(desiredVersion ? { desiredVersion } : {}),
|
|
95
|
+
provider,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
function providerReadiness(runtime, env) {
|
|
99
|
+
const mode = runtime.state.provider;
|
|
100
|
+
const required = mode === 'offline'
|
|
101
|
+
? []
|
|
102
|
+
: mode === 'azure'
|
|
103
|
+
? [
|
|
104
|
+
'AZURE_OPENAI_ENDPOINT',
|
|
105
|
+
runtime.edition === 'selfhosted' ? 'AZURE_OPENAI_APIKEY' : 'AZURE_OPENAI_API_KEY',
|
|
106
|
+
]
|
|
107
|
+
: mode === 'gcp'
|
|
108
|
+
? ['VERTEX__PROJECT', 'GCLOUD_ADC_PATH']
|
|
109
|
+
: runtime.edition === 'selfhosted'
|
|
110
|
+
? [
|
|
111
|
+
'OPENAI_COMPAT_ENDPOINT',
|
|
112
|
+
'OPENAI_COMPAT_CHAT_MODEL',
|
|
113
|
+
'OPENAI_COMPAT_EMBEDDING_MODEL',
|
|
114
|
+
]
|
|
115
|
+
: ['OPENAICOMPAT__ENDPOINT', 'OPENAICOMPAT__CHATMODEL', 'OPENAICOMPAT__EMBEDDINGMODEL'];
|
|
116
|
+
const missing = required.filter((key) => !env[key]?.trim());
|
|
117
|
+
return {
|
|
118
|
+
mode,
|
|
119
|
+
configured: missing.length === 0,
|
|
120
|
+
connectivity: 'not-checked',
|
|
121
|
+
detail: mode === 'offline'
|
|
122
|
+
? env.KNOWZ_AI_DISABLED === 'true' ? 'AI is explicitly disabled by the host; knowledge storage remains available.' : 'No host AI provider is selected. Application configuration may override this; check Instance configuration for the active provider.'
|
|
123
|
+
: missing.length
|
|
124
|
+
? `Missing provider settings: ${missing.join(', ')}. Reconfigure through knowz up.`
|
|
125
|
+
: 'Provider settings are present. Use the application connection test to verify provider connectivity.',
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=runtime-status.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime-status.js","sourceRoot":"","sources":["../../src/lib/runtime-status.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { type PlatformPaths, type ProcessRunner, type AsyncProcessRunner } from './platform-runtime.js';
|
|
2
|
+
import type { EngineStatus } from './container-engine.js';
|
|
3
|
+
interface RuntimeInput {
|
|
4
|
+
paths: PlatformPaths;
|
|
5
|
+
projectName: string;
|
|
6
|
+
engine?: EngineStatus;
|
|
7
|
+
runner: ProcessRunner | AsyncProcessRunner;
|
|
8
|
+
emit?: (line: string) => void;
|
|
9
|
+
}
|
|
10
|
+
export declare function runSelfHostedBackup(input: RuntimeInput & {
|
|
11
|
+
out?: string;
|
|
12
|
+
encrypt: boolean;
|
|
13
|
+
passphrase?: string;
|
|
14
|
+
cliVersion: string;
|
|
15
|
+
}): Promise<{
|
|
16
|
+
archive: string;
|
|
17
|
+
encrypted: boolean;
|
|
18
|
+
warning: string;
|
|
19
|
+
}>;
|
|
20
|
+
export declare function runSelfHostedRestore(input: RuntimeInput & {
|
|
21
|
+
archive: string;
|
|
22
|
+
passphrase?: string;
|
|
23
|
+
yes: boolean;
|
|
24
|
+
isTty: boolean;
|
|
25
|
+
replaceExisting?: boolean;
|
|
26
|
+
confirmName?: () => Promise<string>;
|
|
27
|
+
}): Promise<{
|
|
28
|
+
edition: "selfhosted";
|
|
29
|
+
version: string;
|
|
30
|
+
platformName: string;
|
|
31
|
+
integrityChecked: boolean;
|
|
32
|
+
healthPassed: boolean;
|
|
33
|
+
next: string;
|
|
34
|
+
warning: string;
|
|
35
|
+
}>;
|
|
36
|
+
export {};
|
|
37
|
+
//# sourceMappingURL=selfhosted-backup.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selfhosted-backup.d.ts","sourceRoot":"","sources":["../../src/lib/selfhosted-backup.ts"],"names":[],"mappings":"AA4BA,OAAO,EAML,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,KAAK,kBAAkB,EACxB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAC1D,UAAU,YAAY;IACpB,KAAK,EAAE,aAAa,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,MAAM,EAAE,aAAa,GAAG,kBAAkB,CAAC;IAC3C,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAC/B;AA8ED,wBAAsB,mBAAmB,CACvC,KAAK,EAAE,YAAY,GAAG;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE;aAiDxE,MAAM;eAAa,OAAO;aAAW,MAAM;GAuOrE;AACD,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,YAAY,GAAG;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,GAAG,EAAE,OAAO,CAAC;IACb,KAAK,EAAE,OAAO,CAAC;IACf,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;CACrC;;;;;;;;GAkRF"}
|
|
@@ -0,0 +1,446 @@
|
|
|
1
|
+
import { preserveLegacySelfHostedKeyring } from './selfhosted-keyring.js';
|
|
2
|
+
import { assertLocalEngineContext, readSavedLocalEngine } from './local-engine-context.js';
|
|
3
|
+
import { acquireRuntimeLock } from './runtime-lock.js';
|
|
4
|
+
import { withAnonymousRegistry } from './anonymous-registry.js';
|
|
5
|
+
import { copyFileSync, existsSync, readFileSync, rmSync, statSync, writeFileSync, createReadStream, } from 'node:fs';
|
|
6
|
+
import { createHash } from 'node:crypto';
|
|
7
|
+
import { dirname, join, resolve } from 'node:path';
|
|
8
|
+
import { KnowzError, ExitCode, ensurePrivateDirectory, protectPrivatePath } from '@knowzai/core';
|
|
9
|
+
import { createPrivateStaging, encryptStream, finalizePrivateArchive, executeBackupSteps, } from './platform-backup.js';
|
|
10
|
+
import { SELFHOSTED_BACKUP_ARTIFACTS, withRuntimeBackup } from './runtime-backup-archive.js';
|
|
11
|
+
import { resolvePackagedSelfHostedAssetsDir, resolveSelfHostedReleaseContract, } from './selfhosted-lifecycle.js';
|
|
12
|
+
import { parseEnv, writePrivateFile, validateProjectName, validatePort, redactPlatformSecrets, } from './platform-runtime.js';
|
|
13
|
+
const warning = 'This private backup contains knowledge, file data, user credentials, runtime secrets and the provider encryption keyring. Store it securely; use --encrypt for passphrase protection.';
|
|
14
|
+
function runtime(input) {
|
|
15
|
+
validateProjectName(input.projectName);
|
|
16
|
+
if (!input.engine?.daemonReachable ||
|
|
17
|
+
!input.engine.composeFront ||
|
|
18
|
+
input.engine.engine === 'none')
|
|
19
|
+
throw new KnowzError('Start Docker Desktop or Podman with Compose before backup/restore.', ExitCode.Usage);
|
|
20
|
+
return input.engine;
|
|
21
|
+
}
|
|
22
|
+
function invocation(input, args, compose = true) {
|
|
23
|
+
const engine = runtime(input);
|
|
24
|
+
const front = engine.composeFront;
|
|
25
|
+
return {
|
|
26
|
+
command: compose ? front.command : engine.engine,
|
|
27
|
+
args: compose
|
|
28
|
+
? [
|
|
29
|
+
...front.baseArgs,
|
|
30
|
+
'--project-name',
|
|
31
|
+
`knowz-selfhosted-${input.projectName}`,
|
|
32
|
+
'--file',
|
|
33
|
+
input.paths.composeFile,
|
|
34
|
+
'--env-file',
|
|
35
|
+
input.paths.envFile,
|
|
36
|
+
...args,
|
|
37
|
+
]
|
|
38
|
+
: args,
|
|
39
|
+
options: {
|
|
40
|
+
cwd: existsSync(input.paths.runtimeDir) ? input.paths.runtimeDir : process.cwd(),
|
|
41
|
+
shell: false,
|
|
42
|
+
...(front.env ? { env: front.env } : {}),
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
async function run(input, args, description, compose = true, secrets = []) {
|
|
47
|
+
const call = invocation(input, args, compose);
|
|
48
|
+
const result = !compose && args[0] === 'run' && args.includes('alpine:3.21')
|
|
49
|
+
? await withAnonymousRegistry(call.options.env, async (env) => input.runner(call.command, call.args, { ...call.options, env }))
|
|
50
|
+
: await input.runner(call.command, call.args, call.options);
|
|
51
|
+
if (result.status !== 0)
|
|
52
|
+
throw new KnowzError(`${description} failed: ${redactPlatformSecrets(result.stderr || result.error?.message || 'container command failed', secrets)}`, ExitCode.Generic);
|
|
53
|
+
return result;
|
|
54
|
+
}
|
|
55
|
+
function release(version) {
|
|
56
|
+
const catalog = JSON.parse(readFileSync(join(resolvePackagedSelfHostedAssetsDir(), 'releases.json'), 'utf8'));
|
|
57
|
+
const contract = resolveSelfHostedReleaseContract(JSON.stringify(catalog), version);
|
|
58
|
+
if (contract.runtime.database !== 'postgres')
|
|
59
|
+
throw new KnowzError('Legacy MSSQL backup/restore is unsupported by this PostgreSQL adapter. Use the matching legacy tools; never restore SQL backups into PostgreSQL.', ExitCode.Usage);
|
|
60
|
+
return { contract, digests: catalog.releases.find((x) => x.version === version)?.digests ?? {} };
|
|
61
|
+
}
|
|
62
|
+
async function sha(path) {
|
|
63
|
+
const hash = createHash('sha256');
|
|
64
|
+
for await (const chunk of createReadStream(path))
|
|
65
|
+
hash.update(chunk);
|
|
66
|
+
return 'sha256:' + hash.digest('hex');
|
|
67
|
+
}
|
|
68
|
+
export async function runSelfHostedBackup(input) {
|
|
69
|
+
const state = JSON.parse(readFileSync(input.paths.stateFile, 'utf8'));
|
|
70
|
+
const metadata = release(state.version);
|
|
71
|
+
if (state.edition !== 'selfhosted' || state.name !== input.projectName)
|
|
72
|
+
throw new KnowzError('Runtime identity does not match selfhosted backup target.', ExitCode.Usage);
|
|
73
|
+
const env = parseEnv(readFileSync(input.paths.envFile, 'utf8'));
|
|
74
|
+
if (env.KNOWZ_SELFHOSTED_VERSION !== state.version)
|
|
75
|
+
throw new KnowzError('Runtime version and environment disagree; repair setup before backup.', ExitCode.Usage);
|
|
76
|
+
if (input.encrypt && !input.passphrase)
|
|
77
|
+
throw new KnowzError('A passphrase is required for --encrypt.', ExitCode.Auth);
|
|
78
|
+
const secrets = Object.entries(env)
|
|
79
|
+
.filter(([key]) => /password|secret|key|token/i.test(key))
|
|
80
|
+
.map(([, value]) => value)
|
|
81
|
+
.filter(Boolean);
|
|
82
|
+
const filename = `knowz-selfhosted-backup-${input.projectName}-${new Date().toISOString().replace(/[:.]/g, '-')}.tar.gz${input.encrypt ? '.enc' : ''}`;
|
|
83
|
+
let destination = resolve(input.out ?? filename);
|
|
84
|
+
if (existsSync(destination) && statSync(destination).isDirectory())
|
|
85
|
+
destination = join(destination, filename);
|
|
86
|
+
if (input.encrypt && !destination.endsWith('.enc'))
|
|
87
|
+
destination += '.enc';
|
|
88
|
+
if (existsSync(destination))
|
|
89
|
+
throw new KnowzError('Refusing to overwrite an existing backup.', ExitCode.Usage);
|
|
90
|
+
if (!existsSync(dirname(destination)))
|
|
91
|
+
throw new KnowzError('Backup destination directory does not exist.', ExitCode.Usage);
|
|
92
|
+
input = {
|
|
93
|
+
...input,
|
|
94
|
+
engine: await assertLocalEngineContext(runtime(input), {
|
|
95
|
+
runner: input.runner,
|
|
96
|
+
savedEngine: readSavedLocalEngine(input.paths.stateFile),
|
|
97
|
+
}),
|
|
98
|
+
};
|
|
99
|
+
const unlock = acquireRuntimeLock(input.paths.runtimeDir);
|
|
100
|
+
try {
|
|
101
|
+
const staging = createPrivateStaging(input.paths.runtimeDir);
|
|
102
|
+
const plain = join(staging, 'result.tar.gz');
|
|
103
|
+
let writers = [];
|
|
104
|
+
let startedDb = false;
|
|
105
|
+
let attemptedDump = false;
|
|
106
|
+
let result;
|
|
107
|
+
let failure;
|
|
108
|
+
try {
|
|
109
|
+
for (const dir of ['pg', 'volumes', 'runtime'])
|
|
110
|
+
ensurePrivateDirectory(join(staging, dir));
|
|
111
|
+
const status = await run(input, ['ps', '--services', '--status', 'running'], 'inspect runtime', true, secrets);
|
|
112
|
+
const running = (status.stdout ?? '').trim().split(/\s+/);
|
|
113
|
+
const enabledServices = [
|
|
114
|
+
'db',
|
|
115
|
+
'api',
|
|
116
|
+
'web',
|
|
117
|
+
...(state.components?.mcp === false ? [] : ['mcp']),
|
|
118
|
+
];
|
|
119
|
+
const observedImages = {};
|
|
120
|
+
for (const service of enabledServices) {
|
|
121
|
+
const listed = await run(input, ['ps', '--all', '--quiet', service], `inspect ${service} identity`, true, secrets);
|
|
122
|
+
const id = (listed.stdout ?? '').trim();
|
|
123
|
+
if (!id)
|
|
124
|
+
continue;
|
|
125
|
+
if (!/^[a-f0-9]{12,64}$/.test(id))
|
|
126
|
+
throw new KnowzError('Ambiguous container identity; backup refused.', ExitCode.Usage);
|
|
127
|
+
const inspected = await run(input, ['inspect', id, '--format', '{"id":{{json .Image}},"reference":{{json .Config.Image}}}'], `inspect ${service} image`, false, secrets);
|
|
128
|
+
try {
|
|
129
|
+
const image = JSON.parse(inspected.stdout ?? '');
|
|
130
|
+
if (typeof image.id !== 'string' ||
|
|
131
|
+
!/^sha256:[a-f0-9]{64}$/.test(image.id) ||
|
|
132
|
+
typeof image.reference !== 'string' ||
|
|
133
|
+
!/^[A-Za-z0-9][A-Za-z0-9./:@_-]+$/.test(image.reference))
|
|
134
|
+
throw new Error();
|
|
135
|
+
observedImages[service] = { id: image.id, reference: image.reference };
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
throw new KnowzError('Cannot validate observed container image metadata; backup refused.', ExitCode.Usage);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
writers = running.filter((x) => ['api', 'mcp'].includes(x));
|
|
142
|
+
if (writers.length)
|
|
143
|
+
await run(input, ['stop', ...writers], 'pause writers for consistent snapshot', true, secrets);
|
|
144
|
+
await preserveLegacySelfHostedKeyring({
|
|
145
|
+
name: input.projectName,
|
|
146
|
+
paths: input.paths,
|
|
147
|
+
engine: input.engine,
|
|
148
|
+
runner: input.runner,
|
|
149
|
+
});
|
|
150
|
+
if (!running.includes('db')) {
|
|
151
|
+
startedDb = true;
|
|
152
|
+
await run(input, ['up', '--detach', '--wait', 'db'], 'start database', true, secrets);
|
|
153
|
+
}
|
|
154
|
+
attemptedDump = true;
|
|
155
|
+
await run(input, [
|
|
156
|
+
'exec',
|
|
157
|
+
'-T',
|
|
158
|
+
'db',
|
|
159
|
+
'pg_dump',
|
|
160
|
+
'-U',
|
|
161
|
+
'knowz',
|
|
162
|
+
'-Fc',
|
|
163
|
+
'-f',
|
|
164
|
+
'/tmp/knowz-backup.dump',
|
|
165
|
+
'knowz_selfhosted',
|
|
166
|
+
], 'dump selfhosted PostgreSQL', true, secrets);
|
|
167
|
+
await run(input, ['cp', 'db:/tmp/knowz-backup.dump', join(staging, 'pg/knowz_selfhosted.dump')], 'copy logical dump', true, secrets);
|
|
168
|
+
await run(input, ['exec', '-T', 'db', 'rm', '-f', '/tmp/knowz-backup.dump'], 'remove container dump', true, secrets);
|
|
169
|
+
for (const volume of ['knowz-file-storage', 'knowz-protected-keys'])
|
|
170
|
+
await run(input, [
|
|
171
|
+
'run',
|
|
172
|
+
'--rm',
|
|
173
|
+
'-v',
|
|
174
|
+
`knowz-selfhosted-${input.projectName}_${volume}:/src:ro`,
|
|
175
|
+
'-v',
|
|
176
|
+
`${staging}:/out`,
|
|
177
|
+
'alpine:3.21',
|
|
178
|
+
'tar',
|
|
179
|
+
'-czf',
|
|
180
|
+
`/out/volumes/${volume}.tar.gz`,
|
|
181
|
+
'-C',
|
|
182
|
+
'/src',
|
|
183
|
+
'.',
|
|
184
|
+
], `snapshot ${volume}`, false, secrets);
|
|
185
|
+
writePrivateFile(join(staging, 'runtime/.env'), readFileSync(input.paths.envFile, 'utf8'));
|
|
186
|
+
writePrivateFile(join(staging, 'runtime/state.json'), readFileSync(input.paths.stateFile, 'utf8'));
|
|
187
|
+
const checksums = {};
|
|
188
|
+
const sizes = {};
|
|
189
|
+
for (const file of SELFHOSTED_BACKUP_ARTIFACTS) {
|
|
190
|
+
checksums[file] = await sha(join(staging, file));
|
|
191
|
+
sizes[file] = statSync(join(staging, file)).size;
|
|
192
|
+
}
|
|
193
|
+
const manifest = {
|
|
194
|
+
formatVersion: 2,
|
|
195
|
+
schemaVersion: 2,
|
|
196
|
+
edition: 'selfhosted',
|
|
197
|
+
database: {
|
|
198
|
+
engine: 'postgres',
|
|
199
|
+
version: '16',
|
|
200
|
+
schemaVersion: 'unknown',
|
|
201
|
+
schemaVersionSource: 'not-observed',
|
|
202
|
+
},
|
|
203
|
+
runtime: {
|
|
204
|
+
release: state.version,
|
|
205
|
+
imageDigests: metadata.digests,
|
|
206
|
+
imageDigestSource: 'release-catalog',
|
|
207
|
+
enabledServices,
|
|
208
|
+
observedImages,
|
|
209
|
+
},
|
|
210
|
+
platformName: input.projectName,
|
|
211
|
+
createdAt: new Date().toISOString(),
|
|
212
|
+
cliVersion: input.cliVersion,
|
|
213
|
+
encrypted: input.encrypt,
|
|
214
|
+
keyMaterial: 'runtime secrets and protected provider keyring included',
|
|
215
|
+
checksums,
|
|
216
|
+
sizes,
|
|
217
|
+
};
|
|
218
|
+
writeFileSync(join(staging, 'manifest.json'), JSON.stringify(manifest, null, 2) + '\n', {
|
|
219
|
+
mode: 0o600,
|
|
220
|
+
});
|
|
221
|
+
await executeBackupSteps([
|
|
222
|
+
{
|
|
223
|
+
kind: 'fs',
|
|
224
|
+
description: 'create selfhosted archive',
|
|
225
|
+
invocation: {
|
|
226
|
+
command: 'tar',
|
|
227
|
+
args: [
|
|
228
|
+
'--format=ustar',
|
|
229
|
+
'-czf',
|
|
230
|
+
plain,
|
|
231
|
+
'-C',
|
|
232
|
+
staging,
|
|
233
|
+
'manifest.json',
|
|
234
|
+
...SELFHOSTED_BACKUP_ARTIFACTS,
|
|
235
|
+
],
|
|
236
|
+
options: { cwd: staging, shell: false, env: { COPYFILE_DISABLE: '1' } },
|
|
237
|
+
},
|
|
238
|
+
},
|
|
239
|
+
], input.runner, secrets);
|
|
240
|
+
protectPrivatePath(plain);
|
|
241
|
+
if (input.encrypt)
|
|
242
|
+
await encryptStream(plain, destination, input.passphrase);
|
|
243
|
+
else
|
|
244
|
+
finalizePrivateArchive(plain, destination);
|
|
245
|
+
result = { archive: destination, encrypted: input.encrypt, warning };
|
|
246
|
+
}
|
|
247
|
+
catch (error) {
|
|
248
|
+
failure = error;
|
|
249
|
+
}
|
|
250
|
+
finally {
|
|
251
|
+
if (attemptedDump) {
|
|
252
|
+
try {
|
|
253
|
+
await run(input, ['exec', '-T', 'db', 'rm', '-f', '/tmp/knowz-backup.dump'], 'remove any partial database dump', true, secrets);
|
|
254
|
+
}
|
|
255
|
+
catch {
|
|
256
|
+
/* Preserve primary failure; original service state still needs recovery. */
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
try {
|
|
260
|
+
if (startedDb)
|
|
261
|
+
await run(input, ['stop', 'db'], 'restore original stopped database state', true, secrets);
|
|
262
|
+
if (writers.length)
|
|
263
|
+
await run(input, ['start', ...writers], 'resume original runtime writers', true, secrets);
|
|
264
|
+
}
|
|
265
|
+
catch (error) {
|
|
266
|
+
failure ??= error;
|
|
267
|
+
}
|
|
268
|
+
rmSync(staging, { recursive: true, force: true });
|
|
269
|
+
}
|
|
270
|
+
if (failure)
|
|
271
|
+
throw failure;
|
|
272
|
+
input.emit?.(warning);
|
|
273
|
+
return result;
|
|
274
|
+
}
|
|
275
|
+
finally {
|
|
276
|
+
unlock();
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
export async function runSelfHostedRestore(input) {
|
|
280
|
+
if (!input.yes && !input.isTty)
|
|
281
|
+
throw new KnowzError('Refusing restore without --yes in a non-interactive session.', ExitCode.Usage);
|
|
282
|
+
return withRuntimeBackup(input, async (backup, extracted) => {
|
|
283
|
+
const manifest = backup.manifest;
|
|
284
|
+
const database = manifest.database;
|
|
285
|
+
const recorded = manifest.runtime;
|
|
286
|
+
if (backup.edition !== 'selfhosted' ||
|
|
287
|
+
database?.engine !== 'postgres' ||
|
|
288
|
+
database?.version !== '16' ||
|
|
289
|
+
!recorded?.release)
|
|
290
|
+
throw new KnowzError('Cross-edition or incompatible database restore refused.', ExitCode.Usage);
|
|
291
|
+
const metadata = release(recorded.release);
|
|
292
|
+
const state = JSON.parse(readFileSync(join(extracted, 'runtime/state.json'), 'utf8'));
|
|
293
|
+
if (state.edition !== 'selfhosted' || state.version !== recorded.release)
|
|
294
|
+
throw new KnowzError('Archive state does not match its release/edition manifest.', ExitCode.Usage);
|
|
295
|
+
for (const port of Object.values(state.ports ?? {}))
|
|
296
|
+
validatePort(port);
|
|
297
|
+
if (!state.ports?.api || !state.ports.web || !state.ports.mcp)
|
|
298
|
+
throw new KnowzError('Archive runtime ports are invalid.', ExitCode.Usage);
|
|
299
|
+
const archivedEnv = readFileSync(join(extracted, 'runtime/.env'), 'utf8');
|
|
300
|
+
const env = parseEnv(archivedEnv);
|
|
301
|
+
if (env.KNOWZ_SELFHOSTED_VERSION !== state.version)
|
|
302
|
+
throw new KnowzError('Archive environment version is inconsistent.', ExitCode.Usage);
|
|
303
|
+
const occupied = existsSync(input.paths.runtimeDir);
|
|
304
|
+
if (occupied && !input.replaceExisting)
|
|
305
|
+
throw new KnowzError('Restore target is occupied. Restore into a new --name or stop it and explicitly use --replace-installation.', ExitCode.Usage);
|
|
306
|
+
if (occupied && existsSync(input.paths.stateFile)) {
|
|
307
|
+
const previous = JSON.parse(readFileSync(input.paths.stateFile, 'utf8'));
|
|
308
|
+
if (previous.edition !== 'selfhosted' || previous.version !== state.version)
|
|
309
|
+
throw new KnowzError('Replacing a different edition or database release is refused. Restore to a fresh isolated --name; do not downgrade an occupied database.', ExitCode.Usage);
|
|
310
|
+
}
|
|
311
|
+
input = {
|
|
312
|
+
...input,
|
|
313
|
+
engine: await assertLocalEngineContext(runtime(input), {
|
|
314
|
+
runner: input.runner,
|
|
315
|
+
savedEngine: readSavedLocalEngine(input.paths.stateFile),
|
|
316
|
+
}),
|
|
317
|
+
};
|
|
318
|
+
const active = await run(input, [
|
|
319
|
+
'ps',
|
|
320
|
+
'--filter',
|
|
321
|
+
`label=com.docker.compose.project=knowz-selfhosted-${input.projectName}`,
|
|
322
|
+
'--format',
|
|
323
|
+
'{{.Names}}',
|
|
324
|
+
], 'inspect target containers', false);
|
|
325
|
+
if (active.stdout?.trim())
|
|
326
|
+
throw new KnowzError('Target runtime is running; run knowz down first.', ExitCode.Usage);
|
|
327
|
+
const volumes = await run(input, [
|
|
328
|
+
'volume',
|
|
329
|
+
'ls',
|
|
330
|
+
'--filter',
|
|
331
|
+
`label=com.docker.compose.project=knowz-selfhosted-${input.projectName}`,
|
|
332
|
+
'--format',
|
|
333
|
+
'{{.Name}}',
|
|
334
|
+
], 'inspect existing target volumes', false);
|
|
335
|
+
if (volumes.stdout?.trim() && !input.replaceExisting)
|
|
336
|
+
throw new KnowzError('Target has occupied runtime volumes; choose a new name or use --replace-installation.', ExitCode.Usage);
|
|
337
|
+
if (!input.yes && (await input.confirmName?.()) !== input.projectName)
|
|
338
|
+
throw new KnowzError('Restore confirmation did not match the runtime name.', ExitCode.Usage);
|
|
339
|
+
const unlock = acquireRuntimeLock(input.paths.runtimeDir);
|
|
340
|
+
try {
|
|
341
|
+
if (!occupied && (existsSync(input.paths.stateFile) || existsSync(input.paths.envFile)))
|
|
342
|
+
throw new KnowzError('Restore target changed during validation; retry with a new name.', ExitCode.Usage);
|
|
343
|
+
if (existsSync(input.paths.stateFile)) {
|
|
344
|
+
const current = JSON.parse(readFileSync(input.paths.stateFile, 'utf8'));
|
|
345
|
+
if (current.edition !== 'selfhosted' || current.version !== state.version)
|
|
346
|
+
throw new KnowzError('Target identity changed during restore validation.', ExitCode.Usage);
|
|
347
|
+
}
|
|
348
|
+
input = {
|
|
349
|
+
...input,
|
|
350
|
+
engine: await assertLocalEngineContext(runtime(input), {
|
|
351
|
+
runner: input.runner,
|
|
352
|
+
savedEngine: readSavedLocalEngine(input.paths.stateFile),
|
|
353
|
+
}),
|
|
354
|
+
};
|
|
355
|
+
const activeUnderLease = await run(input, [
|
|
356
|
+
'ps',
|
|
357
|
+
'--filter',
|
|
358
|
+
`label=com.docker.compose.project=knowz-selfhosted-${input.projectName}`,
|
|
359
|
+
'--format',
|
|
360
|
+
'{{.Names}}',
|
|
361
|
+
], 'recheck stopped target under restore lock', false);
|
|
362
|
+
if (activeUnderLease.stdout?.trim())
|
|
363
|
+
throw new KnowzError('Target runtime is now running; stop it and retry restore.', ExitCode.Usage);
|
|
364
|
+
const volumesUnderLease = await run(input, [
|
|
365
|
+
'volume',
|
|
366
|
+
'ls',
|
|
367
|
+
'--filter',
|
|
368
|
+
`label=com.docker.compose.project=knowz-selfhosted-${input.projectName}`,
|
|
369
|
+
'--format',
|
|
370
|
+
'{{.Name}}',
|
|
371
|
+
], 'recheck target volumes under restore lock', false);
|
|
372
|
+
if (volumesUnderLease.stdout?.trim() && !input.replaceExisting)
|
|
373
|
+
throw new KnowzError('Target acquired volumes during restore validation; select a fresh target.', ExitCode.Usage);
|
|
374
|
+
// Only the packaged reviewed compose contract is executed. Archive compose files are never executed.
|
|
375
|
+
ensurePrivateDirectory(input.paths.runtimeDir);
|
|
376
|
+
writePrivateFile(input.paths.envFile, archivedEnv);
|
|
377
|
+
copyFileSync(join(resolvePackagedSelfHostedAssetsDir(), metadata.contract.runtime.composeAsset), input.paths.composeFile);
|
|
378
|
+
const secrets = Object.entries(env)
|
|
379
|
+
.filter(([key]) => /password|secret|key|token/i.test(key))
|
|
380
|
+
.map(([, value]) => value)
|
|
381
|
+
.filter(Boolean);
|
|
382
|
+
let started = false;
|
|
383
|
+
try {
|
|
384
|
+
if (input.replaceExisting)
|
|
385
|
+
await run(input, ['down', '--volumes', '--remove-orphans'], 'remove explicitly selected stopped runtime', true, secrets);
|
|
386
|
+
await run(input, ['up', '--detach', '--wait', 'db'], 'start restore database', true, secrets);
|
|
387
|
+
started = true;
|
|
388
|
+
await run(input, ['cp', join(extracted, 'pg/knowz_selfhosted.dump'), 'db:/tmp/knowz-restore.dump'], 'copy restore dump', true, secrets);
|
|
389
|
+
await run(input, [
|
|
390
|
+
'exec',
|
|
391
|
+
'-T',
|
|
392
|
+
'db',
|
|
393
|
+
'pg_restore',
|
|
394
|
+
'--exit-on-error',
|
|
395
|
+
'--clean',
|
|
396
|
+
'--if-exists',
|
|
397
|
+
'--no-owner',
|
|
398
|
+
'-U',
|
|
399
|
+
'knowz',
|
|
400
|
+
'-d',
|
|
401
|
+
'knowz_selfhosted',
|
|
402
|
+
'/tmp/knowz-restore.dump',
|
|
403
|
+
], 'restore PostgreSQL', true, secrets);
|
|
404
|
+
await run(input, ['exec', '-T', 'db', 'rm', '-f', '/tmp/knowz-restore.dump'], 'remove restore dump', true, secrets);
|
|
405
|
+
for (const volume of ['knowz-file-storage', 'knowz-protected-keys'])
|
|
406
|
+
await run(input, [
|
|
407
|
+
'run',
|
|
408
|
+
'--rm',
|
|
409
|
+
'-v',
|
|
410
|
+
`knowz-selfhosted-${input.projectName}_${volume}:/dst`,
|
|
411
|
+
'-v',
|
|
412
|
+
`${extracted}:/in:ro`,
|
|
413
|
+
'alpine:3.21',
|
|
414
|
+
'sh',
|
|
415
|
+
'-c',
|
|
416
|
+
`tar -xzf /in/volumes/${volume}.tar.gz --no-same-owner -C /dst && chown -R 1654:1654 /dst`,
|
|
417
|
+
], `restore ${volume}`, false, secrets);
|
|
418
|
+
writePrivateFile(input.paths.stateFile, JSON.stringify({
|
|
419
|
+
...state,
|
|
420
|
+
name: input.projectName,
|
|
421
|
+
engine: input.engine,
|
|
422
|
+
healthPassed: false,
|
|
423
|
+
restoredAt: new Date().toISOString(),
|
|
424
|
+
updatedAt: new Date().toISOString(),
|
|
425
|
+
}, null, 2) + '\n');
|
|
426
|
+
}
|
|
427
|
+
finally {
|
|
428
|
+
if (started)
|
|
429
|
+
await run(input, ['stop', 'db'], 'leave restored runtime stopped', true, secrets);
|
|
430
|
+
}
|
|
431
|
+
return {
|
|
432
|
+
edition: 'selfhosted',
|
|
433
|
+
version: state.version,
|
|
434
|
+
platformName: input.projectName,
|
|
435
|
+
integrityChecked: true,
|
|
436
|
+
healthPassed: false,
|
|
437
|
+
next: `knowz up --edition selfhosted --name ${input.projectName}`,
|
|
438
|
+
warning: 'Runtime restored and left stopped. Start it, verify login and file hashes, then verify provider readiness.',
|
|
439
|
+
};
|
|
440
|
+
}
|
|
441
|
+
finally {
|
|
442
|
+
unlock();
|
|
443
|
+
}
|
|
444
|
+
});
|
|
445
|
+
}
|
|
446
|
+
//# sourceMappingURL=selfhosted-backup.js.map
|