create-aura-appliance 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +42 -0
- package/dist/bin.d.ts +3 -0
- package/dist/bin.d.ts.map +1 -0
- package/dist/bin.js +5 -0
- package/dist/bin.js.map +1 -0
- package/dist/cli.d.ts +30 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +200 -0
- package/dist/cli.js.map +1 -0
- package/dist/config-file.d.ts +12 -0
- package/dist/config-file.d.ts.map +1 -0
- package/dist/config-file.js +50 -0
- package/dist/config-file.js.map +1 -0
- package/dist/i18n.d.ts +7 -0
- package/dist/i18n.d.ts.map +1 -0
- package/dist/i18n.js +10 -0
- package/dist/i18n.js.map +1 -0
- package/dist/local.d.ts +7 -0
- package/dist/local.d.ts.map +1 -0
- package/dist/local.js +110 -0
- package/dist/local.js.map +1 -0
- package/dist/messages/en.d.ts +61 -0
- package/dist/messages/en.d.ts.map +1 -0
- package/dist/messages/en.js +61 -0
- package/dist/messages/en.js.map +1 -0
- package/dist/messages/it.d.ts +3 -0
- package/dist/messages/it.d.ts.map +1 -0
- package/dist/messages/it.js +61 -0
- package/dist/messages/it.js.map +1 -0
- package/dist/modelroute.d.ts +20 -0
- package/dist/modelroute.d.ts.map +1 -0
- package/dist/modelroute.js +67 -0
- package/dist/modelroute.js.map +1 -0
- package/dist/preflight-floors.d.ts +4 -0
- package/dist/preflight-floors.d.ts.map +1 -0
- package/dist/preflight-floors.js +9 -0
- package/dist/preflight-floors.js.map +1 -0
- package/dist/preflight.d.ts +8 -0
- package/dist/preflight.d.ts.map +1 -0
- package/dist/preflight.js +53 -0
- package/dist/preflight.js.map +1 -0
- package/dist/process.d.ts +39 -0
- package/dist/process.d.ts.map +1 -0
- package/dist/process.js +115 -0
- package/dist/process.js.map +1 -0
- package/dist/prompts.d.ts +37 -0
- package/dist/prompts.d.ts.map +1 -0
- package/dist/prompts.js +123 -0
- package/dist/prompts.js.map +1 -0
- package/dist/remote.d.ts +10 -0
- package/dist/remote.d.ts.map +1 -0
- package/dist/remote.js +268 -0
- package/dist/remote.js.map +1 -0
- package/dist/types.d.ts +23 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/validation.d.ts +12 -0
- package/dist/validation.d.ts.map +1 -0
- package/dist/validation.js +88 -0
- package/dist/validation.js.map +1 -0
- package/install-appliance.run +908 -1
- package/package.json +45 -0
package/dist/prompts.js
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { confirm, input, password, select } from '@inquirer/prompts';
|
|
2
|
+
import { embedTargetFor, probeGpu, probeOllama, } from './modelroute.js';
|
|
3
|
+
import { validateBaseUrl, validateHost, validateInstallDir, validateModelId, validatePort, validateUsername, } from './validation.js';
|
|
4
|
+
export const inquirerPrompt = {
|
|
5
|
+
select: (options) => select({ message: options.message, choices: [...options.choices] }),
|
|
6
|
+
input: (options) => input(options),
|
|
7
|
+
password: (options) => password(options),
|
|
8
|
+
confirm: (options) => confirm(options),
|
|
9
|
+
};
|
|
10
|
+
export async function collectTarget(prompt, t, requestedMode) {
|
|
11
|
+
const mode = requestedMode ?? await prompt.select({
|
|
12
|
+
message: t('modeQuestion'),
|
|
13
|
+
choices: [
|
|
14
|
+
{ name: t('modeLocal'), value: 'local' },
|
|
15
|
+
{ name: t('modeRemote'), value: 'remote' },
|
|
16
|
+
],
|
|
17
|
+
});
|
|
18
|
+
let remote;
|
|
19
|
+
if (mode === 'remote') {
|
|
20
|
+
remote = {
|
|
21
|
+
host: validateHost(await prompt.input({ message: t('remoteHost') })),
|
|
22
|
+
port: validatePort(await prompt.input({ message: t('remotePort'), default: '22' })),
|
|
23
|
+
// Aura's remote target is a clean Ubuntu Server mini-PC, not a Raspberry Pi -- 'ubuntu'
|
|
24
|
+
// is that image's standard default account, replacing the reference's 'pi'.
|
|
25
|
+
username: validateUsername(await prompt.input({ message: t('remoteUsername'), default: 'ubuntu' })),
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
const installDir = validateInstallDir(await prompt.input({
|
|
29
|
+
message: t('installDir'),
|
|
30
|
+
// scripts/install.sh:86 -- /opt/aura is the appliance's own default installation path.
|
|
31
|
+
default: '/opt/aura',
|
|
32
|
+
}));
|
|
33
|
+
return remote ? { mode, installDir, remote } : { mode, installDir };
|
|
34
|
+
}
|
|
35
|
+
async function collectGpuChoice(prompt, t, probeRunner) {
|
|
36
|
+
if (probeRunner)
|
|
37
|
+
return probeGpu(probeRunner);
|
|
38
|
+
// R1 (Task 5 controller ruling): with no runner able to probe the actual install target
|
|
39
|
+
// (remote mode, until Task 6 supplies an SSH-wrapping one), the wizard must not run
|
|
40
|
+
// nvidia-smi against the operator's own laptop and present that as the target's GPU --
|
|
41
|
+
// it asks instead.
|
|
42
|
+
const hasGpu = await prompt.confirm({ message: t('gpuQuestion'), default: false });
|
|
43
|
+
return { cuda: hasGpu, ...embedTargetFor(hasGpu) };
|
|
44
|
+
}
|
|
45
|
+
async function collectOllamaModel(prompt, t, probeRunner, llmBaseUrl) {
|
|
46
|
+
const probe = probeRunner ? await probeOllama(probeRunner, llmBaseUrl) : undefined;
|
|
47
|
+
if (probe?.reachable && probe.models.length > 0) {
|
|
48
|
+
return prompt.select({
|
|
49
|
+
message: t('ollamaModelSelect'),
|
|
50
|
+
choices: probe.models.map((model) => ({ name: model, value: model })),
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
// R2 (Task 4 review, landed here): probe.reachable is false for four different causes --
|
|
54
|
+
// the endpoint refused, docker is absent or its daemon is down, the alpine probe image
|
|
55
|
+
// could not be pulled, or the reply was not JSON. The message must not assert the
|
|
56
|
+
// endpoint is at fault, or the operator debugs a box that was fine. A probe that WAS
|
|
57
|
+
// reachable but listed no models yet (or no probe was attempted at all, e.g. remote mode)
|
|
58
|
+
// gets the plain manual-entry prompt instead.
|
|
59
|
+
const message = probe && !probe.reachable ? t('ollamaModelUnreachable') : t('ollamaModelManualEntry');
|
|
60
|
+
return validateModelId(await prompt.input({ message }));
|
|
61
|
+
}
|
|
62
|
+
export async function collectSettings(prompt, t, installDir, probeRunner) {
|
|
63
|
+
const appliance = await prompt.confirm({ message: t('applianceQuestion'), default: true });
|
|
64
|
+
const gvisor = await prompt.confirm({ message: t('gvisorQuestion'), default: false });
|
|
65
|
+
// R4: exactly two model routes. A third llama.cpp route is deliberately not offered --
|
|
66
|
+
// compose.yaml's aura-llm sits behind profiles:[localllm] and needs a ~6.7 GB GGUF that
|
|
67
|
+
// install.sh never fetches, so enabling it would leave the volume empty, the healthcheck
|
|
68
|
+
// would never pass, and `docker compose up -d --wait` would abort the whole install.
|
|
69
|
+
const llmProvider = await prompt.select({
|
|
70
|
+
message: t('modelRouteQuestion'),
|
|
71
|
+
choices: [
|
|
72
|
+
{ name: t('modelRouteOpenrouter'), value: 'openrouter' },
|
|
73
|
+
{ name: t('modelRouteOllama'), value: 'ollama' },
|
|
74
|
+
],
|
|
75
|
+
});
|
|
76
|
+
let llmBaseUrl;
|
|
77
|
+
let llmModel;
|
|
78
|
+
let openrouterApiKey;
|
|
79
|
+
if (llmProvider === 'openrouter') {
|
|
80
|
+
llmBaseUrl = validateBaseUrl(await prompt.input({
|
|
81
|
+
message: t('openrouterBaseUrl'),
|
|
82
|
+
default: 'https://openrouter.ai/api/v1',
|
|
83
|
+
}));
|
|
84
|
+
openrouterApiKey = await prompt.password({ message: t('openrouterApiKey'), mask: '*' });
|
|
85
|
+
llmModel = validateModelId(await prompt.input({ message: t('openrouterModel') }));
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
llmBaseUrl = validateBaseUrl(await prompt.input({
|
|
89
|
+
message: t('ollamaBaseUrl'),
|
|
90
|
+
// C1 (review round 1): 'localhost' here is wrong twice. probeOllama's request runs
|
|
91
|
+
// INSIDE the throwaway alpine container, where 'localhost' means the container itself,
|
|
92
|
+
// not the operator's host -- modelroute.ts's own comment warns about exactly this ("an
|
|
93
|
+
// Ollama on the host is not at 127.0.0.1 as seen from there"), so the wizard's own
|
|
94
|
+
// default could never probe reachable. And the /v1 suffix is load-bearing:
|
|
95
|
+
// internal/llm/config.go:21's defaultBaseURL carries it, and every other Ollama base
|
|
96
|
+
// URL in this repo is spelled with it (scripts/install_config_test.sh:19,
|
|
97
|
+
// internal/agui/settings_api_test.go:218,
|
|
98
|
+
// internal/channels/telegram/commands_spend_test.go:157) -- without it Aura requests
|
|
99
|
+
// .../11434/chat/completions, which Ollama does not serve.
|
|
100
|
+
default: 'http://host.docker.internal:11434/v1',
|
|
101
|
+
}));
|
|
102
|
+
llmModel = await collectOllamaModel(prompt, t, probeRunner, llmBaseUrl);
|
|
103
|
+
}
|
|
104
|
+
const gpu = await collectGpuChoice(prompt, t, probeRunner);
|
|
105
|
+
const confirmed = await prompt.confirm({ message: t('confirmInstall'), default: true });
|
|
106
|
+
if (!confirmed)
|
|
107
|
+
return null;
|
|
108
|
+
return {
|
|
109
|
+
installDir,
|
|
110
|
+
appliance,
|
|
111
|
+
gvisor,
|
|
112
|
+
llmProvider,
|
|
113
|
+
llmBaseUrl,
|
|
114
|
+
llmModel,
|
|
115
|
+
// R5: the empty OpenRouter key is emitted, never omitted -- install.sh's
|
|
116
|
+
// parse_install_config accepts an empty openrouter_api_key_base64 and exit 2s on a
|
|
117
|
+
// MISSING key set, so the Ollama route must still produce all nine keys.
|
|
118
|
+
...(openrouterApiKey === undefined ? {} : { openrouterApiKey }),
|
|
119
|
+
embedImage: gpu.embedImage,
|
|
120
|
+
embedNgl: gpu.embedNgl,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=prompts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompts.js","sourceRoot":"","sources":["../src/prompts.ts"],"names":[],"mappings":"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"}
|
package/dist/remote.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { TemporaryFile } from './config-file.js';
|
|
2
|
+
import type { CommandRunner } from './process.js';
|
|
3
|
+
import type { InstallSettings, PreflightResult, RemoteTarget } from './types.js';
|
|
4
|
+
export declare const REMOTE_INSTALL_SCRIPT = "#!/bin/sh\nset -eu\nexec 2>&1\nINSTALLER=\"$1\"\nCONFIG=\"$2\"\nRUNNER=\"$0\"\ncleanup() { rm -f -- \"$CONFIG\" \"$INSTALLER\" \"$RUNNER\"; }\ntrap cleanup EXIT\ntrap 'exit 129' HUP\ntrap 'exit 130' INT\ntrap 'exit 143' TERM\nchmod 700 \"$INSTALLER\"\nchmod 600 \"$CONFIG\"\nsudo bash \"$INSTALLER\" -- --config \"$CONFIG\"\n";
|
|
5
|
+
export type WarningSink = (message: string) => void;
|
|
6
|
+
export declare function sshDestination(target: RemoteTarget): string;
|
|
7
|
+
export declare function preflightRemote(runner: CommandRunner, target: RemoteTarget, installDir: string, platform?: NodeJS.Platform): Promise<PreflightResult>;
|
|
8
|
+
export declare function installRemote(runner: CommandRunner, target: RemoteTarget, artifact: TemporaryFile, config: TemporaryFile, settings: InstallSettings, remoteId?: string, warn?: WarningSink, tempRoot?: string): Promise<void>;
|
|
9
|
+
export declare function createSshProbeRunner(runner: CommandRunner, target: RemoteTarget): CommandRunner;
|
|
10
|
+
//# sourceMappingURL=remote.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remote.d.ts","sourceRoot":"","sources":["../src/remote.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAOtD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAiFjF,eAAO,MAAM,qBAAqB,0UAcjC,CAAC;AAOF,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;AAiDpD,wBAAgB,cAAc,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAI3D;AAqCD,wBAAsB,eAAe,CACnC,MAAM,EAAE,aAAa,EACrB,MAAM,EAAE,YAAY,EACpB,UAAU,EAAE,MAAM,EAClB,QAAQ,GAAE,MAAM,CAAC,QAA2B,GAC3C,OAAO,CAAC,eAAe,CAAC,CA2B1B;AAED,wBAAsB,aAAa,CACjC,MAAM,EAAE,aAAa,EACrB,MAAM,EAAE,YAAY,EACpB,QAAQ,EAAE,aAAa,EACvB,MAAM,EAAE,aAAa,EACrB,QAAQ,EAAE,eAAe,EACzB,QAAQ,GAAE,MAAqB,EAC/B,IAAI,GAAE,WAA+D,EACrE,QAAQ,SAAW,GAClB,OAAO,CAAC,IAAI,CAAC,CAmEf;AAeD,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,YAAY,GAAG,aAAa,CAa/F"}
|
package/dist/remote.js
ADDED
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { chmod, copyFile, mkdtemp, rm, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { isIP } from 'node:net';
|
|
4
|
+
import { tmpdir } from 'node:os';
|
|
5
|
+
import { join } from 'node:path';
|
|
6
|
+
import { assertSufficientCpuCores, assertSufficientDiskSpace, assertSufficientMemory, normalizeArchitecture, } from './preflight.js';
|
|
7
|
+
import { validateHost, validatePort, validateUsername } from './validation.js';
|
|
8
|
+
const REMOTE_ID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
|
|
9
|
+
// R4: the same REQUIRED_COMMANDS as local.ts's preflightLocal, and for the same reasons --
|
|
10
|
+
// the exact same install.sh runs on this target, whether reached over SSH or run in place.
|
|
11
|
+
// See local.ts for the per-command justification (sudo/curl/openssl unconditional; apt-get,
|
|
12
|
+
// systemctl, and docker itself deliberately excluded).
|
|
13
|
+
// R3: the same REQUIRED_HOSTS -- ghcr.io and get.docker.com kept, raw.githubusercontent.com
|
|
14
|
+
// removed (the npm package carries the payload), huggingface.co added (install.sh:357's
|
|
15
|
+
// unconditional embedding-model probe).
|
|
16
|
+
// R2 (this file's own gap, closed): the reference's own REMOTE_PROBE measured disk alone.
|
|
17
|
+
// install.sh's actual hard gate is cpu+mem+disk together (scripts/install.sh:172-187), so
|
|
18
|
+
// cpu_cores and memory_kib are measured here too -- a remote target must clear the same three
|
|
19
|
+
// floors a local one does, not just one of them. Reading /proc/meminfo directly (no Darwin
|
|
20
|
+
// branch, unlike local.ts's RAM_KIB_SCRIPT) is safe because the case above already asserts
|
|
21
|
+
// the remote target is Linux.
|
|
22
|
+
const REMOTE_PROBE = `set -eu
|
|
23
|
+
exec 2>&1
|
|
24
|
+
INSTALL_DIR="$(printf '%s' "$1" | base64 --decode)"
|
|
25
|
+
case "$INSTALL_DIR" in
|
|
26
|
+
/*) ;;
|
|
27
|
+
*) echo 'invalid install directory' >&2; exit 1 ;;
|
|
28
|
+
esac
|
|
29
|
+
[ "$INSTALL_DIR" != "/" ] || { echo 'invalid install directory' >&2; exit 1; }
|
|
30
|
+
[ "$(uname -s)" = "Linux" ] || { echo 'Linux target required' >&2; exit 1; }
|
|
31
|
+
for REQUIRED_COMMAND in sudo curl openssl; do
|
|
32
|
+
command -v "$REQUIRED_COMMAND" >/dev/null 2>&1 || {
|
|
33
|
+
echo "missing command: $REQUIRED_COMMAND" >&2
|
|
34
|
+
exit 1
|
|
35
|
+
}
|
|
36
|
+
done
|
|
37
|
+
ARCHITECTURE="$(uname -m)"
|
|
38
|
+
case "$ARCHITECTURE" in
|
|
39
|
+
aarch64|arm64|x86_64|amd64) ;;
|
|
40
|
+
*) echo "unsupported architecture: $ARCHITECTURE" >&2; exit 1 ;;
|
|
41
|
+
esac
|
|
42
|
+
EXISTING_INSTALL=false
|
|
43
|
+
[ -f "$INSTALL_DIR/compose.yaml" ] && EXISTING_INSTALL=true
|
|
44
|
+
CPU_CORES="$(getconf _NPROCESSORS_ONLN 2>/dev/null || echo 0)"
|
|
45
|
+
case "$CPU_CORES" in
|
|
46
|
+
''|*[!0-9]*) echo 'unable to determine cpu core count' >&2; exit 1 ;;
|
|
47
|
+
esac
|
|
48
|
+
MEMORY_KIB="$(awk '/MemTotal:/ {print $2}' /proc/meminfo 2>/dev/null || echo 0)"
|
|
49
|
+
case "$MEMORY_KIB" in
|
|
50
|
+
''|*[!0-9]*) echo 'unable to determine memory availability' >&2; exit 1 ;;
|
|
51
|
+
esac
|
|
52
|
+
DISK_PROBE="$INSTALL_DIR"
|
|
53
|
+
while [ ! -e "$DISK_PROBE" ] && [ "$DISK_PROBE" != "/" ]; do
|
|
54
|
+
DISK_PROBE="$(dirname "$DISK_PROBE")"
|
|
55
|
+
done
|
|
56
|
+
DISK_AVAILABLE_KB="$(df -Pk "$DISK_PROBE" | awk 'NR == 2 { print $4 }')"
|
|
57
|
+
case "$DISK_AVAILABLE_KB" in
|
|
58
|
+
''|*[!0-9]*) echo 'unable to determine disk availability' >&2; exit 1 ;;
|
|
59
|
+
esac
|
|
60
|
+
for URL in https://ghcr.io https://get.docker.com https://huggingface.co; do
|
|
61
|
+
curl -fsS -o /dev/null -m 10 "$URL"
|
|
62
|
+
done
|
|
63
|
+
printf 'architecture=%s\\n' "$ARCHITECTURE"
|
|
64
|
+
printf 'existing_install=%s\\n' "$EXISTING_INSTALL"
|
|
65
|
+
printf 'cpu_cores=%s\\n' "$CPU_CORES"
|
|
66
|
+
printf 'memory_kib=%s\\n' "$MEMORY_KIB"
|
|
67
|
+
printf 'disk_available_kb=%s\\n' "$DISK_AVAILABLE_KB"
|
|
68
|
+
`;
|
|
69
|
+
const STALE_CLEANUP = `set -eu
|
|
70
|
+
exec 2>&1
|
|
71
|
+
find /tmp -xdev -maxdepth 1 -type f -user "$(id -un)" -mtime +0 \\
|
|
72
|
+
\\( -name 'create-aura-????????-????-????-????-????????????-installer.sh' \\
|
|
73
|
+
-o -name 'create-aura-????????-????-????-????-????????????-install.conf' \\
|
|
74
|
+
-o -name 'create-aura-????????-????-????-????-????????????-run.sh' \\) \\
|
|
75
|
+
-delete
|
|
76
|
+
`;
|
|
77
|
+
// R6: `--` before `--config`, mirroring local.ts's installLocal -- makeself's runtime header
|
|
78
|
+
// parses argv against ITS OWN flag set before it execs the embedded script, so
|
|
79
|
+
// `install-appliance.run --config X` dies with "Unrecognized flag" and install.sh never runs.
|
|
80
|
+
// Exported (unlike the reference's private constant) so remote.test.ts can assert the fix
|
|
81
|
+
// directly on the script's own source: the flag never appears in any ssh/scp argv, only
|
|
82
|
+
// inside this transferred file, so an argv-only assertion would not exercise it.
|
|
83
|
+
export const REMOTE_INSTALL_SCRIPT = `#!/bin/sh
|
|
84
|
+
set -eu
|
|
85
|
+
exec 2>&1
|
|
86
|
+
INSTALLER="$1"
|
|
87
|
+
CONFIG="$2"
|
|
88
|
+
RUNNER="$0"
|
|
89
|
+
cleanup() { rm -f -- "$CONFIG" "$INSTALLER" "$RUNNER"; }
|
|
90
|
+
trap cleanup EXIT
|
|
91
|
+
trap 'exit 129' HUP
|
|
92
|
+
trap 'exit 130' INT
|
|
93
|
+
trap 'exit 143' TERM
|
|
94
|
+
chmod 700 "$INSTALLER"
|
|
95
|
+
chmod 600 "$CONFIG"
|
|
96
|
+
sudo bash "$INSTALLER" -- --config "$CONFIG"
|
|
97
|
+
`;
|
|
98
|
+
const CURRENT_CLEANUP = `set -eu
|
|
99
|
+
exec 2>&1
|
|
100
|
+
rm -f -- "$1" "$2" "$3"
|
|
101
|
+
`;
|
|
102
|
+
function remoteScriptCommand(script, args = []) {
|
|
103
|
+
const encodedScript = Buffer.from(script, 'utf8').toString('base64');
|
|
104
|
+
const suffix = args.length === 0 ? '' : ` -- ${args.join(' ')}`;
|
|
105
|
+
return `printf %s ${encodedScript} | base64 --decode | sh -s${suffix}`;
|
|
106
|
+
}
|
|
107
|
+
async function stageRemoteFiles(artifact, config, remoteId, tempRoot) {
|
|
108
|
+
const directory = await mkdtemp(join(tempRoot, 'create-aura-upload-'));
|
|
109
|
+
const installerPath = join(directory, `create-aura-${remoteId}-installer.sh`);
|
|
110
|
+
const configPath = join(directory, `create-aura-${remoteId}-install.conf`);
|
|
111
|
+
const runnerPath = join(directory, `create-aura-${remoteId}-run.sh`);
|
|
112
|
+
try {
|
|
113
|
+
await chmod(directory, 0o700);
|
|
114
|
+
await copyFile(artifact.path, installerPath);
|
|
115
|
+
await copyFile(config.path, configPath);
|
|
116
|
+
await writeFile(runnerPath, REMOTE_INSTALL_SCRIPT, { mode: 0o700, flag: 'wx' });
|
|
117
|
+
await chmod(installerPath, 0o700);
|
|
118
|
+
await chmod(configPath, 0o600);
|
|
119
|
+
await chmod(runnerPath, 0o700);
|
|
120
|
+
}
|
|
121
|
+
catch (error) {
|
|
122
|
+
await rm(directory, { recursive: true, force: true });
|
|
123
|
+
throw error;
|
|
124
|
+
}
|
|
125
|
+
return {
|
|
126
|
+
path: directory,
|
|
127
|
+
installerPath,
|
|
128
|
+
configPath,
|
|
129
|
+
runnerPath,
|
|
130
|
+
cleanup: async () => rm(directory, { recursive: true, force: true }),
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
// Ported unchanged (task instructions): validated defensively even though collectTarget
|
|
134
|
+
// already validated host/username/port once at collection time.
|
|
135
|
+
export function sshDestination(target) {
|
|
136
|
+
const username = validateUsername(target.username);
|
|
137
|
+
const host = validateHost(target.host);
|
|
138
|
+
return `${username}@${isIP(host) === 6 ? `[${host}]` : host}`;
|
|
139
|
+
}
|
|
140
|
+
function parseProbeOutput(output) {
|
|
141
|
+
const values = new Map();
|
|
142
|
+
for (const line of output.split(/\r?\n/)) {
|
|
143
|
+
const separator = line.indexOf('=');
|
|
144
|
+
if (separator <= 0)
|
|
145
|
+
continue;
|
|
146
|
+
values.set(line.slice(0, separator), line.slice(separator + 1));
|
|
147
|
+
}
|
|
148
|
+
const rawArchitecture = values.get('architecture');
|
|
149
|
+
const rawExisting = values.get('existing_install');
|
|
150
|
+
const rawCpuCores = values.get('cpu_cores');
|
|
151
|
+
const rawMemory = values.get('memory_kib');
|
|
152
|
+
const rawDisk = values.get('disk_available_kb');
|
|
153
|
+
if (rawArchitecture === undefined
|
|
154
|
+
|| !['true', 'false'].includes(rawExisting ?? '')
|
|
155
|
+
|| rawCpuCores === undefined
|
|
156
|
+
|| rawMemory === undefined
|
|
157
|
+
|| rawDisk === undefined) {
|
|
158
|
+
throw new Error('invalidRemotePreflightOutput');
|
|
159
|
+
}
|
|
160
|
+
// R2: the same three hard floors install.sh:172-187 enforces locally, run against the
|
|
161
|
+
// TARGET's own numbers -- not the operator's laptop.
|
|
162
|
+
assertSufficientCpuCores(rawCpuCores);
|
|
163
|
+
assertSufficientMemory(rawMemory);
|
|
164
|
+
assertSufficientDiskSpace(rawDisk);
|
|
165
|
+
return {
|
|
166
|
+
architecture: normalizeArchitecture(rawArchitecture),
|
|
167
|
+
existingInstall: rawExisting === 'true',
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
export async function preflightRemote(runner, target, installDir, platform = process.platform) {
|
|
171
|
+
await runner.run('ssh', ['-V']);
|
|
172
|
+
if (platform === 'win32') {
|
|
173
|
+
await runner.run('where.exe', ['scp.exe']);
|
|
174
|
+
}
|
|
175
|
+
else if (platform === 'linux') {
|
|
176
|
+
await runner.run('sh', [
|
|
177
|
+
'-c',
|
|
178
|
+
'command -v "$1" >/dev/null 2>&1',
|
|
179
|
+
'create-aura',
|
|
180
|
+
'scp',
|
|
181
|
+
]);
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
throw new Error('unsupportedRemoteClientPlatform');
|
|
185
|
+
}
|
|
186
|
+
const result = await runner.run('ssh', [
|
|
187
|
+
'-p',
|
|
188
|
+
String(validatePort(String(target.port))),
|
|
189
|
+
sshDestination(target),
|
|
190
|
+
remoteScriptCommand(REMOTE_PROBE, [Buffer.from(installDir, 'utf8').toString('base64')]),
|
|
191
|
+
], { terminal: true });
|
|
192
|
+
return parseProbeOutput(result.stdout);
|
|
193
|
+
}
|
|
194
|
+
export async function installRemote(runner, target, artifact, config, settings, remoteId = randomUUID(), warn = (message) => process.stderr.write(`${message}\n`), tempRoot = tmpdir()) {
|
|
195
|
+
if (!REMOTE_ID_PATTERN.test(remoteId))
|
|
196
|
+
throw new Error('invalidRemoteId');
|
|
197
|
+
const destination = sshDestination(target);
|
|
198
|
+
const port = String(validatePort(String(target.port)));
|
|
199
|
+
const installerPath = `/tmp/create-aura-${remoteId}-installer.sh`;
|
|
200
|
+
const configPath = `/tmp/create-aura-${remoteId}-install.conf`;
|
|
201
|
+
const runnerPath = `/tmp/create-aura-${remoteId}-run.sh`;
|
|
202
|
+
// R7: the OpenRouter key travels in redactions on the remote path too -- its output crosses
|
|
203
|
+
// an SSH session and often a terminal someone is screen-sharing, so it matters MORE here
|
|
204
|
+
// than on the local path, not less.
|
|
205
|
+
const redactions = [settings.openrouterApiKey];
|
|
206
|
+
await runner.run('ssh', ['-p', port, destination, remoteScriptCommand(STALE_CLEANUP)], { terminal: true, redactions });
|
|
207
|
+
const staged = await stageRemoteFiles(artifact, config, remoteId, tempRoot);
|
|
208
|
+
let operationFailed = false;
|
|
209
|
+
let operationError;
|
|
210
|
+
try {
|
|
211
|
+
await runner.run('scp', [
|
|
212
|
+
'-P',
|
|
213
|
+
port,
|
|
214
|
+
staged.installerPath,
|
|
215
|
+
staged.configPath,
|
|
216
|
+
staged.runnerPath,
|
|
217
|
+
`${destination}:/tmp/`,
|
|
218
|
+
], { terminal: true, redactions });
|
|
219
|
+
await runner.run('ssh', ['-tt', '-p', port, destination, 'sh', runnerPath, installerPath, configPath], { terminal: true, redactions });
|
|
220
|
+
}
|
|
221
|
+
catch (error) {
|
|
222
|
+
operationFailed = true;
|
|
223
|
+
operationError = error;
|
|
224
|
+
try {
|
|
225
|
+
await runner.run('ssh', [
|
|
226
|
+
'-p',
|
|
227
|
+
port,
|
|
228
|
+
destination,
|
|
229
|
+
remoteScriptCommand(CURRENT_CLEANUP, [installerPath, configPath, runnerPath]),
|
|
230
|
+
], { terminal: true, redactions });
|
|
231
|
+
}
|
|
232
|
+
catch {
|
|
233
|
+
warn('remoteCleanupFailed');
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
try {
|
|
237
|
+
await staged.cleanup();
|
|
238
|
+
}
|
|
239
|
+
catch (cleanupError) {
|
|
240
|
+
warn('localStagingCleanupFailed');
|
|
241
|
+
if (!operationFailed)
|
|
242
|
+
throw cleanupError;
|
|
243
|
+
}
|
|
244
|
+
if (operationFailed)
|
|
245
|
+
throw operationError;
|
|
246
|
+
}
|
|
247
|
+
function shellQuote(value) {
|
|
248
|
+
return `'${value.replace(/'/g, "'\\''")}'`;
|
|
249
|
+
}
|
|
250
|
+
// R2 (Task 6 controller ruling): collectSettings's GPU/Ollama probes (modelroute.ts) take a
|
|
251
|
+
// plain CommandRunner and know nothing about SSH -- Task 5's own ruling forbids teaching them
|
|
252
|
+
// ("Nothing inside collectSettings or modelroute.ts may learn what an SSH is"). This wraps one
|
|
253
|
+
// so its run(command, args) executes ON THE REMOTE TARGET via sshDestination instead of on the
|
|
254
|
+
// machine running the wizard. Each argument is single-quoted because ssh joins the trailing
|
|
255
|
+
// argv into ONE string for the remote shell to re-parse (it does not preserve argv
|
|
256
|
+
// boundaries the way execa's direct spawn does): an operator-typed Ollama base URL reaching
|
|
257
|
+
// modelroute.ts's `docker run ... wget ... "$url"` unquoted would let shell metacharacters in
|
|
258
|
+
// that URL execute on the target.
|
|
259
|
+
export function createSshProbeRunner(runner, target) {
|
|
260
|
+
const destination = sshDestination(target);
|
|
261
|
+
const port = String(validatePort(String(target.port)));
|
|
262
|
+
return {
|
|
263
|
+
async run(command, args = [], options) {
|
|
264
|
+
return runner.run('ssh', ['-p', port, destination, ...[command, ...args].map(shellQuote)], options);
|
|
265
|
+
},
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
//# sourceMappingURL=remote.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remote.js","sourceRoot":"","sources":["../src/remote.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC3E,OAAO,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAChC,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAGjC,OAAO,EACL,wBAAwB,EACxB,yBAAyB,EACzB,sBAAsB,EACtB,qBAAqB,GACtB,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAE/E,MAAM,iBAAiB,GAAG,gEAAgE,CAAC;AAE3F,2FAA2F;AAC3F,2FAA2F;AAC3F,4FAA4F;AAC5F,uDAAuD;AACvD,4FAA4F;AAC5F,wFAAwF;AACxF,wCAAwC;AACxC,0FAA0F;AAC1F,0FAA0F;AAC1F,8FAA8F;AAC9F,2FAA2F;AAC3F,2FAA2F;AAC3F,8BAA8B;AAC9B,MAAM,YAAY,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8CpB,CAAC;AAEF,MAAM,aAAa,GAAG;;;;;;;CAOrB,CAAC;AAEF,6FAA6F;AAC7F,+EAA+E;AAC/E,8FAA8F;AAC9F,0FAA0F;AAC1F,wFAAwF;AACxF,iFAAiF;AACjF,MAAM,CAAC,MAAM,qBAAqB,GAAG;;;;;;;;;;;;;;CAcpC,CAAC;AAEF,MAAM,eAAe,GAAG;;;CAGvB,CAAC;AAUF,SAAS,mBAAmB,CAAC,MAAc,EAAE,OAA0B,EAAE;IACvE,MAAM,aAAa,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACrE,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;IAChE,OAAO,aAAa,aAAa,6BAA6B,MAAM,EAAE,CAAC;AACzE,CAAC;AAED,KAAK,UAAU,gBAAgB,CAC7B,QAAuB,EACvB,MAAqB,EACrB,QAAgB,EAChB,QAAgB;IAEhB,MAAM,SAAS,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,qBAAqB,CAAC,CAAC,CAAC;IACvE,MAAM,aAAa,GAAG,IAAI,CAAC,SAAS,EAAE,eAAe,QAAQ,eAAe,CAAC,CAAC;IAC9E,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,EAAE,eAAe,QAAQ,eAAe,CAAC,CAAC;IAC3E,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,EAAE,eAAe,QAAQ,SAAS,CAAC,CAAC;IAErE,IAAI,CAAC;QACH,MAAM,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;QAC9B,MAAM,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC;QAC7C,MAAM,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;QACxC,MAAM,SAAS,CAAC,UAAU,EAAE,qBAAqB,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QAChF,MAAM,KAAK,CAAC,aAAa,EAAE,KAAK,CAAC,CAAC;QAClC,MAAM,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;QAC/B,MAAM,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;IACjC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,EAAE,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACtD,MAAM,KAAK,CAAC;IACd,CAAC;IAED,OAAO;QACL,IAAI,EAAE,SAAS;QACf,aAAa;QACb,UAAU;QACV,UAAU;QACV,OAAO,EAAE,KAAK,IAAI,EAAE,CAAC,EAAE,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;KACrE,CAAC;AACJ,CAAC;AAED,wFAAwF;AACxF,gEAAgE;AAChE,MAAM,UAAU,cAAc,CAAC,MAAoB;IACjD,MAAM,QAAQ,GAAG,gBAAgB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IACnD,MAAM,IAAI,GAAG,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACvC,OAAO,GAAG,QAAQ,IAAI,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;AAChE,CAAC;AAED,SAAS,gBAAgB,CAAC,MAAc;IACtC,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAC;IACzC,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;QACzC,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACpC,IAAI,SAAS,IAAI,CAAC;YAAE,SAAS;QAC7B,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC;IAClE,CAAC;IAED,MAAM,eAAe,GAAG,MAAM,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IACnD,MAAM,WAAW,GAAG,MAAM,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;IACnD,MAAM,WAAW,GAAG,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IAC5C,MAAM,SAAS,GAAG,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;IAC3C,MAAM,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;IAChD,IACE,eAAe,KAAK,SAAS;WAC1B,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,QAAQ,CAAC,WAAW,IAAI,EAAE,CAAC;WAC9C,WAAW,KAAK,SAAS;WACzB,SAAS,KAAK,SAAS;WACvB,OAAO,KAAK,SAAS,EACxB,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;IAClD,CAAC;IAED,sFAAsF;IACtF,qDAAqD;IACrD,wBAAwB,CAAC,WAAW,CAAC,CAAC;IACtC,sBAAsB,CAAC,SAAS,CAAC,CAAC;IAClC,yBAAyB,CAAC,OAAO,CAAC,CAAC;IAEnC,OAAO;QACL,YAAY,EAAE,qBAAqB,CAAC,eAAe,CAAC;QACpD,eAAe,EAAE,WAAW,KAAK,MAAM;KACxC,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,MAAqB,EACrB,MAAoB,EACpB,UAAkB,EAClB,WAA4B,OAAO,CAAC,QAAQ;IAE5C,MAAM,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;IAChC,IAAI,QAAQ,KAAK,OAAO,EAAE,CAAC;QACzB,MAAM,MAAM,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC;IAC7C,CAAC;SAAM,IAAI,QAAQ,KAAK,OAAO,EAAE,CAAC;QAChC,MAAM,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE;YACrB,IAAI;YACJ,iCAAiC;YACjC,aAAa;YACb,KAAK;SACN,CAAC,CAAC;IACL,CAAC;SAAM,CAAC;QACN,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;IACrD,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,GAAG,CAC7B,KAAK,EACL;QACE,IAAI;QACJ,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;QACzC,cAAc,CAAC,MAAM,CAAC;QACtB,mBAAmB,CAAC,YAAY,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;KACxF,EACD,EAAE,QAAQ,EAAE,IAAI,EAAE,CACnB,CAAC;IAEF,OAAO,gBAAgB,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;AACzC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,MAAqB,EACrB,MAAoB,EACpB,QAAuB,EACvB,MAAqB,EACrB,QAAyB,EACzB,WAAmB,UAAU,EAAE,EAC/B,OAAoB,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,OAAO,IAAI,CAAC,EACrE,QAAQ,GAAG,MAAM,EAAE;IAEnB,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,QAAQ,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC;IAE1E,MAAM,WAAW,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;IAC3C,MAAM,IAAI,GAAG,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACvD,MAAM,aAAa,GAAG,oBAAoB,QAAQ,eAAe,CAAC;IAClE,MAAM,UAAU,GAAG,oBAAoB,QAAQ,eAAe,CAAC;IAC/D,MAAM,UAAU,GAAG,oBAAoB,QAAQ,SAAS,CAAC;IACzD,4FAA4F;IAC5F,yFAAyF;IACzF,oCAAoC;IACpC,MAAM,UAAU,GAAG,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC;IAE/C,MAAM,MAAM,CAAC,GAAG,CACd,KAAK,EACL,CAAC,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,mBAAmB,CAAC,aAAa,CAAC,CAAC,EAC7D,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,EAAE,CAC/B,CAAC;IAEF,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC5E,IAAI,eAAe,GAAG,KAAK,CAAC;IAC5B,IAAI,cAAuB,CAAC;IAC5B,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,GAAG,CACd,KAAK,EACL;YACE,IAAI;YACJ,IAAI;YACJ,MAAM,CAAC,aAAa;YACpB,MAAM,CAAC,UAAU;YACjB,MAAM,CAAC,UAAU;YACjB,GAAG,WAAW,QAAQ;SACvB,EACD,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,EAAE,CAC/B,CAAC;QACF,MAAM,MAAM,CAAC,GAAG,CACd,KAAK,EACL,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,UAAU,EAAE,aAAa,EAAE,UAAU,CAAC,EAC7E,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,EAAE,CAC/B,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,eAAe,GAAG,IAAI,CAAC;QACvB,cAAc,GAAG,KAAK,CAAC;QACvB,IAAI,CAAC;YACH,MAAM,MAAM,CAAC,GAAG,CACd,KAAK,EACL;gBACE,IAAI;gBACJ,IAAI;gBACJ,WAAW;gBACX,mBAAmB,CAAC,eAAe,EAAE,CAAC,aAAa,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC;aAC9E,EACD,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,EAAE,CAC/B,CAAC;QACJ,CAAC;QAAC,MAAM,CAAC;YACP,IAAI,CAAC,qBAAqB,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC;IAED,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,OAAO,EAAE,CAAC;IACzB,CAAC;IAAC,OAAO,YAAY,EAAE,CAAC;QACtB,IAAI,CAAC,2BAA2B,CAAC,CAAC;QAClC,IAAI,CAAC,eAAe;YAAE,MAAM,YAAY,CAAC;IAC3C,CAAC;IAED,IAAI,eAAe;QAAE,MAAM,cAAc,CAAC;AAC5C,CAAC;AAED,SAAS,UAAU,CAAC,KAAa;IAC/B,OAAO,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC;AAC7C,CAAC;AAED,4FAA4F;AAC5F,8FAA8F;AAC9F,+FAA+F;AAC/F,+FAA+F;AAC/F,4FAA4F;AAC5F,mFAAmF;AACnF,4FAA4F;AAC5F,8FAA8F;AAC9F,kCAAkC;AAClC,MAAM,UAAU,oBAAoB,CAAC,MAAqB,EAAE,MAAoB;IAC9E,MAAM,WAAW,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;IAC3C,MAAM,IAAI,GAAG,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAEvD,OAAO;QACL,KAAK,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,GAAG,EAAE,EAAE,OAAO;YACnC,OAAO,MAAM,CAAC,GAAG,CACf,KAAK,EACL,CAAC,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,EAChE,OAAO,CACR,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { SupportedArchitecture } from './preflight.js';
|
|
2
|
+
export type InstallMode = 'local' | 'remote';
|
|
3
|
+
export interface RemoteTarget {
|
|
4
|
+
host: string;
|
|
5
|
+
port: number;
|
|
6
|
+
username: string;
|
|
7
|
+
}
|
|
8
|
+
export interface PreflightResult {
|
|
9
|
+
architecture: SupportedArchitecture;
|
|
10
|
+
existingInstall: boolean;
|
|
11
|
+
}
|
|
12
|
+
export interface InstallSettings {
|
|
13
|
+
installDir: string;
|
|
14
|
+
appliance: boolean;
|
|
15
|
+
gvisor: boolean;
|
|
16
|
+
llmProvider: string;
|
|
17
|
+
llmBaseUrl: string;
|
|
18
|
+
llmModel: string;
|
|
19
|
+
openrouterApiKey?: string;
|
|
20
|
+
embedImage: string;
|
|
21
|
+
embedNgl: string;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAE5D,MAAM,MAAM,WAAW,GAAG,OAAO,GAAG,QAAQ,CAAC;AAE7C,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB;AAKD,MAAM,WAAW,eAAe;IAC9B,YAAY,EAAE,qBAAqB,CAAC;IACpC,eAAe,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,OAAO,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare class ValidationError extends Error {
|
|
2
|
+
readonly code: string;
|
|
3
|
+
constructor(code: string);
|
|
4
|
+
}
|
|
5
|
+
export declare function validateHost(raw: string): string;
|
|
6
|
+
export declare function validatePort(raw: string): number;
|
|
7
|
+
export declare function validateUsername(raw: string): string;
|
|
8
|
+
export declare function validateInstallDir(raw: string): string;
|
|
9
|
+
export declare function assertNoLineBreak(raw: string, code: string): void;
|
|
10
|
+
export declare function validateBaseUrl(raw: string): string;
|
|
11
|
+
export declare function validateModelId(raw: string): string;
|
|
12
|
+
//# sourceMappingURL=validation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"AAGA,qBAAa,eAAgB,SAAQ,KAAK;aACZ,IAAI,EAAE,MAAM;gBAAZ,IAAI,EAAE,MAAM;CAIzC;AAKD,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAMhD;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAQhD;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAIpD;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAatD;AAQD,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAEjE;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAiBnD;AAID,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAKnD"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { isIP } from 'node:net';
|
|
2
|
+
import { posix } from 'node:path';
|
|
3
|
+
export class ValidationError extends Error {
|
|
4
|
+
code;
|
|
5
|
+
constructor(code) {
|
|
6
|
+
super(code);
|
|
7
|
+
this.code = code;
|
|
8
|
+
this.name = 'ValidationError';
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
const hostnamePattern = /^(?=.{1,253}$)(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)(?:\.(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?))*$/;
|
|
12
|
+
const usernamePattern = /^[a-z_][a-z0-9_-]{0,31}$/;
|
|
13
|
+
export function validateHost(raw) {
|
|
14
|
+
const value = raw.trim();
|
|
15
|
+
if (!isIP(value) && !hostnamePattern.test(value)) {
|
|
16
|
+
throw new ValidationError('invalidHost');
|
|
17
|
+
}
|
|
18
|
+
return value;
|
|
19
|
+
}
|
|
20
|
+
export function validatePort(raw) {
|
|
21
|
+
const trimmed = raw.trim();
|
|
22
|
+
if (!/^\d+$/.test(trimmed))
|
|
23
|
+
throw new ValidationError('invalidPort');
|
|
24
|
+
const value = Number(trimmed);
|
|
25
|
+
if (!Number.isInteger(value) || value < 1 || value > 65535) {
|
|
26
|
+
throw new ValidationError('invalidPort');
|
|
27
|
+
}
|
|
28
|
+
return value;
|
|
29
|
+
}
|
|
30
|
+
export function validateUsername(raw) {
|
|
31
|
+
const value = raw.trim();
|
|
32
|
+
if (!usernamePattern.test(value))
|
|
33
|
+
throw new ValidationError('invalidUsername');
|
|
34
|
+
return value;
|
|
35
|
+
}
|
|
36
|
+
export function validateInstallDir(raw) {
|
|
37
|
+
if ([...raw].some((character) => {
|
|
38
|
+
const code = character.codePointAt(0) ?? 0;
|
|
39
|
+
return code <= 31 || code === 127;
|
|
40
|
+
})) {
|
|
41
|
+
throw new ValidationError('invalidInstallDir');
|
|
42
|
+
}
|
|
43
|
+
const normalized = posix.normalize(raw.trim());
|
|
44
|
+
const value = normalized.length > 1 ? normalized.replace(/\/$/, '') : normalized;
|
|
45
|
+
if (!value.startsWith('/') || value === '/') {
|
|
46
|
+
throw new ValidationError('invalidInstallDir');
|
|
47
|
+
}
|
|
48
|
+
return value;
|
|
49
|
+
}
|
|
50
|
+
// A newline reaches set_env_value, which writes two .env lines; install.sh's reader takes
|
|
51
|
+
// the first and docker compose takes the last, so the installer and the running appliance
|
|
52
|
+
// would trust different secrets. install.sh rejects it too -- this layer can say so while
|
|
53
|
+
// the operator is still typing. Checked on the raw value (not the trimmed one), mirroring
|
|
54
|
+
// validateInstallDir's control-character check above, since trimming could hide a break
|
|
55
|
+
// sitting at the very edge of the input.
|
|
56
|
+
export function assertNoLineBreak(raw, code) {
|
|
57
|
+
if (/[\n\r]/.test(raw))
|
|
58
|
+
throw new ValidationError(code);
|
|
59
|
+
}
|
|
60
|
+
export function validateBaseUrl(raw) {
|
|
61
|
+
assertNoLineBreak(raw, 'invalidBaseUrl');
|
|
62
|
+
const value = raw.trim();
|
|
63
|
+
let parsed;
|
|
64
|
+
try {
|
|
65
|
+
parsed = new URL(value);
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
throw new ValidationError('invalidBaseUrl');
|
|
69
|
+
}
|
|
70
|
+
if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
|
|
71
|
+
throw new ValidationError('invalidBaseUrl');
|
|
72
|
+
}
|
|
73
|
+
// modelroute.ts's tagsUrlFor only strips a trailing /v1; a base URL that ends in a bare
|
|
74
|
+
// trailing slash (no /v1) would reach it unchanged and produce `${base}//api/tags`, a
|
|
75
|
+
// double slash. Stripping it once here means every downstream consumer sees a URL with
|
|
76
|
+
// no trailing slash, whether or not it happens to end in /v1.
|
|
77
|
+
return value.replace(/\/$/, '');
|
|
78
|
+
}
|
|
79
|
+
// Aura is agnostic about which model an operator runs: no vendor-specific naming shape is
|
|
80
|
+
// enforced here, only that a value was actually given and carries no line break.
|
|
81
|
+
export function validateModelId(raw) {
|
|
82
|
+
assertNoLineBreak(raw, 'invalidModelId');
|
|
83
|
+
const value = raw.trim();
|
|
84
|
+
if (value.length === 0)
|
|
85
|
+
throw new ValidationError('invalidModelId');
|
|
86
|
+
return value;
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=validation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation.js","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"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"}
|