@arcote.tech/arc-cli 0.6.0 → 0.6.2
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/dist/index.js +47 -29
- package/package.json +7 -7
- package/runtime/entrypoint.sh +31 -0
- package/src/builder/dependency-collector.ts +21 -9
- package/src/commands/platform-deploy.ts +21 -5
- package/src/deploy/remote-sync.ts +6 -8
- package/src/deploy/ssh.ts +14 -4
- package/src/platform/deploy-api.ts +5 -1
- package/src/platform/shared.ts +4 -1
package/dist/index.js
CHANGED
|
@@ -26446,7 +26446,7 @@ ${colors3.yellow}Type declaration errors:${colors3.reset}`);
|
|
|
26446
26446
|
}
|
|
26447
26447
|
|
|
26448
26448
|
// src/platform/shared.ts
|
|
26449
|
-
import { copyFileSync
|
|
26449
|
+
import { copyFileSync, existsSync as existsSync10, mkdirSync as mkdirSync10, readFileSync as readFileSync11, readdirSync as readdirSync6, rmSync as rmSync3, writeFileSync as writeFileSync10 } from "fs";
|
|
26450
26450
|
import { dirname as dirname6, join as join12 } from "path";
|
|
26451
26451
|
|
|
26452
26452
|
// src/builder/module-builder.ts
|
|
@@ -27254,7 +27254,7 @@ async function buildStyles(rootDir, arcDir, packages, themePath, cache, noCache)
|
|
|
27254
27254
|
|
|
27255
27255
|
// src/builder/dependency-collector.ts
|
|
27256
27256
|
import { createHash } from "crypto";
|
|
27257
|
-
import {
|
|
27257
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync8, readFileSync as readFileSync9, writeFileSync as writeFileSync8 } from "fs";
|
|
27258
27258
|
import { basename as basename3, join as join10 } from "path";
|
|
27259
27259
|
var FRAMEWORK_PEERS = [
|
|
27260
27260
|
"@arcote.tech/arc",
|
|
@@ -27276,16 +27276,22 @@ function collectFrameworkDeps(arcDir, rootDir, packages) {
|
|
|
27276
27276
|
const manifestPath = join10(arcDir, "package.json");
|
|
27277
27277
|
writeFileSync8(manifestPath, JSON.stringify(manifest, null, 2) + `
|
|
27278
27278
|
`);
|
|
27279
|
-
const rootLock = join10(rootDir, "bun.lock");
|
|
27280
27279
|
const targetLock = join10(arcDir, "bun.lock");
|
|
27281
|
-
|
|
27282
|
-
|
|
27283
|
-
}
|
|
27284
|
-
const hash = sha256OfFiles2([manifestPath, targetLock]);
|
|
27280
|
+
writeFileSync8(targetLock, "");
|
|
27281
|
+
const hash = sha256ConcatHex([manifestPath, targetLock]);
|
|
27285
27282
|
writeFileSync8(join10(arcDir, ".deps-hash"), hash + `
|
|
27286
27283
|
`);
|
|
27287
27284
|
return { hash, manifestPath };
|
|
27288
27285
|
}
|
|
27286
|
+
function sha256ConcatHex(paths) {
|
|
27287
|
+
const hash = createHash("sha256");
|
|
27288
|
+
for (const p of paths) {
|
|
27289
|
+
if (existsSync9(p)) {
|
|
27290
|
+
hash.update(readFileSync9(p));
|
|
27291
|
+
}
|
|
27292
|
+
}
|
|
27293
|
+
return hash.digest("hex");
|
|
27294
|
+
}
|
|
27289
27295
|
function collectModuleDeps(arcDir, pkg) {
|
|
27290
27296
|
const safeName = basename3(pkg.path);
|
|
27291
27297
|
const moduleDir = join10(arcDir, "modules", safeName);
|
|
@@ -27452,7 +27458,7 @@ function resolveWorkspace() {
|
|
|
27452
27458
|
log2("Scanning workspaces...");
|
|
27453
27459
|
const packages = discoverPackages(rootDir);
|
|
27454
27460
|
ok(`Found ${packages.length} package(s): ${packages.map((p) => p.name).join(", ")}`);
|
|
27455
|
-
if (packages.length === 0) {
|
|
27461
|
+
if (packages.length === 0 && process.env.ARC_DEPLOY_API !== "1") {
|
|
27456
27462
|
err("No workspace packages found.");
|
|
27457
27463
|
process.exit(1);
|
|
27458
27464
|
}
|
|
@@ -27613,7 +27619,7 @@ async function copyBrowserAssets(ws, cache, noCache) {
|
|
|
27613
27619
|
for (const asset of assets) {
|
|
27614
27620
|
const dest = join12(ws.assetsDir, asset.to);
|
|
27615
27621
|
mkdirSync10(dirname6(dest), { recursive: true });
|
|
27616
|
-
|
|
27622
|
+
copyFileSync(asset.src, dest);
|
|
27617
27623
|
outputHashes[asset.to] = sha256Hex(readFileSync11(dest));
|
|
27618
27624
|
}
|
|
27619
27625
|
updateCache(cache, unitId, inputHash, { outputHashes });
|
|
@@ -27821,7 +27827,7 @@ async function platformBuild(opts = {}) {
|
|
|
27821
27827
|
|
|
27822
27828
|
// src/commands/platform-deploy.ts
|
|
27823
27829
|
import { existsSync as existsSync14, readFileSync as readFileSync14 } from "fs";
|
|
27824
|
-
import { join as join18 } from "path";
|
|
27830
|
+
import { dirname as dirname7, join as join18 } from "path";
|
|
27825
27831
|
|
|
27826
27832
|
// src/deploy/bootstrap.ts
|
|
27827
27833
|
import { mkdirSync as mkdirSync13, writeFileSync as writeFileSync14 } from "fs";
|
|
@@ -28510,17 +28516,19 @@ async function streamToString(stream2) {
|
|
|
28510
28516
|
return new Response(stream2).text();
|
|
28511
28517
|
}
|
|
28512
28518
|
function baseSshArgs(target) {
|
|
28513
|
-
const
|
|
28519
|
+
const key = target.sshKey ?? `${process.env.HOME}/.ssh/id_ed25519`;
|
|
28520
|
+
return [
|
|
28514
28521
|
"-o",
|
|
28515
28522
|
"BatchMode=yes",
|
|
28516
28523
|
"-o",
|
|
28517
28524
|
"StrictHostKeyChecking=accept-new",
|
|
28525
|
+
"-o",
|
|
28526
|
+
"IdentitiesOnly=yes",
|
|
28527
|
+
"-i",
|
|
28528
|
+
key,
|
|
28518
28529
|
"-p",
|
|
28519
28530
|
String(target.port)
|
|
28520
28531
|
];
|
|
28521
|
-
if (target.sshKey)
|
|
28522
|
-
args.push("-i", target.sshKey);
|
|
28523
|
-
return args;
|
|
28524
28532
|
}
|
|
28525
28533
|
async function sshExec(target, cmd, opts = {}) {
|
|
28526
28534
|
const args = [
|
|
@@ -28574,16 +28582,19 @@ async function waitForSsh(target, opts = {}) {
|
|
|
28574
28582
|
throw new Error(`Timed out waiting for SSH on ${target.user}@${target.host}`);
|
|
28575
28583
|
}
|
|
28576
28584
|
async function scpUpload(target, localPath, remotePath) {
|
|
28585
|
+
const key = target.sshKey ?? `${process.env.HOME}/.ssh/id_ed25519`;
|
|
28577
28586
|
const args = [
|
|
28578
28587
|
"-o",
|
|
28579
28588
|
"BatchMode=yes",
|
|
28580
28589
|
"-o",
|
|
28581
28590
|
"StrictHostKeyChecking=accept-new",
|
|
28591
|
+
"-o",
|
|
28592
|
+
"IdentitiesOnly=yes",
|
|
28593
|
+
"-i",
|
|
28594
|
+
key,
|
|
28582
28595
|
"-P",
|
|
28583
28596
|
String(target.port)
|
|
28584
28597
|
];
|
|
28585
|
-
if (target.sshKey)
|
|
28586
|
-
args.push("-i", target.sshKey);
|
|
28587
28598
|
args.push(localPath, `${target.user}@${target.host}:${remotePath}`);
|
|
28588
28599
|
const proc2 = spawn3({ cmd: ["scp", ...args], stderr: "pipe" });
|
|
28589
28600
|
const [stderr, exitCode] = await Promise.all([
|
|
@@ -28781,10 +28792,7 @@ async function syncEnv(inputs) {
|
|
|
28781
28792
|
console.log("[arc] Pushing framework deps...");
|
|
28782
28793
|
const form = new FormData;
|
|
28783
28794
|
form.append("package.json", new Blob([readFileSync13(join17(ws.arcDir, "package.json"))]), "package.json");
|
|
28784
|
-
|
|
28785
|
-
if (existsSync13(lockPath)) {
|
|
28786
|
-
form.append("bun.lock", new Blob([readFileSync13(lockPath)]), "bun.lock");
|
|
28787
|
-
}
|
|
28795
|
+
form.append("bun.lock", new Blob([""]), "bun.lock");
|
|
28788
28796
|
const res = await fetch(`${base2()}/api/deploy/framework`, {
|
|
28789
28797
|
method: "POST",
|
|
28790
28798
|
body: form
|
|
@@ -29666,13 +29674,23 @@ async function platformDeploy(envArg, options = {}) {
|
|
|
29666
29674
|
}
|
|
29667
29675
|
}
|
|
29668
29676
|
function readCliVersion() {
|
|
29677
|
+
const candidates = [];
|
|
29678
|
+
const entry = process.argv[1];
|
|
29679
|
+
if (entry) {
|
|
29680
|
+
candidates.push(join18(dirname7(entry), "..", "package.json"));
|
|
29681
|
+
}
|
|
29669
29682
|
try {
|
|
29670
|
-
|
|
29671
|
-
|
|
29672
|
-
|
|
29673
|
-
|
|
29674
|
-
|
|
29683
|
+
candidates.push(join18(import.meta.dir, "..", "..", "package.json"));
|
|
29684
|
+
} catch {}
|
|
29685
|
+
for (const path4 of candidates) {
|
|
29686
|
+
try {
|
|
29687
|
+
const pkg = JSON.parse(readFileSync14(path4, "utf-8"));
|
|
29688
|
+
if (pkg.name === "@arcote.tech/arc-cli" && pkg.version) {
|
|
29689
|
+
return pkg.version;
|
|
29690
|
+
}
|
|
29691
|
+
} catch {}
|
|
29675
29692
|
}
|
|
29693
|
+
return "unknown";
|
|
29676
29694
|
}
|
|
29677
29695
|
async function hashDeployConfig(rootDir) {
|
|
29678
29696
|
const p2 = join18(rootDir, "deploy.arc.json");
|
|
@@ -31147,7 +31165,7 @@ import {
|
|
|
31147
31165
|
rmSync as rmSync4,
|
|
31148
31166
|
writeFileSync as writeFileSync15
|
|
31149
31167
|
} from "fs";
|
|
31150
|
-
import { dirname as
|
|
31168
|
+
import { dirname as dirname8, join as join19, normalize as normalize2, resolve } from "path";
|
|
31151
31169
|
function createDeployApiHandler(opts) {
|
|
31152
31170
|
return async (req, url, ctx) => {
|
|
31153
31171
|
const p3 = url.pathname;
|
|
@@ -31176,7 +31194,7 @@ function createDeployApiHandler(opts) {
|
|
|
31176
31194
|
writeFileSync15(join19(opts.ws.arcDir, "package.json"), Buffer.from(await pkgFile.arrayBuffer()));
|
|
31177
31195
|
writeFileSync15(join19(opts.ws.arcDir, "bun.lock"), Buffer.from(await lockFile.arrayBuffer()));
|
|
31178
31196
|
const start = Date.now();
|
|
31179
|
-
const installOk = await runBun(["install", "--production"
|
|
31197
|
+
const installOk = await runBun(["install", "--production"], opts.ws.arcDir);
|
|
31180
31198
|
if (!installOk) {
|
|
31181
31199
|
return Response.json({ error: "bun install failed" }, { status: 500, headers: cors });
|
|
31182
31200
|
}
|
|
@@ -31290,7 +31308,7 @@ function createDeployApiHandler(opts) {
|
|
|
31290
31308
|
if (existsSync15(dst)) {
|
|
31291
31309
|
rmSync4(dst, { recursive: true, force: true });
|
|
31292
31310
|
}
|
|
31293
|
-
mkdirSync14(
|
|
31311
|
+
mkdirSync14(dirname8(dst), { recursive: true });
|
|
31294
31312
|
cpSync(src2, dst, { recursive: true });
|
|
31295
31313
|
}
|
|
31296
31314
|
}
|
|
@@ -31328,7 +31346,7 @@ async function writeField(targetDir, name, file) {
|
|
|
31328
31346
|
if (!full.startsWith(safeRoot + "/") && full !== safeRoot) {
|
|
31329
31347
|
throw new Error(`Path traversal rejected: ${name}`);
|
|
31330
31348
|
}
|
|
31331
|
-
mkdirSync14(
|
|
31349
|
+
mkdirSync14(dirname8(full), { recursive: true });
|
|
31332
31350
|
writeFileSync15(full, Buffer.from(await file.arrayBuffer()));
|
|
31333
31351
|
}
|
|
31334
31352
|
function sanitizeName2(name) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arcote.tech/arc-cli",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.2",
|
|
4
4
|
"description": "CLI tool for Arc framework",
|
|
5
5
|
"module": "index.ts",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -12,12 +12,12 @@
|
|
|
12
12
|
"build": "bun build --target=bun ./src/index.ts --outdir=dist --external @arcote.tech/arc --external @arcote.tech/arc-ds --external @arcote.tech/arc-react --external @arcote.tech/platform && chmod +x dist/index.js"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@arcote.tech/arc": "^0.6.
|
|
16
|
-
"@arcote.tech/arc-ds": "^0.6.
|
|
17
|
-
"@arcote.tech/arc-react": "^0.6.
|
|
18
|
-
"@arcote.tech/arc-host": "^0.6.
|
|
19
|
-
"@arcote.tech/arc-adapter-db-sqlite": "^0.6.
|
|
20
|
-
"@arcote.tech/platform": "^0.6.
|
|
15
|
+
"@arcote.tech/arc": "^0.6.2",
|
|
16
|
+
"@arcote.tech/arc-ds": "^0.6.2",
|
|
17
|
+
"@arcote.tech/arc-react": "^0.6.2",
|
|
18
|
+
"@arcote.tech/arc-host": "^0.6.2",
|
|
19
|
+
"@arcote.tech/arc-adapter-db-sqlite": "^0.6.2",
|
|
20
|
+
"@arcote.tech/platform": "^0.6.2",
|
|
21
21
|
"@clack/prompts": "^0.9.0",
|
|
22
22
|
"commander": "^11.1.0",
|
|
23
23
|
"chokidar": "^3.5.3",
|
package/runtime/entrypoint.sh
CHANGED
|
@@ -23,5 +23,36 @@ if [ ! -f "$CLI_BIN" ]; then
|
|
|
23
23
|
bun add "@arcote.tech/arc-cli@${ARC_CLI_VERSION}"
|
|
24
24
|
fi
|
|
25
25
|
|
|
26
|
+
# resolveWorkspace() in arc platform start exits hard if /app has no
|
|
27
|
+
# package.json. In runtime mode the workspace lives in /app/.arc/platform/
|
|
28
|
+
# but the CLI still walks up from cwd. Drop a stub manifest here so the
|
|
29
|
+
# walk-up resolves to /app/.arc/platform (or to a stable "no workspace"
|
|
30
|
+
# state in pre-deploy).
|
|
31
|
+
if [ ! -f /app/package.json ]; then
|
|
32
|
+
cat > /app/package.json <<'EOF'
|
|
33
|
+
{
|
|
34
|
+
"name": "arc-runtime",
|
|
35
|
+
"private": true,
|
|
36
|
+
"type": "module",
|
|
37
|
+
"workspaces": []
|
|
38
|
+
}
|
|
39
|
+
EOF
|
|
40
|
+
fi
|
|
41
|
+
|
|
42
|
+
# Make /app/.arc/platform the working directory — that's where deployed user
|
|
43
|
+
# code, deps and node_modules live (volume mount).
|
|
44
|
+
mkdir -p /app/.arc/platform
|
|
45
|
+
cd /app/.arc/platform
|
|
46
|
+
if [ ! -f package.json ]; then
|
|
47
|
+
cat > package.json <<'EOF'
|
|
48
|
+
{
|
|
49
|
+
"name": "arc-platform-runtime",
|
|
50
|
+
"private": true,
|
|
51
|
+
"type": "module",
|
|
52
|
+
"workspaces": []
|
|
53
|
+
}
|
|
54
|
+
EOF
|
|
55
|
+
fi
|
|
56
|
+
|
|
26
57
|
echo "[entrypoint] starting arc platform (cli=${ARC_CLI_VERSION})"
|
|
27
58
|
exec bun run "$CLI_BIN" platform start
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
|
-
import {
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
3
3
|
import { basename, join } from "path";
|
|
4
4
|
import type { WorkspacePackage } from "./module-builder";
|
|
5
5
|
|
|
@@ -59,20 +59,32 @@ export function collectFrameworkDeps(
|
|
|
59
59
|
const manifestPath = join(arcDir, "package.json");
|
|
60
60
|
writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + "\n");
|
|
61
61
|
|
|
62
|
-
//
|
|
63
|
-
//
|
|
64
|
-
//
|
|
65
|
-
|
|
62
|
+
// Empty bun.lock placeholder. We CAN'T copy the workspace bun.lock — it
|
|
63
|
+
// contains the full dep graph (workspaces, dev deps) but our framework
|
|
64
|
+
// manifest is just the singleton peers. `bun install --frozen-lockfile`
|
|
65
|
+
// would reject as "lockfile had changes". An empty lockfile is harmless
|
|
66
|
+
// when server runs `bun install --production` without freeze.
|
|
66
67
|
const targetLock = join(arcDir, "bun.lock");
|
|
67
|
-
|
|
68
|
-
copyFileSync(rootLock, targetLock);
|
|
69
|
-
}
|
|
68
|
+
writeFileSync(targetLock, "");
|
|
70
69
|
|
|
71
|
-
|
|
70
|
+
// Hash MUST match the server-side computation in deploy-api.ts
|
|
71
|
+
// (sha256 over concat of raw bytes) — otherwise every deploy would think
|
|
72
|
+
// framework changed and re-install in a loop.
|
|
73
|
+
const hash = sha256ConcatHex([manifestPath, targetLock]);
|
|
72
74
|
writeFileSync(join(arcDir, ".deps-hash"), hash + "\n");
|
|
73
75
|
return { hash, manifestPath };
|
|
74
76
|
}
|
|
75
77
|
|
|
78
|
+
function sha256ConcatHex(paths: string[]): string {
|
|
79
|
+
const hash = createHash("sha256");
|
|
80
|
+
for (const p of paths) {
|
|
81
|
+
if (existsSync(p)) {
|
|
82
|
+
hash.update(readFileSync(p));
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return hash.digest("hex");
|
|
86
|
+
}
|
|
87
|
+
|
|
76
88
|
// ---------------------------------------------------------------------------
|
|
77
89
|
// Per-module deps
|
|
78
90
|
// ---------------------------------------------------------------------------
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from "fs";
|
|
2
|
-
import { join } from "path";
|
|
2
|
+
import { dirname, join } from "path";
|
|
3
3
|
import { bootstrap } from "../deploy/bootstrap";
|
|
4
4
|
import {
|
|
5
5
|
deployConfigExists,
|
|
@@ -125,13 +125,29 @@ export async function platformDeploy(
|
|
|
125
125
|
// ---------------------------------------------------------------------------
|
|
126
126
|
|
|
127
127
|
function readCliVersion(): string {
|
|
128
|
+
// import.meta.dir gets mangled by `bun build` — derive from process.argv[1]
|
|
129
|
+
// (the bundled dist/index.js path) which is stable across run modes.
|
|
130
|
+
const candidates: string[] = [];
|
|
131
|
+
const entry = process.argv[1];
|
|
132
|
+
if (entry) {
|
|
133
|
+
candidates.push(join(dirname(entry), "..", "package.json"));
|
|
134
|
+
}
|
|
128
135
|
try {
|
|
129
|
-
|
|
130
|
-
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
131
|
-
return pkg.version ?? "unknown";
|
|
136
|
+
candidates.push(join(import.meta.dir, "..", "..", "package.json"));
|
|
132
137
|
} catch {
|
|
133
|
-
|
|
138
|
+
// import.meta.dir unavailable
|
|
139
|
+
}
|
|
140
|
+
for (const path of candidates) {
|
|
141
|
+
try {
|
|
142
|
+
const pkg = JSON.parse(readFileSync(path, "utf-8"));
|
|
143
|
+
if (pkg.name === "@arcote.tech/arc-cli" && pkg.version) {
|
|
144
|
+
return pkg.version as string;
|
|
145
|
+
}
|
|
146
|
+
} catch {
|
|
147
|
+
// Try next
|
|
148
|
+
}
|
|
134
149
|
}
|
|
150
|
+
return "unknown";
|
|
135
151
|
}
|
|
136
152
|
|
|
137
153
|
async function hashDeployConfig(rootDir: string): Promise<string> {
|
|
@@ -116,14 +116,12 @@ export async function syncEnv(inputs: SyncInputs): Promise<SyncOutcome> {
|
|
|
116
116
|
new Blob([readFileSync(join(ws.arcDir, "package.json"))]),
|
|
117
117
|
"package.json",
|
|
118
118
|
);
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
);
|
|
126
|
-
}
|
|
119
|
+
// Ship a placeholder bun.lock (server validates its presence) but
|
|
120
|
+
// intentionally empty — workspace bun.lock has the full dep graph and
|
|
121
|
+
// would trip --frozen-lockfile against our slim framework package.json.
|
|
122
|
+
// The server side runs `bun install --production` without freeze, so an
|
|
123
|
+
// empty lock is harmless: bun re-resolves against package.json.
|
|
124
|
+
form.append("bun.lock", new Blob([""]), "bun.lock");
|
|
127
125
|
const res = await fetch(`${base()}/api/deploy/framework`, {
|
|
128
126
|
method: "POST",
|
|
129
127
|
body: form,
|
package/src/deploy/ssh.ts
CHANGED
|
@@ -21,16 +21,22 @@ export interface SshExecResult {
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
function baseSshArgs(target: DeployTarget): string[] {
|
|
24
|
-
|
|
24
|
+
// IdentitiesOnly=yes pins auth to the explicit key. Without it ssh-agent
|
|
25
|
+
// offers every loaded identity and trips MaxAuthTries on hardened sshd
|
|
26
|
+
// (ansible's sshd hardening + fail2ban lowers the threshold).
|
|
27
|
+
const key = target.sshKey ?? `${process.env.HOME}/.ssh/id_ed25519`;
|
|
28
|
+
return [
|
|
25
29
|
"-o",
|
|
26
30
|
"BatchMode=yes",
|
|
27
31
|
"-o",
|
|
28
32
|
"StrictHostKeyChecking=accept-new",
|
|
33
|
+
"-o",
|
|
34
|
+
"IdentitiesOnly=yes",
|
|
35
|
+
"-i",
|
|
36
|
+
key,
|
|
29
37
|
"-p",
|
|
30
38
|
String(target.port),
|
|
31
39
|
];
|
|
32
|
-
if (target.sshKey) args.push("-i", target.sshKey);
|
|
33
|
-
return args;
|
|
34
40
|
}
|
|
35
41
|
|
|
36
42
|
/**
|
|
@@ -115,15 +121,19 @@ export async function scpUpload(
|
|
|
115
121
|
localPath: string,
|
|
116
122
|
remotePath: string,
|
|
117
123
|
): Promise<void> {
|
|
124
|
+
const key = target.sshKey ?? `${process.env.HOME}/.ssh/id_ed25519`;
|
|
118
125
|
const args = [
|
|
119
126
|
"-o",
|
|
120
127
|
"BatchMode=yes",
|
|
121
128
|
"-o",
|
|
122
129
|
"StrictHostKeyChecking=accept-new",
|
|
130
|
+
"-o",
|
|
131
|
+
"IdentitiesOnly=yes",
|
|
132
|
+
"-i",
|
|
133
|
+
key,
|
|
123
134
|
"-P",
|
|
124
135
|
String(target.port),
|
|
125
136
|
];
|
|
126
|
-
if (target.sshKey) args.push("-i", target.sshKey);
|
|
127
137
|
args.push(localPath, `${target.user}@${target.host}:${remotePath}`);
|
|
128
138
|
|
|
129
139
|
const proc = spawn({ cmd: ["scp", ...args], stderr: "pipe" });
|
|
@@ -98,8 +98,12 @@ export function createDeployApiHandler(opts: DeployApiOptions): ArcHttpHandler {
|
|
|
98
98
|
);
|
|
99
99
|
|
|
100
100
|
const start = Date.now();
|
|
101
|
+
// No --frozen-lockfile: workspace bun.lock from the source project
|
|
102
|
+
// contains the full dep graph, but our framework manifest is a subset.
|
|
103
|
+
// Bun would reject as "lockfile had changes". Let bun re-resolve against
|
|
104
|
+
// the framework-only package.json.
|
|
101
105
|
const installOk = await runBun(
|
|
102
|
-
["install", "--production"
|
|
106
|
+
["install", "--production"],
|
|
103
107
|
opts.ws.arcDir,
|
|
104
108
|
);
|
|
105
109
|
if (!installOk) {
|
package/src/platform/shared.ts
CHANGED
|
@@ -97,7 +97,10 @@ export function resolveWorkspace(): WorkspaceInfo {
|
|
|
97
97
|
`Found ${packages.length} package(s): ${packages.map((p) => p.name).join(", ")}`,
|
|
98
98
|
);
|
|
99
99
|
|
|
100
|
-
|
|
100
|
+
// Empty package list is allowed in pre-deploy runtime mode (container with
|
|
101
|
+
// freshly-mounted volume, no user code pushed yet). The CLI entry that
|
|
102
|
+
// forbids this (arc platform build/dev) checks explicitly.
|
|
103
|
+
if (packages.length === 0 && process.env.ARC_DEPLOY_API !== "1") {
|
|
101
104
|
err("No workspace packages found.");
|
|
102
105
|
process.exit(1);
|
|
103
106
|
}
|