@adep/cli 0.4.6 → 0.4.11

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 CHANGED
@@ -12,7 +12,11 @@ var __export = (target, all) => {
12
12
  // packages/cli/src/config.ts
13
13
  function resolvePaths(env = process.env) {
14
14
  const home = env["ADEP_HOME"] ?? `${env["HOME"] ?? ""}/.adep`;
15
- return { home, credentialsFile: `${home}/credentials` };
15
+ return {
16
+ home,
17
+ credentialsFile: `${home}/credentials`,
18
+ credentialsDir: `${home}/credentials.d`
19
+ };
16
20
  }
17
21
  function resolveServer(env = process.env) {
18
22
  return (env["ADEP_SERVER"] ?? "https://adep.top").replace(/\/+$/, "");
@@ -66,29 +70,13 @@ var init_browser = __esm({
66
70
  });
67
71
 
68
72
  // packages/cli/src/credentials.ts
69
- import { mkdir, open, readFile, rm, stat } from "node:fs/promises";
70
- import { dirname } from "node:path";
71
- async function saveCredentials(paths, credentials) {
72
- await mkdir(dirname(paths.credentialsFile), { recursive: true });
73
- const handle = await open(paths.credentialsFile, "w", 384);
74
- try {
75
- await handle.writeFile(JSON.stringify(credentials, null, 2));
76
- } finally {
77
- await handle.close();
78
- }
79
- await chmodStrict(paths.credentialsFile);
73
+ import { chmod, mkdir, open, readFile, rm, stat, writeFile } from "node:fs/promises";
74
+ import { join } from "node:path";
75
+ function slotNameFor(server) {
76
+ return encodeURIComponent(new URL(server).host);
80
77
  }
81
- async function chmodStrict(file2) {
82
- const info = await stat(file2);
83
- const mode = info.mode & 511;
84
- if (mode !== 384) {
85
- const { chmod } = await import("node:fs/promises");
86
- await chmod(file2, 384);
87
- }
88
- }
89
- async function loadCredentials(paths) {
78
+ function parseCredentials(raw) {
90
79
  try {
91
- const raw = await readFile(paths.credentialsFile, "utf8");
92
80
  const parsed = JSON.parse(raw);
93
81
  if (typeof parsed["server"] !== "string" || typeof parsed["email"] !== "string" || typeof parsed["encodedToken"] !== "string") {
94
82
  return null;
@@ -104,7 +92,84 @@ async function loadCredentials(paths) {
104
92
  return null;
105
93
  }
106
94
  }
95
+ async function chmodStrict(file2) {
96
+ const info = await stat(file2);
97
+ const mode = info.mode & 511;
98
+ if (mode !== 384) {
99
+ await chmod(file2, 384);
100
+ }
101
+ }
102
+ async function writeSlot(paths, credentials, slot) {
103
+ await mkdir(paths.credentialsDir, { recursive: true });
104
+ const file2 = slotFileOf(paths, slot);
105
+ const handle = await open(file2, "w", 384);
106
+ try {
107
+ await handle.writeFile(JSON.stringify(credentials, null, 2));
108
+ } finally {
109
+ await handle.close();
110
+ }
111
+ await chmodStrict(file2);
112
+ }
113
+ async function readSlot(paths, slot) {
114
+ try {
115
+ return parseCredentials(await readFile(slotFileOf(paths, slot), "utf8"));
116
+ } catch {
117
+ return null;
118
+ }
119
+ }
120
+ async function readCurrent(paths) {
121
+ try {
122
+ const raw = (await readFile(currentFileOf(paths), "utf8")).trim();
123
+ return raw === "" ? null : raw;
124
+ } catch {
125
+ return null;
126
+ }
127
+ }
128
+ async function writeCurrent(paths, slot) {
129
+ await mkdir(paths.credentialsDir, { recursive: true });
130
+ await writeFile(currentFileOf(paths), `${slot}
131
+ `, "utf8");
132
+ }
133
+ async function migrateLegacyFile(paths) {
134
+ let raw;
135
+ try {
136
+ raw = await readFile(paths.credentialsFile, "utf8");
137
+ } catch {
138
+ return;
139
+ }
140
+ const parsed = parseCredentials(raw);
141
+ if (parsed === null) return;
142
+ try {
143
+ const slot = slotNameFor(parsed.server);
144
+ await writeSlot(paths, parsed, slot);
145
+ if (await readCurrent(paths) === null) {
146
+ await writeCurrent(paths, slot);
147
+ }
148
+ } catch {
149
+ return;
150
+ }
151
+ await rm(paths.credentialsFile, { force: true });
152
+ }
153
+ async function saveCredentials(paths, credentials) {
154
+ await migrateLegacyFile(paths);
155
+ const slot = slotNameFor(credentials.server);
156
+ const previous = await readSlot(paths, slot);
157
+ await writeSlot(paths, credentials, slot);
158
+ await writeCurrent(paths, slot);
159
+ return { previous };
160
+ }
161
+ async function loadCredentials(paths) {
162
+ await migrateLegacyFile(paths);
163
+ const current = await readCurrent(paths);
164
+ if (current === null) return null;
165
+ return readSlot(paths, current);
166
+ }
107
167
  async function clearCredentials(paths) {
168
+ const current = await readCurrent(paths);
169
+ if (current !== null) {
170
+ await rm(slotFileOf(paths, current), { force: true });
171
+ }
172
+ await rm(currentFileOf(paths), { force: true });
108
173
  await rm(paths.credentialsFile, { force: true });
109
174
  }
110
175
  function encodeToken(token) {
@@ -123,9 +188,12 @@ function authHeaders(credentials) {
123
188
  }
124
189
  return { cookie: sessionCookieHeader(credentials) };
125
190
  }
191
+ var slotFileOf, currentFileOf;
126
192
  var init_credentials = __esm({
127
193
  "packages/cli/src/credentials.ts"() {
128
194
  "use strict";
195
+ slotFileOf = (paths, slot) => join(paths.credentialsDir, `${slot}.json`);
196
+ currentFileOf = (paths) => join(paths.credentialsDir, "current");
129
197
  }
130
198
  });
131
199
 
@@ -246,14 +314,18 @@ async function login(paths, input2) {
246
314
  const eq = cookie.indexOf("=");
247
315
  const cookieName = cookie.slice(0, eq);
248
316
  const token = cookie.slice(eq + 1);
249
- await saveCredentials(paths, {
317
+ const { previous } = await saveCredentials(paths, {
250
318
  server,
251
319
  email: input2.email,
252
320
  encodedToken: encodeToken(token),
253
321
  cookieName,
254
322
  authType: "cookie"
255
323
  });
256
- return { email: input2.email };
324
+ return {
325
+ email: input2.email,
326
+ authType: "cookie",
327
+ ...previous !== null && previous.email !== input2.email ? { replacedEmail: previous.email } : {}
328
+ };
257
329
  }
258
330
  async function parseDeviceError(response) {
259
331
  let body = null;
@@ -394,13 +466,17 @@ async function loginWithDevice(paths, input2) {
394
466
  now: input2.now ?? Date.now
395
467
  });
396
468
  const email3 = await fetchIdentityWithToken(server, token);
397
- await saveCredentials(paths, {
469
+ const { previous } = await saveCredentials(paths, {
398
470
  server,
399
471
  email: email3,
400
472
  encodedToken: encodeToken(token),
401
473
  authType: "bearer"
402
474
  });
403
- return { email: email3, authType: "bearer" };
475
+ return {
476
+ email: email3,
477
+ authType: "bearer",
478
+ ...previous !== null && previous.email !== email3 ? { replacedEmail: previous.email } : {}
479
+ };
404
480
  }
405
481
  async function fetchIdentityWithToken(server, token) {
406
482
  let response;
@@ -1038,22 +1114,22 @@ var init_resolve = __esm({
1038
1114
  // packages/runtime/src/functions/runtime/worker-executor.ts
1039
1115
  import { readFileSync as readFileSync2 } from "node:fs";
1040
1116
  import { fileURLToPath as fileURLToPath2, pathToFileURL } from "node:url";
1041
- import { dirname as dirname4, join as join3 } from "node:path";
1117
+ import { dirname as dirname3, join as join4 } from "node:path";
1042
1118
  import { Worker } from "node:worker_threads";
1043
1119
  function resolveWorkerEntry(baseDir = fileURLToPath2(new URL(".", import.meta.url))) {
1044
1120
  const candidates = [
1045
- join3(baseDir, "worker-entry.js"),
1046
- join3(baseDir, "worker-entry.ts"),
1047
- join3(baseDir, "domains/functions/runtime/worker-entry.js"),
1048
- join3(baseDir, "domains/functions/runtime/worker-entry.ts")
1121
+ join4(baseDir, "worker-entry.js"),
1122
+ join4(baseDir, "worker-entry.ts"),
1123
+ join4(baseDir, "domains/functions/runtime/worker-entry.js"),
1124
+ join4(baseDir, "domains/functions/runtime/worker-entry.ts")
1049
1125
  ];
1050
1126
  let current = baseDir;
1051
1127
  for (let depth = 0; depth < 8; depth += 1) {
1052
1128
  candidates.push(
1053
- join3(current, "packages/runtime/src/functions/runtime/worker-entry.js"),
1054
- join3(current, "packages/runtime/src/functions/runtime/worker-entry.ts")
1129
+ join4(current, "packages/runtime/src/functions/runtime/worker-entry.js"),
1130
+ join4(current, "packages/runtime/src/functions/runtime/worker-entry.ts")
1055
1131
  );
1056
- const parent = dirname4(current);
1132
+ const parent = dirname3(current);
1057
1133
  if (parent === current) break;
1058
1134
  current = parent;
1059
1135
  }
@@ -1923,6 +1999,20 @@ var init_builder = __esm({
1923
1999
 
1924
2000
  // packages/runtime/src/database/sdk/cloud.ts
1925
2001
  function errorWithCode(error62) {
2002
+ if (error62 instanceof Error) {
2003
+ const sqlite = /no such table: (\S+)/.exec(error62.message);
2004
+ if (sqlite !== null) {
2005
+ return new Error(
2006
+ `[DB_TABLE_MISSING] \u9879\u76EE\u5E93\u5DF2\u542F\u52A8\u4F46\u7F3A\u8868 "${sqlite[1]}"\uFF1A\u8BF7\u6267\u884C adep db migrate <schema.sql> \u5EFA\u8868\uFF08\u53D1\u5E03\u4E0D\u542B\u5EFA\u8868\uFF09\u3002\u539F\u59CB\u9519\u8BEF\uFF1A${error62.message}`
2007
+ );
2008
+ }
2009
+ const pg = /relation "([^"]+)" does not exist/.exec(error62.message);
2010
+ if (pg !== null) {
2011
+ return new Error(
2012
+ `[DB_TABLE_MISSING] \u9879\u76EE\u5E93\u5DF2\u542F\u52A8\u4F46\u7F3A\u8868\uFF08\u6216\u5173\u7CFB\uFF09"${pg[1]}"\uFF1A\u8BF7\u6267\u884C adep db migrate <schema.sql> \u5EFA\u8868\uFF08\u53D1\u5E03\u4E0D\u542B\u5EFA\u8868\uFF09\u3002\u539F\u59CB\u9519\u8BEF\uFF1A${error62.message}`
2013
+ );
2014
+ }
2015
+ }
1926
2016
  const code = typeof error62 === "object" && error62 !== null && typeof error62.code === "string" ? error62.code : void 0;
1927
2017
  if (code !== void 0 && error62 instanceof Error) {
1928
2018
  return new Error(`[${code}] ${error62.message}`);
@@ -3260,13 +3350,13 @@ var init_cloud2 = __esm({
3260
3350
  });
3261
3351
 
3262
3352
  // packages/runtime/src/storage/driver/local.ts
3263
- import { mkdir as mkdir3, readFile as readFile2, readdir, rm as rm2, stat as stat3, unlink, writeFile as writeFile2 } from "node:fs/promises";
3264
- import { dirname as dirname5, join as join4 } from "node:path";
3353
+ import { mkdir as mkdir3, readFile as readFile2, readdir, rm as rm2, stat as stat3, unlink, writeFile as writeFile3 } from "node:fs/promises";
3354
+ import { dirname as dirname4, join as join5 } from "node:path";
3265
3355
  function createLocalStorageDriver(options) {
3266
3356
  const quotaBytes = options.quotaBytes ?? PROJECT_QUOTA_BYTES;
3267
- const bucketDir = (projectId) => join4(options.dir, projectId);
3268
- const objectPath = (projectId, path) => join4(bucketDir(projectId), path);
3269
- const metaPath = (projectId, path) => join4(dirname5(objectPath(projectId, path)), `${path.split("/").pop() ?? ""}${META_SUFFIX}`);
3357
+ const bucketDir = (projectId) => join5(options.dir, projectId);
3358
+ const objectPath = (projectId, path) => join5(bucketDir(projectId), path);
3359
+ const metaPath = (projectId, path) => join5(dirname4(objectPath(projectId, path)), `${path.split("/").pop() ?? ""}${META_SUFFIX}`);
3270
3360
  const readStoredMeta = async (projectId, path) => {
3271
3361
  const raw = await readFile2(metaPath(projectId, path), "utf8");
3272
3362
  return JSON.parse(raw);
@@ -3278,7 +3368,7 @@ function createLocalStorageDriver(options) {
3278
3368
  updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
3279
3369
  ...meta3.contentType === void 0 ? {} : { contentType: meta3.contentType }
3280
3370
  };
3281
- await writeFile2(metaPath(projectId, path), JSON.stringify(payload), "utf8");
3371
+ await writeFile3(metaPath(projectId, path), JSON.stringify(payload), "utf8");
3282
3372
  };
3283
3373
  const totalSize = async (projectId) => {
3284
3374
  const root = bucketDir(projectId);
@@ -3292,7 +3382,7 @@ function createLocalStorageDriver(options) {
3292
3382
  }
3293
3383
  const tasks = [];
3294
3384
  for (const entry of entries) {
3295
- const full = join4(dir, entry.name);
3385
+ const full = join5(dir, entry.name);
3296
3386
  if (entry.isDirectory()) {
3297
3387
  tasks.push(walk(full));
3298
3388
  } else if (entry.isFile() && !entry.name.endsWith(META_SUFFIX)) {
@@ -3336,8 +3426,8 @@ function createLocalStorageDriver(options) {
3336
3426
  );
3337
3427
  }
3338
3428
  const dest = objectPath(projectId, path);
3339
- await mkdir3(dirname5(dest), { recursive: true });
3340
- await writeFile2(dest, data);
3429
+ await mkdir3(dirname4(dest), { recursive: true });
3430
+ await writeFile3(dest, data);
3341
3431
  await writeStoredMeta(projectId, path, {
3342
3432
  visibility: putOptions.visibility,
3343
3433
  size: data.byteLength,
@@ -3415,7 +3505,7 @@ function createLocalStorageDriver(options) {
3415
3505
  const tasks = [];
3416
3506
  for (const entry of entries) {
3417
3507
  if (entry.name.endsWith(META_SUFFIX)) continue;
3418
- const full = join4(dir, entry.name);
3508
+ const full = join5(dir, entry.name);
3419
3509
  const rel = relative10 === "" ? entry.name : `${relative10}/${entry.name}`;
3420
3510
  if (entry.isFile()) {
3421
3511
  if (prefix !== void 0 && !rel.startsWith(prefix)) continue;
@@ -3464,9 +3554,9 @@ var init_local = __esm({
3464
3554
  });
3465
3555
 
3466
3556
  // packages/cli/src/sim/storage.ts
3467
- import { join as join5 } from "node:path";
3557
+ import { join as join6 } from "node:path";
3468
3558
  function createSimStorageCapability(options) {
3469
- const dir = join5(options.cwd, ".adep", "sim", "storage");
3559
+ const dir = join6(options.cwd, ".adep", "sim", "storage");
3470
3560
  const driver = createLocalStorageDriver({ dir });
3471
3561
  const signer = {
3472
3562
  secret: options.secret ?? SIM_SIGN_SECRET,
@@ -3641,13 +3731,13 @@ var init_merge = __esm({
3641
3731
  });
3642
3732
 
3643
3733
  // packages/cli/src/sim/runtime.ts
3644
- import { mkdir as mkdir4, readFile as readFile3, writeFile as writeFile3 } from "node:fs/promises";
3645
- import { dirname as dirname6, join as join6 } from "node:path";
3734
+ import { mkdir as mkdir4, readFile as readFile3, writeFile as writeFile4 } from "node:fs/promises";
3735
+ import { dirname as dirname5, join as join7 } from "node:path";
3646
3736
  function simDir(cwd) {
3647
- return join6(cwd, ".adep", "sim");
3737
+ return join7(cwd, ".adep", "sim");
3648
3738
  }
3649
3739
  function jsonStorage(cwd) {
3650
- const file2 = join6(simDir(cwd), "db.json");
3740
+ const file2 = join7(simDir(cwd), "db.json");
3651
3741
  return {
3652
3742
  async load() {
3653
3743
  try {
@@ -3658,8 +3748,8 @@ function jsonStorage(cwd) {
3658
3748
  }
3659
3749
  },
3660
3750
  async save(tables) {
3661
- await mkdir4(dirname6(file2), { recursive: true });
3662
- await writeFile3(file2, JSON.stringify(tables), "utf8");
3751
+ await mkdir4(dirname5(file2), { recursive: true });
3752
+ await writeFile4(file2, JSON.stringify(tables), "utf8");
3663
3753
  }
3664
3754
  };
3665
3755
  }
@@ -3814,6 +3904,63 @@ var init_client = __esm({
3814
3904
  }
3815
3905
  });
3816
3906
 
3907
+ // packages/runtime/src/shared/sql-split.ts
3908
+ function splitSqlStatements(source) {
3909
+ const statements = [];
3910
+ let buffer = "";
3911
+ let inQuote = false;
3912
+ const lines = source.split("\n");
3913
+ for (const rawLine of lines) {
3914
+ const trimmed = rawLine.trim();
3915
+ if (!inQuote && (trimmed.length === 0 || trimmed.startsWith("--"))) continue;
3916
+ const scanLine = inQuote ? rawLine : trimmed;
3917
+ for (let i = 0; i < scanLine.length; i++) {
3918
+ const ch = scanLine[i];
3919
+ if (inQuote) {
3920
+ if (ch === "'") {
3921
+ if (scanLine[i + 1] === "'") {
3922
+ buffer += ch + scanLine[i + 1];
3923
+ i++;
3924
+ continue;
3925
+ }
3926
+ inQuote = false;
3927
+ }
3928
+ buffer += ch;
3929
+ continue;
3930
+ }
3931
+ if (ch === "'") {
3932
+ inQuote = true;
3933
+ buffer += ch;
3934
+ continue;
3935
+ }
3936
+ if (ch === "-" && scanLine[i + 1] === "-") break;
3937
+ if (ch === ";") {
3938
+ const statement = buffer.trim();
3939
+ if (statement.length > 0) statements.push(statement);
3940
+ buffer = "";
3941
+ continue;
3942
+ }
3943
+ buffer += ch;
3944
+ }
3945
+ if (inQuote) {
3946
+ buffer += "\n";
3947
+ } else if (buffer.length > 0 && !/\s$/.test(buffer)) {
3948
+ buffer += " ";
3949
+ }
3950
+ }
3951
+ if (inQuote) {
3952
+ throw new Error(`SQL \u811A\u672C\u5F15\u53F7\u672A\u95ED\u5408\uFF1A${buffer.trim().slice(0, 80)}\u2026`);
3953
+ }
3954
+ const tail = buffer.trim();
3955
+ if (tail.length > 0) statements.push(tail);
3956
+ return statements;
3957
+ }
3958
+ var init_sql_split = __esm({
3959
+ "packages/runtime/src/shared/sql-split.ts"() {
3960
+ "use strict";
3961
+ }
3962
+ });
3963
+
3817
3964
  // packages/cli/src/db.ts
3818
3965
  var db_exports = {};
3819
3966
  __export(db_exports, {
@@ -3915,61 +4062,20 @@ async function dbRollback(paths, options) {
3915
4062
  { method: "POST", body: { to: options.to } }
3916
4063
  );
3917
4064
  }
3918
- function splitSqlStatements(source) {
3919
- const statements = [];
3920
- let buffer = "";
3921
- let inQuote = false;
3922
- const lines = source.split("\n");
3923
- for (const rawLine of lines) {
3924
- const trimmed = rawLine.trim();
3925
- if (!inQuote && (trimmed.length === 0 || trimmed.startsWith("--"))) continue;
3926
- for (let i = 0; i < rawLine.length; i++) {
3927
- const ch = rawLine[i];
3928
- if (inQuote) {
3929
- if (ch === "'") {
3930
- if (rawLine[i + 1] === "'") {
3931
- buffer += ch + rawLine[i + 1];
3932
- i++;
3933
- continue;
3934
- }
3935
- inQuote = false;
3936
- }
3937
- buffer += ch;
3938
- continue;
3939
- }
3940
- if (ch === "'") {
3941
- inQuote = true;
3942
- buffer += ch;
3943
- continue;
3944
- }
3945
- if (ch === "-" && rawLine[i + 1] === "-") break;
3946
- if (ch === ";") {
3947
- const statement = buffer.trim();
3948
- if (statement.length > 0) statements.push(statement);
3949
- buffer = "";
3950
- continue;
3951
- }
3952
- buffer += ch;
3953
- }
3954
- buffer += inQuote ? "\n" : " ";
3955
- }
3956
- if (inQuote) {
3957
- throw new Error(`SQL \u8FC1\u79FB\u6587\u4EF6\u5F15\u53F7\u672A\u95ED\u5408\uFF1A${buffer.trim().slice(0, 80)}\u2026`);
3958
- }
3959
- const tail = buffer.trim();
3960
- if (tail.length > 0) statements.push(tail);
3961
- return statements;
3962
- }
3963
4065
  async function dbMigrate(paths, options) {
3964
- const source = await readFile4(resolve3(options.file), "utf8");
3965
- const statements = splitSqlStatements(source);
3966
- if (statements.length === 0) {
3967
- throw new Error(`\u8FC1\u79FB\u6587\u4EF6\u6CA1\u6709\u53EF\u6267\u884C\u8BED\u53E5\uFF1A${options.file}`);
4066
+ const queue = [];
4067
+ for (const file2 of options.files) {
4068
+ const source = await readFile4(resolve3(file2), "utf8");
4069
+ const statements = splitSqlStatements(source);
4070
+ if (statements.length === 0) {
4071
+ throw new Error(`\u8FC1\u79FB\u6587\u4EF6\u6CA1\u6709\u53EF\u6267\u884C\u8BED\u53E5\uFF1A${file2}`);
4072
+ }
4073
+ for (const statement of statements) queue.push({ file: file2, statement });
3968
4074
  }
3969
4075
  const { project: project2 } = await open2(paths, options);
3970
4076
  const applied = [];
3971
4077
  const changes = [];
3972
- for (const statement of statements) {
4078
+ for (const { file: file2, statement } of queue) {
3973
4079
  try {
3974
4080
  const result = await dbExec(paths, {
3975
4081
  cwd: options.cwd,
@@ -3988,7 +4094,7 @@ async function dbMigrate(paths, options) {
3988
4094
  projectId: project2,
3989
4095
  applied,
3990
4096
  changes,
3991
- failed: { statement, code, message }
4097
+ failed: { file: file2, statement, code, message }
3992
4098
  };
3993
4099
  }
3994
4100
  }
@@ -3999,12 +4105,14 @@ var init_db2 = __esm({
3999
4105
  "use strict";
4000
4106
  init_auth();
4001
4107
  init_client();
4108
+ init_sql_split();
4109
+ init_sql_split();
4002
4110
  }
4003
4111
  });
4004
4112
 
4005
4113
  // packages/cli/src/serve/sqlite-driver.ts
4006
4114
  import { mkdir as mkdir5 } from "node:fs/promises";
4007
- import { dirname as dirname7, resolve as resolve4 } from "node:path";
4115
+ import { dirname as dirname6, resolve as resolve4 } from "node:path";
4008
4116
  function isBun(versions) {
4009
4117
  return versions["bun"] !== void 0 && versions["bun"] !== "";
4010
4118
  }
@@ -4054,7 +4162,7 @@ async function openSqliteProjectDriver(file2, options = {}) {
4054
4162
  throw new Error(`${moduleName} \u672A\u5BFC\u51FA ${ctorName}\uFF1A\u5F53\u524D\u8FD0\u884C\u65F6\u7684 SQLite \u5185\u5EFA\u6A21\u5757\u4E0D\u53EF\u7528`);
4055
4163
  }
4056
4164
  const target = file2 === ":memory:" ? file2 : resolve4(file2);
4057
- if (target !== ":memory:") await mkdir5(dirname7(target), { recursive: true });
4165
+ if (target !== ":memory:") await mkdir5(dirname6(target), { recursive: true });
4058
4166
  const database = new Ctor(target);
4059
4167
  database.exec("PRAGMA journal_mode = WAL; PRAGMA foreign_keys = ON;");
4060
4168
  return {
@@ -4093,7 +4201,7 @@ var init_sqlite_driver = __esm({
4093
4201
 
4094
4202
  // packages/cli/src/serve/db-mode.ts
4095
4203
  import { readFile as readFile5 } from "node:fs/promises";
4096
- import { join as join7, relative, resolve as resolve5 } from "node:path";
4204
+ import { join as join8, relative, resolve as resolve5 } from "node:path";
4097
4205
  function isServeDbMode(value) {
4098
4206
  return SERVE_DB_MODES.includes(value.trim().toLowerCase());
4099
4207
  }
@@ -4128,7 +4236,7 @@ function displayPath(cwd, target) {
4128
4236
  return rel.startsWith("..") ? target : rel.split(/[\\/]/u).join("/");
4129
4237
  }
4130
4238
  function simDbTarget(cwd) {
4131
- return displayPath(cwd, join7(simDir(cwd), "db.json"));
4239
+ return displayPath(cwd, join8(simDir(cwd), "db.json"));
4132
4240
  }
4133
4241
  function resolveLocalDbTarget(cwd, options) {
4134
4242
  const mode = resolveServeDbMode(options.db);
@@ -4214,7 +4322,7 @@ var init_db_mode = __esm({
4214
4322
 
4215
4323
  // packages/cli/src/sim/env.ts
4216
4324
  import { readFile as readFile6 } from "node:fs/promises";
4217
- import { join as join8 } from "node:path";
4325
+ import { join as join9 } from "node:path";
4218
4326
  function parseEnv(content) {
4219
4327
  const env = {};
4220
4328
  for (const raw of content.split(/\r?\n/)) {
@@ -4229,8 +4337,8 @@ function parseEnv(content) {
4229
4337
  return env;
4230
4338
  }
4231
4339
  async function loadSimEnv(cwd, config2 = {}) {
4232
- const envRoot = await readFile6(join8(cwd, ".env"), "utf8").catch(() => "");
4233
- const envLocal = await readFile6(join8(cwd, ".env.local"), "utf8").catch(() => "");
4340
+ const envRoot = await readFile6(join9(cwd, ".env"), "utf8").catch(() => "");
4341
+ const envLocal = await readFile6(join9(cwd, ".env.local"), "utf8").catch(() => "");
4234
4342
  const merged = { ...parseEnv(envRoot), ...parseEnv(envLocal) };
4235
4343
  for (const secret of config2.secrets ?? []) {
4236
4344
  if (merged[secret] !== void 0) continue;
@@ -4417,9 +4525,9 @@ var init_boundary = __esm({
4417
4525
 
4418
4526
  // packages/cli/src/ts-config.ts
4419
4527
  import { stat as stat4, readFile as readFile7 } from "node:fs/promises";
4420
- import { join as join9 } from "node:path";
4528
+ import { join as join10 } from "node:path";
4421
4529
  async function loadAdepConfigModule(cwd) {
4422
- const configPath = join9(cwd, "adep.config.ts");
4530
+ const configPath = join10(cwd, "adep.config.ts");
4423
4531
  try {
4424
4532
  await stat4(configPath);
4425
4533
  } catch {
@@ -5780,7 +5888,7 @@ var init_chain = __esm({
5780
5888
  // packages/runtime/src/functions/runtime/worker-entry.ts
5781
5889
  import { parentPort, workerData } from "node:worker_threads";
5782
5890
  import { createRequire } from "node:module";
5783
- import { join as join10 } from "node:path";
5891
+ import { join as join11 } from "node:path";
5784
5892
  function errorMessageOf2(error62) {
5785
5893
  if (error62 instanceof Error) return error62.message;
5786
5894
  if (typeof error62 === "object" && error62 !== null && "message" in error62) {
@@ -5835,7 +5943,7 @@ function errorMessageWithLocation(error62, files) {
5835
5943
  }
5836
5944
  function createBareResolver(deps) {
5837
5945
  const platformRequire = createRequire(import.meta.url);
5838
- const depsRequire = deps.dir === null ? null : createRequire(join10(deps.dir, "__deps__.js"));
5946
+ const depsRequire = deps.dir === null ? null : createRequire(join11(deps.dir, "__deps__.js"));
5839
5947
  return (request) => {
5840
5948
  if (deps.builtin.includes(request)) return platformRequire(request);
5841
5949
  const root = splitBareSpecifier(request);
@@ -6028,13 +6136,127 @@ var init_function_source = __esm({
6028
6136
  }
6029
6137
  });
6030
6138
 
6139
+ // packages/runtime/src/shared/multipart.ts
6140
+ function extractBoundary(contentType) {
6141
+ const match = /boundary\s*=\s*(?:"([^"]+)"|([^;\s]+))/i.exec(contentType);
6142
+ if (match === null) {
6143
+ throw new MultipartParseError("Content-Type \u7F3A\u5C11 boundary \u53C2\u6570\uFF0C\u65E0\u6CD5\u89E3\u6790 multipart \u8BF7\u6C42\u4F53");
6144
+ }
6145
+ const boundary = match[1] ?? match[2];
6146
+ if (boundary === void 0 || boundary.length === 0) {
6147
+ throw new MultipartParseError("Content-Type \u7684 boundary \u4E3A\u7A7A");
6148
+ }
6149
+ return boundary;
6150
+ }
6151
+ function indexOfSequence(haystack, needle, from) {
6152
+ outer: for (let i = from; i + needle.length <= haystack.length; i++) {
6153
+ for (let j = 0; j < needle.length; j++) {
6154
+ if (haystack[i + j] !== needle[j]) continue outer;
6155
+ }
6156
+ return i;
6157
+ }
6158
+ return -1;
6159
+ }
6160
+ function unquote(value) {
6161
+ return value.replace(/\\(.)/g, "$1");
6162
+ }
6163
+ function parseMultipart(contentType, raw) {
6164
+ const boundary = extractBoundary(contentType);
6165
+ const delim = encoder2.encode(`--${boundary}`);
6166
+ const positions = [];
6167
+ scan: for (let i = 0; i + delim.length <= raw.length; i++) {
6168
+ if (raw[i] !== delim[0]) continue;
6169
+ for (let j = 1; j < delim.length; j++) {
6170
+ if (raw[i + j] !== delim[j]) continue scan;
6171
+ }
6172
+ positions.push(i);
6173
+ }
6174
+ if (positions.length === 0) {
6175
+ throw new MultipartParseError(
6176
+ `\u8BF7\u6C42\u4F53\u91CC\u627E\u4E0D\u5230 boundary "${boundary}" \u7684\u5206\u9694\u7B26\u2014\u2014\u53EF\u80FD\u662F\u8BF7\u6C42\u88AB\u622A\u65AD\u6216 Content-Type \u4E0E\u8BF7\u6C42\u4F53\u4E0D\u5339\u914D`
6177
+ );
6178
+ }
6179
+ const lastPos = positions[positions.length - 1];
6180
+ if (raw[lastPos + delim.length] !== 45 || raw[lastPos + delim.length + 1] !== 45) {
6181
+ throw new MultipartParseError("multipart \u6570\u636E\u88AB\u622A\u65AD\uFF1A\u7F3A\u5C11\u7EC8\u7ED3\u5206\u9694\u7B26 --boundary--");
6182
+ }
6183
+ const files = [];
6184
+ const fields = {};
6185
+ let fieldCount = 0;
6186
+ for (let k = 0; k + 1 < positions.length; k++) {
6187
+ const partStart = positions[k] + delim.length + 2;
6188
+ const partEnd = positions[k + 1] - 2;
6189
+ if (raw[partStart - 2] !== 13 || raw[partStart - 1] !== 10) {
6190
+ throw new MultipartParseError("multipart \u5206\u9694\u7B26\u540E\u7F3A\u5C11 CRLF\uFF0C\u8BF7\u6C42\u4F53\u683C\u5F0F\u975E\u6CD5");
6191
+ }
6192
+ if (partEnd < partStart) {
6193
+ throw new MultipartParseError("multipart part \u5185\u5BB9\u4E3A\u7A7A\uFF08header \u4E0E\u6B63\u6587\u90FD\u4E0D\u5B58\u5728\uFF09");
6194
+ }
6195
+ const part = raw.subarray(partStart, partEnd);
6196
+ const headerSep = indexOfSequence(part, HEADER_BODY_SEP, 0);
6197
+ if (headerSep < 0) {
6198
+ throw new MultipartParseError("multipart part \u7F3A\u5C11 header \u4E0E\u6B63\u6587\u4E4B\u95F4\u7684\u7A7A\u884C\u5206\u9694");
6199
+ }
6200
+ const headerLines = decoder2.decode(part.subarray(0, headerSep)).split("\r\n");
6201
+ const data = part.subarray(headerSep + HEADER_BODY_SEP.length);
6202
+ const disposition = headerLines.find(
6203
+ (line) => line.toLowerCase().startsWith("content-disposition:")
6204
+ );
6205
+ if (disposition === void 0) {
6206
+ throw new MultipartParseError("multipart part \u7F3A\u5C11 Content-Disposition \u5934");
6207
+ }
6208
+ const nameMatch = /name="((?:[^"\\]|\\.)*)"/.exec(disposition);
6209
+ if (nameMatch === null) {
6210
+ throw new MultipartParseError("multipart part \u7684 Content-Disposition \u7F3A\u5C11 name \u53C2\u6570");
6211
+ }
6212
+ const fieldName = unquote(nameMatch[1]);
6213
+ const filenameMatch = /filename="((?:[^"\\]|\\.)*)"/.exec(disposition);
6214
+ if (filenameMatch !== null) {
6215
+ const clientName = unquote(filenameMatch[1]);
6216
+ if (clientName === "") continue;
6217
+ const typeLine = headerLines.find((line) => line.toLowerCase().startsWith("content-type:"));
6218
+ const type = typeLine === void 0 ? "application/octet-stream" : typeLine.slice(typeLine.indexOf(":") + 1).trim();
6219
+ files.push({ name: clientName, type, size: data.length, data });
6220
+ } else {
6221
+ const value = decoder2.decode(data);
6222
+ const prev = fields[fieldName];
6223
+ if (prev === void 0) fields[fieldName] = value;
6224
+ else if (typeof prev === "string") fields[fieldName] = [prev, value];
6225
+ else fields[fieldName] = [...prev, value];
6226
+ fieldCount++;
6227
+ }
6228
+ }
6229
+ return { fields: fieldCount > 0 ? fields : void 0, files };
6230
+ }
6231
+ var MultipartParseError, HEADER_BODY_SEP, encoder2, decoder2;
6232
+ var init_multipart = __esm({
6233
+ "packages/runtime/src/shared/multipart.ts"() {
6234
+ "use strict";
6235
+ MultipartParseError = class extends Error {
6236
+ constructor(message) {
6237
+ super(message);
6238
+ this.name = "MultipartParseError";
6239
+ }
6240
+ };
6241
+ HEADER_BODY_SEP = [13, 10, 13, 10];
6242
+ encoder2 = new TextEncoder();
6243
+ decoder2 = new TextDecoder();
6244
+ }
6245
+ });
6246
+
6031
6247
  // packages/cli/src/dev-shared.ts
6032
6248
  import { readdir as readdir2, readFile as readFile8 } from "node:fs/promises";
6033
- import { join as join11 } from "node:path";
6034
- function bearerUserResolverFromEnv() {
6035
- const raw = process.env.ADEP_AUTH_ISSUER;
6036
- if (raw === void 0 || raw.trim() === "") return void 0;
6037
- return createBearerUserResolver(raw.trim());
6249
+ import { join as join12 } from "node:path";
6250
+ function bearerUserResolverFromEnv(fileEnv = {}) {
6251
+ const raw = firstNonEmpty(process.env.ADEP_AUTH_ISSUER, fileEnv.ADEP_AUTH_ISSUER);
6252
+ return raw === void 0 ? void 0 : createBearerUserResolver(raw);
6253
+ }
6254
+ function firstNonEmpty(...values) {
6255
+ for (const value of values) {
6256
+ const trimmed = value?.trim();
6257
+ if (trimmed !== void 0 && trimmed !== "") return trimmed;
6258
+ }
6259
+ return void 0;
6038
6260
  }
6039
6261
  function createBearerUserResolver(issuer) {
6040
6262
  const userinfoUrl = `${issuer.replace(/\/+$/, "")}/oauth/userinfo`;
@@ -6071,7 +6293,7 @@ async function collectFunctions(dir, readImpl = (path) => readFile8(path, "utf8"
6071
6293
  }
6072
6294
  for (const entry of entries) {
6073
6295
  const rel = prefix.length === 0 ? entry.name : `${prefix}/${entry.name}`;
6074
- const full = join11(sub, entry.name);
6296
+ const full = join12(sub, entry.name);
6075
6297
  if (entry.isDirectory()) {
6076
6298
  await walk(full, rel);
6077
6299
  } else if (entry.isFile() && isRuntimeSource(entry.name)) {
@@ -6101,25 +6323,41 @@ function mergeSharedIntoFunctions(files) {
6101
6323
  }
6102
6324
  return out;
6103
6325
  }
6104
- function bodyOf(req) {
6105
- return new Promise((resolveBody, rejectBody) => {
6326
+ function readRawBody(req) {
6327
+ return new Promise((resolveRaw, rejectRaw) => {
6106
6328
  const chunks = [];
6107
6329
  req.on("data", (chunk) => chunks.push(chunk));
6108
- req.on("end", () => {
6109
- const raw = Buffer.concat(chunks).toString("utf8");
6110
- if (raw.length === 0) {
6111
- resolveBody(void 0);
6112
- return;
6113
- }
6114
- try {
6115
- resolveBody(JSON.parse(raw));
6116
- } catch {
6117
- resolveBody(raw);
6118
- }
6119
- });
6120
- req.on("error", rejectBody);
6330
+ req.on("end", () => resolveRaw(Buffer.concat(chunks)));
6331
+ req.on("error", rejectRaw);
6121
6332
  });
6122
6333
  }
6334
+ async function bodyOf(req) {
6335
+ const raw = (await readRawBody(req)).toString("utf8");
6336
+ if (raw.length === 0) return void 0;
6337
+ try {
6338
+ return JSON.parse(raw);
6339
+ } catch {
6340
+ return raw;
6341
+ }
6342
+ }
6343
+ async function bodyWithFiles(req) {
6344
+ const contentType = String(req.headers["content-type"] ?? "");
6345
+ if (!contentType.toLowerCase().startsWith("multipart/form-data")) {
6346
+ return { body: await bodyOf(req) };
6347
+ }
6348
+ const bytes = await readRawBody(req);
6349
+ let parsed;
6350
+ try {
6351
+ parsed = parseMultipart(contentType, bytes);
6352
+ } catch (error62) {
6353
+ const message = error62 instanceof MultipartParseError ? error62.message : `multipart \u89E3\u6790\u5931\u8D25\uFF1A${error62 instanceof Error ? error62.message : String(error62)}`;
6354
+ throw new ExecutorError(400, "FN_MULTIPART_INVALID", message);
6355
+ }
6356
+ return {
6357
+ body: parsed.fields,
6358
+ ...parsed.files.length > 0 ? { files: [...parsed.files] } : {}
6359
+ };
6360
+ }
6123
6361
  function writeJson(res, status, payload) {
6124
6362
  res.writeHead(status, { "content-type": "application/json" });
6125
6363
  res.end(JSON.stringify(payload));
@@ -6134,13 +6372,14 @@ async function requestInput(url2, req, readBody) {
6134
6372
  for (const [key, value] of Object.entries(req.headers)) {
6135
6373
  if (typeof value === "string") headers[key] = value;
6136
6374
  }
6137
- const body = req.method === "GET" || req.method === "HEAD" ? void 0 : await readBody(req);
6375
+ const parsed = req.method === "GET" || req.method === "HEAD" ? void 0 : await readBody(req);
6138
6376
  return {
6139
6377
  method: req.method ?? "GET",
6140
6378
  path: url2.pathname,
6141
6379
  query,
6142
6380
  headers,
6143
- ...body === void 0 ? {} : { body }
6381
+ ...parsed?.body === void 0 ? {} : { body: parsed.body },
6382
+ ...parsed?.files === void 0 ? {} : { files: parsed.files }
6144
6383
  };
6145
6384
  }
6146
6385
  var BEARER_TOKEN_RE;
@@ -6149,6 +6388,8 @@ var init_dev_shared = __esm({
6149
6388
  "use strict";
6150
6389
  init_function_source();
6151
6390
  init_shared_source();
6391
+ init_multipart();
6392
+ init_executor_runtime();
6152
6393
  init_invoke();
6153
6394
  BEARER_TOKEN_RE = /^Bearer\s+(.+)$/i;
6154
6395
  }
@@ -6164,8 +6405,8 @@ __export(dev_exports, {
6164
6405
  });
6165
6406
  import { createServer } from "node:http";
6166
6407
  import { watch } from "node:fs";
6167
- import { mkdir as mkdir6, readFile as readFile9, writeFile as writeFile4 } from "node:fs/promises";
6168
- import { basename, join as join12, resolve as resolve6 } from "node:path";
6408
+ import { mkdir as mkdir6, readFile as readFile9, writeFile as writeFile5 } from "node:fs/promises";
6409
+ import { basename, join as join13, resolve as resolve6 } from "node:path";
6169
6410
  async function loadConfig(cwd) {
6170
6411
  const name = basename(resolve6(cwd));
6171
6412
  const config2 = await loadAdepConfigModule(cwd);
@@ -6210,10 +6451,10 @@ function printBoundaries(log) {
6210
6451
  }
6211
6452
  }
6212
6453
  async function ensureGitignore(cwd) {
6213
- const gitignorePath = join12(cwd, ".gitignore");
6454
+ const gitignorePath = join13(cwd, ".gitignore");
6214
6455
  const existing = await readFile9(gitignorePath, "utf8").catch(() => "");
6215
6456
  if (existing.split(/\r?\n/).includes(".adep/")) return;
6216
- await writeFile4(gitignorePath, `${existing.replace(/\n+$/, "")}
6457
+ await writeFile5(gitignorePath, `${existing.replace(/\n+$/, "")}
6217
6458
  .adep/
6218
6459
  `, "utf8");
6219
6460
  }
@@ -6225,14 +6466,14 @@ async function startDevServer(options) {
6225
6466
  if (options.prefix !== void 0) {
6226
6467
  config2.functionsPrefix = options.prefix.replace(/^\/+|\/+$/g, "");
6227
6468
  }
6228
- const functionsDir = join12(cwd, config2.functionsDir);
6469
+ const functionsDir = join13(cwd, config2.functionsDir);
6229
6470
  const coldStartAt = Date.now();
6230
6471
  const dbTarget = resolveLocalDbTarget(cwd, {
6231
6472
  ...options.db === void 0 ? {} : { db: options.db },
6232
6473
  ...options.dbFile === void 0 ? {} : { dbFile: options.dbFile }
6233
6474
  });
6234
- const bearerUser = bearerUserResolverFromEnv();
6235
6475
  const simEnv = await loadSimEnv(cwd).catch(() => ({}));
6476
+ let bearerUser = bearerUserResolverFromEnv(simEnv);
6236
6477
  const fetchConfig = resolveLocalFetchConfig(simEnv);
6237
6478
  const executor = new WorkerFunctionExecutor({
6238
6479
  deps: { rootDir: cwd, builtin: LOCAL_BUILTIN_DEPS },
@@ -6342,12 +6583,13 @@ async function startDevServer(options) {
6342
6583
  const reload = async () => {
6343
6584
  const [nextFiles, envText2] = await Promise.all([
6344
6585
  collectFunctions(functionsDir).then(mergeSharedIntoFunctions),
6345
- readFile9(join12(cwd, ".env.local"), "utf8").catch(() => "")
6586
+ readFile9(join13(cwd, ".env.local"), "utf8").catch(() => "")
6346
6587
  ]);
6347
6588
  files = nextFiles;
6348
6589
  env = { ...config2.environment, ...parseEnvFile(envText2) };
6590
+ bearerUser = bearerUserResolverFromEnv(await loadSimEnv(cwd).catch(() => ({})));
6349
6591
  };
6350
- const envText = await readFile9(join12(cwd, ".env.local"), "utf8").catch(() => "");
6592
+ const envText = await readFile9(join13(cwd, ".env.local"), "utf8").catch(() => "");
6351
6593
  env = { ...config2.environment, ...parseEnvFile(envText) };
6352
6594
  let debounceTimer;
6353
6595
  let watcher;
@@ -6363,7 +6605,7 @@ async function startDevServer(options) {
6363
6605
  }
6364
6606
  const buildInput = async (fnName, entry, url2, req) => {
6365
6607
  const hasEnv = Object.keys(env).length > 0;
6366
- const request = await requestInput(url2, req, bodyOf);
6608
+ const request = await requestInput(url2, req, bodyWithFiles);
6367
6609
  if (bearerUser !== void 0) request.user = await bearerUser(request.headers);
6368
6610
  return {
6369
6611
  project: { id: "local", slug: config2.name },
@@ -6437,9 +6679,9 @@ async function startDevServer(options) {
6437
6679
  writeJson(res, 404, { error: { code: "FN_NOT_FOUND", message: `\u51FD\u6570 "${fnName}" \u4E0D\u5B58\u5728` } });
6438
6680
  return;
6439
6681
  }
6440
- const input2 = await buildInput(fnName, entry, url2, req);
6441
6682
  const startedAt = performance.now();
6442
6683
  try {
6684
+ const input2 = await buildInput(fnName, entry, url2, req);
6443
6685
  const result = await executor.execute(input2);
6444
6686
  const durationMs = Math.round(performance.now() - startedAt);
6445
6687
  for (const line of result.logs) log(`[adep] ${line}`);
@@ -6512,7 +6754,9 @@ async function startDevServer(options) {
6512
6754
  log(`[adep] curl \u793A\u4F8B\uFF1Acurl ${baseUrl}${curlPath}`);
6513
6755
  printBoundaries(log);
6514
6756
  if (bearerUser !== void 0) {
6515
- log(`[adep] \u767B\u5F55\u5373\u670D\u52A1\uFF1AADEP_AUTH_ISSUER \u5DF2\u914D\u7F6E\uFF0CBearer token \u5C06\u89E3\u6790\u4E3A\u7528\u6237\u8EAB\u4EFD\uFF08userinfo \u7AEF\u70B9\uFF09`);
6757
+ log(
6758
+ `[adep] \u767B\u5F55\u5373\u670D\u52A1\uFF1AADEP_AUTH_ISSUER \u5DF2\u914D\u7F6E\uFF0CBearer token \u5C06\u89E3\u6790\u4E3A\u7528\u6237\u8EAB\u4EFD\uFF08userinfo \u7AEF\u70B9\uFF09`
6759
+ );
6516
6760
  }
6517
6761
  log(`[adep] \u6570\u636E\u5E93\uFF1A${dbLabel} \u2192 ${dbTargetText}`);
6518
6762
  startStateAlarmScheduler();
@@ -6598,7 +6842,7 @@ var client_exports2 = {};
6598
6842
  __export(client_exports2, {
6599
6843
  createExportApiClient: () => createExportApiClient
6600
6844
  });
6601
- import { writeFile as writeFile7 } from "node:fs/promises";
6845
+ import { writeFile as writeFile8 } from "node:fs/promises";
6602
6846
  function toExportJob(view) {
6603
6847
  return {
6604
6848
  id: view.id,
@@ -6649,7 +6893,7 @@ async function createExportApiClient(paths) {
6649
6893
  }
6650
6894
  const response = await client.download(download.downloadUrl, "EXPORT_DOWNLOAD_FAILED");
6651
6895
  const bytes = Buffer.from(await response.arrayBuffer());
6652
- await writeFile7(outputPath, bytes);
6896
+ await writeFile8(outputPath, bytes);
6653
6897
  return { path: outputPath, size: bytes.length };
6654
6898
  }
6655
6899
  };
@@ -6933,7 +7177,7 @@ function zipRead(buf) {
6933
7177
  if (eocd < 0) throw new ZipFormatError("\u627E\u4E0D\u5230 EOCD \u7B7E\u540D");
6934
7178
  const total = r.u16(eocd + 10);
6935
7179
  const centralOffset = r.u32(eocd + 16);
6936
- const decoder2 = new TextDecoder();
7180
+ const decoder3 = new TextDecoder();
6937
7181
  const out = /* @__PURE__ */ new Map();
6938
7182
  let cursor = centralOffset;
6939
7183
  for (let i = 0; i < total; i++) {
@@ -6947,7 +7191,7 @@ function zipRead(buf) {
6947
7191
  const commentLen = r.u16(cursor + 32);
6948
7192
  const localHeaderOffset = r.u32(cursor + 42);
6949
7193
  if (localHeaderOffset + 30 > buf.length) throw new ZipFormatError("\u672C\u5730\u5934\u504F\u79FB\u8D8A\u754C");
6950
- const name = decoder2.decode(r.slice(cursor + 46, nameLen));
7194
+ const name = decoder3.decode(r.slice(cursor + 46, nameLen));
6951
7195
  const localNameLen = r.u16(localHeaderOffset + 26);
6952
7196
  const localExtraLen = r.u16(localHeaderOffset + 28);
6953
7197
  const dataStart = localHeaderOffset + 30 + localNameLen + localExtraLen;
@@ -7073,6 +7317,58 @@ var init_banner = __esm({
7073
7317
  }
7074
7318
  });
7075
7319
 
7320
+ // packages/cli/src/serve/staleness.ts
7321
+ function diffFunctionFiles(snapshot, current) {
7322
+ const changes = [];
7323
+ for (const path of Object.keys(snapshot)) {
7324
+ const before = snapshot[path];
7325
+ const after = current[path];
7326
+ if (after === void 0) changes.push(`\u5220\u9664 ${path}`);
7327
+ else if (before !== after) changes.push(`\u4FEE\u6539 ${path}`);
7328
+ }
7329
+ for (const path of Object.keys(current)) {
7330
+ if (snapshot[path] === void 0) changes.push(`\u65B0\u589E ${path}`);
7331
+ }
7332
+ return changes.toSorted();
7333
+ }
7334
+ function stalenessWarning(changes) {
7335
+ const shown = changes.slice(0, 3).join("\u3001");
7336
+ const more = changes.length > 3 ? ` \u7B49 ${changes.length} \u5904` : "";
7337
+ return `[serve] \u26A0\uFE0F \u6E90\u7801\u5DF2\u53D8\u66F4\u4F46\u8FDB\u7A0B\u5185\u4ECD\u662F\u65E7\u4EE3\u7801\uFF08${shown}${more}\uFF09\u3002\u8BF7\u91CD\u542F serve \u6216\u6539\u7528 --watch \u70ED\u91CD\u8F7D\u3002`;
7338
+ }
7339
+ function createStalenessGuard(options) {
7340
+ const { loadedFiles, loadFiles, log } = options;
7341
+ const minIntervalMs = options.minIntervalMs ?? 2e3;
7342
+ let lastScanAt = -Infinity;
7343
+ let warned = false;
7344
+ return {
7345
+ check: async () => {
7346
+ const now = Date.now();
7347
+ if (now - lastScanAt < minIntervalMs) return;
7348
+ lastScanAt = now;
7349
+ let current;
7350
+ try {
7351
+ current = await loadFiles();
7352
+ } catch {
7353
+ return;
7354
+ }
7355
+ const changes = diffFunctionFiles(loadedFiles, current);
7356
+ if (changes.length === 0) {
7357
+ warned = false;
7358
+ return;
7359
+ }
7360
+ if (warned) return;
7361
+ warned = true;
7362
+ log(stalenessWarning(changes));
7363
+ }
7364
+ };
7365
+ }
7366
+ var init_staleness = __esm({
7367
+ "packages/cli/src/serve/staleness.ts"() {
7368
+ "use strict";
7369
+ }
7370
+ });
7371
+
7076
7372
  // shared/sdk/template-params.ts
7077
7373
  function extractTemplateFields(root) {
7078
7374
  if (root === null || typeof root !== "object") {
@@ -7200,7 +7496,7 @@ var init_template_params = __esm({
7200
7496
 
7201
7497
  // packages/cli/src/serve/template-params.ts
7202
7498
  import { readFile as readFile20 } from "node:fs/promises";
7203
- import { join as join27 } from "node:path";
7499
+ import { join as join28 } from "node:path";
7204
7500
  import { parse as parse3 } from "yaml";
7205
7501
  function mergeTemplateEnvSource(source) {
7206
7502
  return { ...source.processEnv, ...source.dotenv, ...source.dotenvLocal };
@@ -7208,7 +7504,7 @@ function mergeTemplateEnvSource(source) {
7208
7504
  async function loadTemplateFields(cwd) {
7209
7505
  let text;
7210
7506
  try {
7211
- text = await readFile20(join27(cwd, TEMPLATE_PARAMS_FILE), "utf8");
7507
+ text = await readFile20(join28(cwd, TEMPLATE_PARAMS_FILE), "utf8");
7212
7508
  } catch {
7213
7509
  return null;
7214
7510
  }
@@ -7224,7 +7520,7 @@ async function loadTemplateFields(cwd) {
7224
7520
  return extractTemplateFields(root);
7225
7521
  }
7226
7522
  async function readDotenvFile(cwd, name) {
7227
- const text = await readFile20(join27(cwd, name), "utf8").catch(() => "");
7523
+ const text = await readFile20(join28(cwd, name), "utf8").catch(() => "");
7228
7524
  if (text === "") return {};
7229
7525
  return parseEnvFile(text);
7230
7526
  }
@@ -7280,7 +7576,7 @@ __export(server_exports, {
7280
7576
  import { createServer as createServer2 } from "node:http";
7281
7577
  import { watch as watch2 } from "node:fs";
7282
7578
  import { mkdir as mkdir14, readFile as readFile21, stat as stat12 } from "node:fs/promises";
7283
- import { extname, join as join28, relative as relative4, resolve as resolve12 } from "node:path";
7579
+ import { extname, join as join29, relative as relative4, resolve as resolve12 } from "node:path";
7284
7580
  function envNumber(name) {
7285
7581
  const raw = process.env[name];
7286
7582
  if (raw === void 0 || raw.trim() === "") return void 0;
@@ -7313,8 +7609,7 @@ async function startServeServer(options) {
7313
7609
  ...options.dbFile === void 0 ? {} : { dbFile: options.dbFile }
7314
7610
  });
7315
7611
  const config2 = await loadConfig(cwd);
7316
- const functionsDir = join28(cwd, config2.functionsDir);
7317
- const bearerUser = bearerUserResolverFromEnv();
7612
+ const functionsDir = join29(cwd, config2.functionsDir);
7318
7613
  let hasStatic = false;
7319
7614
  try {
7320
7615
  const publicStat = await stat12(staticDir);
@@ -7325,9 +7620,10 @@ async function startServeServer(options) {
7325
7620
  const loadFunctionFiles = async () => mergeSharedIntoFunctions(await collectFunctions(functionsDir));
7326
7621
  let files = await loadFunctionFiles();
7327
7622
  let functionNames = listFunctionNames(files);
7328
- const envText = await readFile21(join28(cwd, ".env.local"), "utf8").catch(() => "");
7623
+ const envText = await readFile21(join29(cwd, ".env.local"), "utf8").catch(() => "");
7329
7624
  let env = parseEnvFile(envText);
7330
7625
  let simEnv = await loadSimEnv(cwd).catch(() => ({}));
7626
+ let bearerUser = bearerUserResolverFromEnv(simEnv);
7331
7627
  const dotenvFile = await readDotenvFile(cwd, ".env");
7332
7628
  let templateEnv;
7333
7629
  try {
@@ -7378,16 +7674,23 @@ async function startServeServer(options) {
7378
7674
  }
7379
7675
  const dbBundle = runtime.bundle;
7380
7676
  let invokeHandler = createSimInvokeHandler({ executor, files });
7677
+ const stalenessGuard = options.watch === true ? void 0 : createStalenessGuard({
7678
+ loadedFiles: { ...files },
7679
+ loadFiles: loadFunctionFiles,
7680
+ log,
7681
+ ...options.stalenessCheckIntervalMs === void 0 ? {} : { minIntervalMs: options.stalenessCheckIntervalMs }
7682
+ });
7381
7683
  let stopWatch;
7382
7684
  if (options.watch === true) {
7383
7685
  const reload = async () => {
7384
7686
  const [nextFiles, envLocalText] = await Promise.all([
7385
7687
  loadFunctionFiles(),
7386
- readFile21(join28(cwd, ".env.local"), "utf8").catch(() => "")
7688
+ readFile21(join29(cwd, ".env.local"), "utf8").catch(() => "")
7387
7689
  ]);
7388
7690
  files = nextFiles;
7389
7691
  env = parseEnvFile(envLocalText);
7390
7692
  simEnv = await loadSimEnv(cwd).catch(() => ({}));
7693
+ bearerUser = bearerUserResolverFromEnv(simEnv);
7391
7694
  invokeHandler = createSimInvokeHandler({ executor, files });
7392
7695
  functionNames = listFunctionNames(files);
7393
7696
  log(`[serve] \u70ED\u91CD\u8F7D\uFF1A\u68C0\u6D4B\u5230\u53D8\u66F4\uFF0C\u5DF2\u91CD\u65B0\u52A0\u8F7D ${functionNames.length} \u4E2A\u51FD\u6570`);
@@ -7418,7 +7721,7 @@ async function startServeServer(options) {
7418
7721
  const buildInput = async (fnName, entry, url2, req) => {
7419
7722
  const hasEnv = Object.keys(env).length > 0 || Object.keys(simEnv).length > 0 || Object.keys(config2.environment ?? {}).length > 0;
7420
7723
  const mergedEnv = { ...config2.environment, ...simEnv, ...env };
7421
- const request = await requestInput(url2, req, bodyOf);
7724
+ const request = await requestInput(url2, req, bodyWithFiles);
7422
7725
  if (bearerUser !== void 0) request.user = await bearerUser(request.headers);
7423
7726
  return {
7424
7727
  project: { id: "local", slug: config2.name },
@@ -7455,12 +7758,12 @@ async function startServeServer(options) {
7455
7758
  const serveStatic = async (pathname, res) => {
7456
7759
  if (!hasStatic) return false;
7457
7760
  const safePath = pathname.replace(/\.\.\//g, "").replace(/^\//, "");
7458
- const filePath = join28(staticDir, safePath);
7459
- const resolvedPath = safePath === "" || safePath === "/" ? join28(filePath, "index.html") : filePath;
7761
+ const filePath = join29(staticDir, safePath);
7762
+ const resolvedPath = safePath === "" || safePath === "/" ? join29(filePath, "index.html") : filePath;
7460
7763
  try {
7461
7764
  const fileStat = await stat12(resolvedPath);
7462
7765
  if (fileStat.isDirectory()) {
7463
- const indexPath = join28(resolvedPath, "index.html");
7766
+ const indexPath = join29(resolvedPath, "index.html");
7464
7767
  try {
7465
7768
  const indexStat = await stat12(indexPath);
7466
7769
  if (indexStat.isFile()) {
@@ -7478,8 +7781,8 @@ async function startServeServer(options) {
7478
7781
  const ext = extname(pathname);
7479
7782
  if (ext === "" || ext === ".html") {
7480
7783
  try {
7481
- const indexContent = await readFile21(join28(staticDir, "index.html"));
7482
- sendStaticFile(res, join28(staticDir, "index.html"), indexContent);
7784
+ const indexContent = await readFile21(join29(staticDir, "index.html"));
7785
+ sendStaticFile(res, join29(staticDir, "index.html"), indexContent);
7483
7786
  return true;
7484
7787
  } catch {
7485
7788
  }
@@ -7562,15 +7865,16 @@ async function startServeServer(options) {
7562
7865
  });
7563
7866
  return;
7564
7867
  }
7868
+ await stalenessGuard?.check();
7565
7869
  const entry = resolveFunctionEntry(files, fnName);
7566
7870
  if (entry === void 0) {
7567
7871
  log(`[serve] ${req.method ?? "GET"} ${pathname} -> 404\uFF08\u51FD\u6570\u4E0D\u5B58\u5728\uFF09`);
7568
7872
  writeJson(res, 404, { error: { code: "FN_NOT_FOUND", message: `\u51FD\u6570 "${fnName}" \u4E0D\u5B58\u5728` } });
7569
7873
  return;
7570
7874
  }
7571
- const input2 = await buildInput(fnName, entry, url2, req);
7572
7875
  const startedAt = performance.now();
7573
7876
  try {
7877
+ const input2 = await buildInput(fnName, entry, url2, req);
7574
7878
  const result = await executor.execute(input2);
7575
7879
  const durationMs = Math.round(performance.now() - startedAt);
7576
7880
  if (options.watch === true) {
@@ -7711,6 +8015,7 @@ var init_server = __esm({
7711
8015
  init_invoke();
7712
8016
  init_dev();
7713
8017
  init_banner();
8018
+ init_staleness();
7714
8019
  init_template_params2();
7715
8020
  init_adep_env_inject();
7716
8021
  init_template_params();
@@ -7740,6 +8045,20 @@ var init_server = __esm({
7740
8045
  }
7741
8046
  });
7742
8047
 
8048
+ // packages/cli/src/hash.ts
8049
+ import { createHash as createHash4 } from "node:crypto";
8050
+ function sha256Hex(content) {
8051
+ return createHash4("sha256").update(content).digest("hex");
8052
+ }
8053
+ function sha256HexOfBytes(bytes) {
8054
+ return createHash4("sha256").update(bytes).digest("hex");
8055
+ }
8056
+ var init_hash = __esm({
8057
+ "packages/cli/src/hash.ts"() {
8058
+ "use strict";
8059
+ }
8060
+ });
8061
+
7743
8062
  // packages/cli/src/deploy.ts
7744
8063
  var deploy_exports = {};
7745
8064
  __export(deploy_exports, {
@@ -7748,9 +8067,8 @@ __export(deploy_exports, {
7748
8067
  collectShared: () => collectShared,
7749
8068
  deploy: () => deploy
7750
8069
  });
7751
- import { createHash as createHash4 } from "node:crypto";
7752
8070
  import { readdir as readdir9, readFile as readFile22 } from "node:fs/promises";
7753
- import { join as join29, resolve as resolve13, basename as basename4, relative as relative5, sep } from "node:path";
8071
+ import { join as join30, resolve as resolve13, basename as basename4, relative as relative5, sep } from "node:path";
7754
8072
  function functionUrlBase(prefix) {
7755
8073
  const raw = (prefix ?? "/api").trim();
7756
8074
  const normalized = raw === "/" ? "/" : raw.replace(/\/+$/, "");
@@ -7776,10 +8094,10 @@ async function collectFunctionFiles(functionsDir) {
7776
8094
  if (conflicting.length > 0) throw new AmbiguousFunctionError(functionsDir, conflicting);
7777
8095
  const out = {};
7778
8096
  for (const name of flatNames) {
7779
- out[name] = { [`${name}.ts`]: await readFile22(join29(functionsDir, `${name}.ts`), "utf8") };
8097
+ out[name] = { [`${name}.ts`]: await readFile22(join30(functionsDir, `${name}.ts`), "utf8") };
7780
8098
  }
7781
8099
  for (const name of dirNames) {
7782
- const files = await collectFunctionDir(join29(functionsDir, name));
8100
+ const files = await collectFunctionDir(join30(functionsDir, name));
7783
8101
  if (files["index.ts"] === void 0) continue;
7784
8102
  out[name] = files;
7785
8103
  }
@@ -7798,21 +8116,18 @@ async function collectFunctionDir(absDir) {
7798
8116
  const rel = prefix === "" ? entry.name : `${prefix}/${entry.name}`;
7799
8117
  if (entry.isDirectory()) {
7800
8118
  if (entry.name === "__tests__" || IGNORED_DIRS.has(entry.name)) continue;
7801
- await walk(join29(dir, entry.name), rel);
8119
+ await walk(join30(dir, entry.name), rel);
7802
8120
  continue;
7803
8121
  }
7804
8122
  if (!isRuntimeSource2(entry.name)) continue;
7805
- files[rel] = await readFile22(join29(dir, entry.name), "utf8");
8123
+ files[rel] = await readFile22(join30(dir, entry.name), "utf8");
7806
8124
  }
7807
8125
  };
7808
8126
  await walk(absDir, "");
7809
8127
  return files;
7810
8128
  }
7811
- function sha256Hex(content) {
7812
- return createHash4("sha256").update(content).digest("hex");
7813
- }
7814
8129
  async function collectShared(functionsDir) {
7815
- const sharedDir = join29(functionsDir, FUNCTION_SHARED_DIR);
8130
+ const sharedDir = join30(functionsDir, FUNCTION_SHARED_DIR);
7816
8131
  const files = {};
7817
8132
  const walk = async (dir) => {
7818
8133
  let entries;
@@ -7824,11 +8139,11 @@ async function collectShared(functionsDir) {
7824
8139
  for (const entry of entries) {
7825
8140
  if (entry.isDirectory()) {
7826
8141
  if (entry.name === "__tests__" || entry.name === "node_modules") continue;
7827
- await walk(join29(dir, entry.name));
8142
+ await walk(join30(dir, entry.name));
7828
8143
  continue;
7829
8144
  }
7830
8145
  if (!isRuntimeSource2(entry.name)) continue;
7831
- const full = join29(dir, entry.name);
8146
+ const full = join30(dir, entry.name);
7832
8147
  const rel = relative5(sharedDir, full).split(sep).join("/");
7833
8148
  files[`${SHARED_SOURCE_ROOT}${rel}`] = await readFile22(full, "utf8");
7834
8149
  }
@@ -7842,7 +8157,7 @@ async function deploy(paths, options) {
7842
8157
  const cwd = resolve13(options.cwd);
7843
8158
  const config2 = await loadConfig(cwd);
7844
8159
  const slug = options.slug ?? config2.name;
7845
- const functionsDir = options.functionsDir === void 0 ? join29(cwd, config2.functionsDir) : resolve13(cwd, options.functionsDir);
8160
+ const functionsDir = options.functionsDir === void 0 ? join30(cwd, config2.functionsDir) : resolve13(cwd, options.functionsDir);
7846
8161
  const local = await collectFunctionFiles(functionsDir);
7847
8162
  if (Object.keys(local).length === 0) {
7848
8163
  throw new CliError("NO_FUNCTIONS", `${functionsDir} \u4E0B\u6CA1\u6709\u51FD\u6570\u6587\u4EF6`);
@@ -7946,6 +8261,7 @@ var init_deploy = __esm({
7946
8261
  init_function_source();
7947
8262
  init_auth();
7948
8263
  init_client();
8264
+ init_hash();
7949
8265
  init_dev();
7950
8266
  init_net();
7951
8267
  init_shared_source();
@@ -7973,8 +8289,8 @@ __export(storage_exports, {
7973
8289
  storageRemove: () => storageRemove,
7974
8290
  storageUpload: () => storageUpload
7975
8291
  });
7976
- import { mkdir as mkdir15, readFile as readFile23, stat as stat13, writeFile as writeFile14 } from "node:fs/promises";
7977
- import { basename as basename5, dirname as dirname13, extname as extname2, join as join30, resolve as resolve14 } from "node:path";
8292
+ import { mkdir as mkdir15, readFile as readFile23, stat as stat13, writeFile as writeFile15 } from "node:fs/promises";
8293
+ import { basename as basename5, dirname as dirname12, extname as extname2, join as join31, resolve as resolve14 } from "node:path";
7978
8294
  function envQuery2(options) {
7979
8295
  return options.environment === void 0 ? "" : `?environment=${options.environment}`;
7980
8296
  }
@@ -8066,9 +8382,9 @@ async function storageDownload(paths, options) {
8066
8382
  const url2 = await resolveDownloadUrl(client, project2, options.path, options.environment);
8067
8383
  const response = await client.download(url2, "STORAGE_DOWNLOAD_FAILED");
8068
8384
  const bytes = Buffer.from(await response.arrayBuffer());
8069
- const output2 = resolve14(options.output ?? join30(resolve14(options.cwd), basename5(options.path)));
8070
- await mkdir15(dirname13(output2), { recursive: true });
8071
- await writeFile14(output2, bytes);
8385
+ const output2 = resolve14(options.output ?? join31(resolve14(options.cwd), basename5(options.path)));
8386
+ await mkdir15(dirname12(output2), { recursive: true });
8387
+ await writeFile15(output2, bytes);
8072
8388
  return { path: options.path, output: output2, size: bytes.length };
8073
8389
  }
8074
8390
  async function storageRemove(paths, options) {
@@ -8095,7 +8411,8 @@ __export(hosting_exports, {
8095
8411
  hostingPull: () => hostingPull
8096
8412
  });
8097
8413
  import { readdir as readdir10, readFile as readFile24, stat as stat14 } from "node:fs/promises";
8098
- import { dirname as dirname14, join as join31, relative as relative6, resolve as resolve15, sep as sep2 } from "node:path";
8414
+ import { spawnSync } from "node:child_process";
8415
+ import { dirname as dirname13, join as join32, relative as relative6, resolve as resolve15, sep as sep2 } from "node:path";
8099
8416
  async function open5(paths, options) {
8100
8417
  const client = await createClient(paths);
8101
8418
  const project2 = await resolveSlug(resolve15(options.cwd), options.slug);
@@ -8121,7 +8438,7 @@ async function collectSiteFiles(dir) {
8121
8438
  return;
8122
8439
  }
8123
8440
  for (const entry of entries) {
8124
- const full = join31(sub, entry.name);
8441
+ const full = join32(sub, entry.name);
8125
8442
  if (entry.isDirectory()) {
8126
8443
  await walk(full);
8127
8444
  } else if (entry.isFile()) {
@@ -8137,25 +8454,70 @@ async function hostingDeploy(paths, options) {
8137
8454
  const { client, project: project2 } = await open5(paths, options);
8138
8455
  const log = options.log ?? ((line) => process.stdout.write(`${line}
8139
8456
  `));
8457
+ if (options.build !== void 0) {
8458
+ log(`[adep] \u6267\u884C\u6784\u5EFA\uFF1A${options.build}`);
8459
+ const runner = spawnSync(options.build, {
8460
+ shell: true,
8461
+ cwd: resolve15(options.cwd),
8462
+ stdio: options.log ? "pipe" : "inherit"
8463
+ });
8464
+ if (runner.status !== 0) {
8465
+ throw new CliError(
8466
+ "BUILD_FAILED",
8467
+ `\u6784\u5EFA\u547D\u4EE4\u5931\u8D25\uFF08exit ${runner.status ?? "\u672A\u77E5"}\uFF09\uFF1A${options.build}`
8468
+ );
8469
+ }
8470
+ }
8140
8471
  const files = await collectSiteFiles(options.dir);
8141
8472
  if (files.size === 0) {
8142
8473
  throw new CliError("NO_SITE_FILES", `\u7AD9\u70B9\u76EE\u5F55\u4E3A\u7A7A\uFF1A${resolve15(options.dir)}`);
8143
8474
  }
8144
- const uploaded = [];
8475
+ let newestMtimeMs = 0;
8476
+ const localEntries = /* @__PURE__ */ new Map();
8145
8477
  for (const [rel, full] of files) {
8478
+ const [info2, bytes] = await Promise.all([stat14(full), readFile24(full)]);
8479
+ localEntries.set(rel, { bytes, size: info2.size, hash: sha256HexOfBytes(bytes) });
8480
+ newestMtimeMs = Math.max(newestMtimeMs, info2.mtimeMs);
8481
+ }
8482
+ const builtAt = new Date(newestMtimeMs).toISOString();
8483
+ log(`[adep] \u90E8\u7F72\u5185\u5BB9\u6784\u5EFA\u4E8E ${builtAt}\uFF08\u672C\u5730\u76EE\u5F55\u6700\u65B0\u6587\u4EF6\u4FEE\u6539\u65F6\u95F4\uFF09`);
8484
+ const remote = await client.request(
8485
+ `/api/v1/projects/${project2}/hosting`
8486
+ );
8487
+ const remotePublic = /* @__PURE__ */ new Map();
8488
+ for (const entry of remote.files ?? []) {
8489
+ if (entry.visibility === "public" && entry.path.startsWith("site/") && entry.path !== HOSTING_CONFIG_PATH) {
8490
+ remotePublic.set(entry.path.slice("site/".length), entry);
8491
+ }
8492
+ }
8493
+ const uploaded = [];
8494
+ let reused = 0;
8495
+ for (const [rel, local] of localEntries) {
8496
+ const remoteEntry = remotePublic.get(rel);
8497
+ if (remoteEntry !== void 0 && remoteEntry.size === local.size && remoteEntry.url) {
8498
+ const response = await client.download(remoteEntry.url, "HOSTING_COMPARE_FAILED");
8499
+ const remoteBytes = new Uint8Array(await response.arrayBuffer());
8500
+ if (sha256HexOfBytes(remoteBytes) === local.hash) {
8501
+ reused += 1;
8502
+ continue;
8503
+ }
8504
+ }
8146
8505
  log(`[adep] \u4E0A\u4F20 site/${rel}`);
8147
- const info2 = await stat14(full);
8148
- const bytes = await readFile24(full);
8149
8506
  const form = new FormData();
8150
8507
  form.set("path", `site/${rel}`);
8151
8508
  form.set("visibility", "public");
8152
8509
  form.set(
8153
8510
  "file",
8154
- new Blob([bytes], { type: contentTypeOf(rel) }),
8511
+ new Blob([local.bytes], { type: contentTypeOf(rel) }),
8155
8512
  rel.split("/").pop()
8156
8513
  );
8157
8514
  await client.upload(`/api/v1/projects/${project2}/files`, form, "HOSTING_UPLOAD_FAILED");
8158
- uploaded.push({ path: `site/${rel}`, size: info2.size });
8515
+ uploaded.push({ path: `site/${rel}`, size: local.size });
8516
+ }
8517
+ const identical = uploaded.length === 0;
8518
+ if (identical) {
8519
+ log("\u26A0 \u672C\u6B21\u4E0A\u4F20\u5185\u5BB9\u4E0E\u7EBF\u4E0A\u73B0\u6709\u7248\u672C\u5B8C\u5168\u4E00\u81F4\u2014\u2014\u82E5\u521A\u4FEE\u6539\u8FC7\u6E90\u7801\uFF0C\u53EF\u80FD\u5FD8\u4E86\u5148\u6784\u5EFA\u3002");
8520
+ log(" \u5982\u786E\u5C5E\u91CD\u590D\u90E8\u7F72\uFF08\u4F8B\u5982\u91CD\u8BD5\uFF09\uFF0C\u53EF\u5FFD\u7565\u672C\u8B66\u793A\u3002");
8159
8521
  }
8160
8522
  const config2 = await client.request(
8161
8523
  `/api/v1/projects/${project2}/hosting`,
@@ -8165,7 +8527,7 @@ async function hostingDeploy(paths, options) {
8165
8527
  }
8166
8528
  );
8167
8529
  const info = await hostingInfo(paths, options);
8168
- return { config: config2.config, siteUrl: info.siteUrl, uploaded };
8530
+ return { config: config2.config, siteUrl: info.siteUrl, uploaded, reused, identical, builtAt };
8169
8531
  }
8170
8532
  async function hostingPull(paths, options) {
8171
8533
  const { client } = await open5(paths, options);
@@ -8173,7 +8535,7 @@ async function hostingPull(paths, options) {
8173
8535
  `));
8174
8536
  const info = await hostingInfo(paths, options);
8175
8537
  const outputDir = resolve15(options.output ?? resolve15(options.cwd));
8176
- const { mkdir: mkdir17, writeFile: writeFile16 } = await import("node:fs/promises");
8538
+ const { mkdir: mkdir17, writeFile: writeFile17 } = await import("node:fs/promises");
8177
8539
  const files = [];
8178
8540
  for (const entry of info.files) {
8179
8541
  if (entry.visibility !== "public" || entry.path === HOSTING_CONFIG_PATH) continue;
@@ -8183,9 +8545,9 @@ async function hostingPull(paths, options) {
8183
8545
  const response = await client.download(url2, "HOSTING_DOWNLOAD_FAILED");
8184
8546
  const bytes = Buffer.from(await response.arrayBuffer());
8185
8547
  const rel = entry.path.replace(/^site\//, "");
8186
- const target = join31(outputDir, ...rel.split("/"));
8187
- await mkdir17(dirname14(target), { recursive: true });
8188
- await writeFile16(target, bytes);
8548
+ const target = join32(outputDir, ...rel.split("/"));
8549
+ await mkdir17(dirname13(target), { recursive: true });
8550
+ await writeFile17(target, bytes);
8189
8551
  files.push({ path: entry.path, size: bytes.length });
8190
8552
  }
8191
8553
  return { siteUrl: info.siteUrl, outputDir, files };
@@ -8207,6 +8569,7 @@ var init_hosting = __esm({
8207
8569
  "use strict";
8208
8570
  init_client();
8209
8571
  init_auth();
8572
+ init_hash();
8210
8573
  init_storage2();
8211
8574
  HOSTING_CONFIG_PATH = "site/.hosting.json";
8212
8575
  }
@@ -8240,7 +8603,7 @@ __export(frontend_exports, {
8240
8603
  isStaticFrontendDir: () => isStaticFrontendDir
8241
8604
  });
8242
8605
  import { readdir as readdir11, readFile as readFile25, stat as stat15 } from "node:fs/promises";
8243
- import { join as join32, relative as relative7, sep as sep3 } from "node:path";
8606
+ import { join as join33, relative as relative7, sep as sep3 } from "node:path";
8244
8607
  async function collectFiles(root, dir) {
8245
8608
  const files = /* @__PURE__ */ new Map();
8246
8609
  const skipped = [];
@@ -8248,13 +8611,13 @@ async function collectFiles(root, dir) {
8248
8611
  for (const entry of entries) {
8249
8612
  if (entry.isDirectory()) {
8250
8613
  if (IGNORED_DIRS2.has(entry.name)) continue;
8251
- const nested = await collectFiles(root, join32(dir, entry.name));
8614
+ const nested = await collectFiles(root, join33(dir, entry.name));
8252
8615
  for (const [path, content] of nested.files) files.set(path, content);
8253
8616
  skipped.push(...nested.skipped);
8254
8617
  continue;
8255
8618
  }
8256
8619
  if (IGNORED_FILES.has(entry.name)) continue;
8257
- const full = join32(dir, entry.name);
8620
+ const full = join33(dir, entry.name);
8258
8621
  const rel = relative7(root, full).split(sep3).join("/");
8259
8622
  const info = await stat15(full);
8260
8623
  if (info.size > 1024 * 1024) {
@@ -8277,7 +8640,7 @@ async function collectFiles(root, dir) {
8277
8640
  async function frontendSync(paths, options) {
8278
8641
  const log = options.silent === true ? () => void 0 : options.log ?? ((line) => process.stdout.write(`${line}
8279
8642
  `));
8280
- const webDir = options.dir ?? join32(options.cwd, "web");
8643
+ const webDir = options.dir ?? join33(options.cwd, "web");
8281
8644
  const rootStat = await stat15(webDir).catch(() => null);
8282
8645
  if (rootStat === null || !rootStat.isDirectory()) {
8283
8646
  throw new CliError(
@@ -8337,14 +8700,14 @@ function declaresBuildScript(pkgJson) {
8337
8700
  return typeof build === "string" && build.trim().length > 0;
8338
8701
  }
8339
8702
  async function isStaticFrontendDir(dir) {
8340
- const pkg = await readFile25(join32(dir, "package.json"), "utf8").catch(() => void 0);
8703
+ const pkg = await readFile25(join33(dir, "package.json"), "utf8").catch(() => void 0);
8341
8704
  if (declaresBuildScript(pkg)) return false;
8342
8705
  const walk = async (sub) => {
8343
8706
  const entries = await readdir11(sub, { withFileTypes: true });
8344
8707
  for (const entry of entries) {
8345
8708
  if (entry.isDirectory()) {
8346
8709
  if (IGNORED_DIRS2.has(entry.name)) continue;
8347
- if (!await walk(join32(sub, entry.name))) return false;
8710
+ if (!await walk(join33(sub, entry.name))) return false;
8348
8711
  continue;
8349
8712
  }
8350
8713
  if (FRONTEND_TRANSFORM_EXTENSIONS.some((ext) => entry.name.endsWith(ext))) return false;
@@ -8380,12 +8743,12 @@ var fs_exports = {};
8380
8743
  __export(fs_exports, {
8381
8744
  createExportFileSystem: () => createExportFileSystem
8382
8745
  });
8383
- import { mkdir as mkdir16, readFile as readFile27, rm as rm5, stat as stat17, writeFile as writeFile15 } from "node:fs/promises";
8384
- import { dirname as dirname15, join as join35 } from "node:path";
8746
+ import { mkdir as mkdir16, readFile as readFile27, rm as rm5, stat as stat17, writeFile as writeFile16 } from "node:fs/promises";
8747
+ import { dirname as dirname14, join as join36 } from "node:path";
8385
8748
  function createExportFileSystem() {
8386
8749
  return {
8387
8750
  readFile: (path) => readFile27(path),
8388
- writeFile: (path, content) => writeFile15(path, content),
8751
+ writeFile: (path, content) => writeFile16(path, content),
8389
8752
  // 同时用于清理解压临时目录(${zip}.tmp 是个目录)——递归强制删除,缺失不报错。
8390
8753
  deleteFile: async (path) => {
8391
8754
  await rm5(path, { recursive: true, force: true });
@@ -8404,9 +8767,9 @@ function createExportFileSystem() {
8404
8767
  unzip: async (zipPath, targetDir) => {
8405
8768
  const entries = zipRead(await readFile27(zipPath));
8406
8769
  for (const [name, data] of entries) {
8407
- const dest = join35(targetDir, name);
8408
- await mkdir16(dirname15(dest), { recursive: true });
8409
- await writeFile15(dest, data);
8770
+ const dest = join36(targetDir, name);
8771
+ await mkdir16(dirname14(dest), { recursive: true });
8772
+ await writeFile16(dest, data);
8410
8773
  }
8411
8774
  }
8412
8775
  };
@@ -8651,7 +9014,7 @@ ${detail}`);
8651
9014
 
8652
9015
  // packages/cli/src/sandbox-scan.ts
8653
9016
  import { readdir as readdir13, readFile as readFile28 } from "node:fs/promises";
8654
- import { join as join36, relative as relative9, sep as sep5 } from "node:path";
9017
+ import { join as join37, relative as relative9, sep as sep5 } from "node:path";
8655
9018
  function extractSpecifiers(line) {
8656
9019
  const out = [];
8657
9020
  const patterns = [
@@ -8695,7 +9058,7 @@ function classify(specifier) {
8695
9058
  return null;
8696
9059
  }
8697
9060
  async function scanFunctionSources(rootDir, functionsDir) {
8698
- const base = join36(rootDir, functionsDir);
9061
+ const base = join37(rootDir, functionsDir);
8699
9062
  const findings = [];
8700
9063
  async function walk(current) {
8701
9064
  let entries;
@@ -8705,7 +9068,7 @@ async function scanFunctionSources(rootDir, functionsDir) {
8705
9068
  return;
8706
9069
  }
8707
9070
  for (const entry of entries) {
8708
- const abs = join36(current, entry.name);
9071
+ const abs = join37(current, entry.name);
8709
9072
  if (entry.isDirectory()) {
8710
9073
  if (SKIP_DIRS.has(entry.name)) continue;
8711
9074
  await walk(abs);
@@ -8839,6 +9202,7 @@ __export(doctor_exports, {
8839
9202
  runDoctor: () => runDoctor
8840
9203
  });
8841
9204
  import { stat as stat18 } from "node:fs/promises";
9205
+ import { join as join38 } from "node:path";
8842
9206
  async function probeServer(server) {
8843
9207
  const controller = new AbortController();
8844
9208
  const timer = setTimeout(() => controller.abort(), SERVER_PROBE_TIMEOUT_MS);
@@ -8866,14 +9230,15 @@ async function credentialMode(file2) {
8866
9230
  async function runDoctor(paths, cwd = process.cwd()) {
8867
9231
  const credentials = await loadCredentials(paths);
8868
9232
  const server = credentials?.server ?? resolveServer();
8869
- const mode = await credentialMode(paths.credentialsFile);
9233
+ const credentialsFile = credentials !== null ? join38(paths.credentialsDir, `${slotNameFor(credentials.server)}.json`) : paths.credentialsFile;
9234
+ const mode = await credentialMode(credentialsFile);
8870
9235
  const offline = await isOffline();
8871
9236
  const health = await probeServer(server);
8872
9237
  const sandbox = await scanSandbox(cwd);
8873
9238
  const report = {
8874
9239
  server,
8875
9240
  credentials: {
8876
- file: paths.credentialsFile,
9241
+ file: credentialsFile,
8877
9242
  present: credentials !== null,
8878
9243
  ...mode === void 0 ? {} : { mode }
8879
9244
  },
@@ -8885,7 +9250,7 @@ async function runDoctor(paths, cwd = process.cwd()) {
8885
9250
  };
8886
9251
  if (credentials !== null) report.credentials.email = credentials.email;
8887
9252
  if (mode !== void 0 && mode !== "600") {
8888
- report.credentials.warning = `\u6743\u9650 ${mode} \u5BBD\u4E8E 0600\uFF0C\u5EFA\u8BAE chmod 600 ${paths.credentialsFile}`;
9253
+ report.credentials.warning = `\u6743\u9650 ${mode} \u5BBD\u4E8E 0600\uFF0C\u5EFA\u8BAE chmod 600 ${credentialsFile}`;
8889
9254
  }
8890
9255
  return report;
8891
9256
  }
@@ -9330,12 +9695,12 @@ import { createRequire as createRequire2 } from "node:module";
9330
9695
  init_auth();
9331
9696
 
9332
9697
  // packages/cli/src/init.ts
9333
- import { mkdir as mkdir2, stat as stat2, writeFile } from "node:fs/promises";
9334
- import { dirname as dirname3, join as join2, resolve } from "node:path";
9698
+ import { mkdir as mkdir2, stat as stat2, writeFile as writeFile2 } from "node:fs/promises";
9699
+ import { dirname as dirname2, join as join3, resolve } from "node:path";
9335
9700
 
9336
9701
  // packages/cli/src/templates/registry.ts
9337
9702
  import { readFileSync } from "node:fs";
9338
- import { dirname as dirname2, join } from "node:path";
9703
+ import { dirname, join as join2 } from "node:path";
9339
9704
  import { fileURLToPath } from "node:url";
9340
9705
 
9341
9706
  // packages/cli/src/templates/generated.ts
@@ -12720,15 +13085,15 @@ var TEMPLATE_CODES = [
12720
13085
  ];
12721
13086
  var TEMPLATE_NAMES = TEMPLATE_CODES;
12722
13087
  function findCliPackageJson() {
12723
- let dir = dirname2(fileURLToPath(import.meta.url));
13088
+ let dir = dirname(fileURLToPath(import.meta.url));
12724
13089
  for (; ; ) {
12725
- const candidate = join(dir, "package.json");
13090
+ const candidate = join2(dir, "package.json");
12726
13091
  try {
12727
13092
  const pkg = JSON.parse(readFileSync(candidate, "utf8"));
12728
13093
  if (pkg.name === "@adep/cli") return candidate;
12729
13094
  } catch {
12730
13095
  }
12731
- const parent = dirname2(dir);
13096
+ const parent = dirname(dir);
12732
13097
  if (parent === dir) {
12733
13098
  throw new Error("\u627E\u4E0D\u5230 @adep/cli \u7684 package.json\uFF08\u5DF2\u904D\u5386\u5230\u6587\u4EF6\u7CFB\u7EDF\u6839\uFF09");
12734
13099
  }
@@ -12740,10 +13105,10 @@ function cliVersionOf() {
12740
13105
  return pkg.version;
12741
13106
  }
12742
13107
  function cliPackageRoot() {
12743
- return dirname2(findCliPackageJson());
13108
+ return dirname(findCliPackageJson());
12744
13109
  }
12745
13110
  function localTemplateDir(code) {
12746
- return join(cliPackageRoot(), "src", "templates", code);
13111
+ return join2(cliPackageRoot(), "src", "templates", code);
12747
13112
  }
12748
13113
  function templateFiles(code, name) {
12749
13114
  const generated = GENERATED_TEMPLATES[code];
@@ -12804,9 +13169,9 @@ async function initProject(cwd, name, template, filesOverride) {
12804
13169
  await mkdir2(projectPath, { recursive: true });
12805
13170
  await Promise.all(
12806
13171
  files.map(async (file2) => {
12807
- const target = join2(projectPath, file2.path);
12808
- await mkdir2(dirname3(target), { recursive: true });
12809
- await writeFile(target, file2.content);
13172
+ const target = join3(projectPath, file2.path);
13173
+ await mkdir2(dirname2(target), { recursive: true });
13174
+ await writeFile2(target, file2.content);
12810
13175
  })
12811
13176
  );
12812
13177
  return { projectPath, files: files.map((file2) => file2.path) };
@@ -12997,7 +13362,8 @@ function registerAuth(program2, ctx) {
12997
13362
  });
12998
13363
  command.ok(result2, (data) => {
12999
13364
  const d = data;
13000
- return `\u5DF2\u767B\u5F55\uFF1A${d.email}\uFF08\u51ED\u636E\u5DF2\u5199\u5165 ${ctx.paths.credentialsFile}\uFF0C\u6743\u9650 0600\uFF09`;
13365
+ const replaced = d.replacedEmail !== void 0 ? `\uFF0C\u5DF2\u66FF\u6362\u539F ${d.replacedEmail} \u7684\u51ED\u636E` : "";
13366
+ return `\u5DF2\u767B\u5F55\uFF1A${d.email}\uFF08\u51ED\u636E\u6309 server \u5206\u69FD\u4FDD\u5B58\u4E8E ${ctx.paths.credentialsDir}/\uFF0C\u6743\u9650 0600${replaced}\uFF09`;
13001
13367
  });
13002
13368
  return;
13003
13369
  }
@@ -13018,7 +13384,8 @@ function registerAuth(program2, ctx) {
13018
13384
  });
13019
13385
  command.ok(result, (data) => {
13020
13386
  const d = data;
13021
- return `\u5DF2\u767B\u5F55\uFF1A${d.email}\uFF08\u6D4F\u89C8\u5668\u7F51\u9875\u6388\u6743\uFF1B\u51ED\u636E\u5DF2\u5199\u5165 ${ctx.paths.credentialsFile}\uFF0C\u6743\u9650 0600\uFF09`;
13387
+ const replaced = d.replacedEmail !== void 0 ? `\uFF0C\u5DF2\u66FF\u6362\u539F ${d.replacedEmail} \u7684\u51ED\u636E` : "";
13388
+ return `\u5DF2\u767B\u5F55\uFF1A${d.email}\uFF08\u6D4F\u89C8\u5668\u7F51\u9875\u6388\u6743\uFF1B\u51ED\u636E\u6309 server \u5206\u69FD\u4FDD\u5B58\u4E8E ${ctx.paths.credentialsDir}/\uFF0C\u6743\u9650 0600${replaced}\uFF09`;
13022
13389
  });
13023
13390
  });
13024
13391
  }
@@ -13075,17 +13442,17 @@ async function fetchTemplates(server) {
13075
13442
  // packages/cli/src/template-package.ts
13076
13443
  init_auth();
13077
13444
  init_credentials();
13078
- import { mkdir as mkdir7, readFile as readFile10, readdir as readdir3, stat as stat5, writeFile as writeFile5 } from "node:fs/promises";
13079
- import { join as join13 } from "node:path";
13445
+ import { mkdir as mkdir7, readFile as readFile10, readdir as readdir3, stat as stat5, writeFile as writeFile6 } from "node:fs/promises";
13446
+ import { join as join14 } from "node:path";
13080
13447
  function cachedPackagePath(paths, code, version2) {
13081
- return join13(paths.home, "templates", `${code}-${version2}.json`);
13448
+ return join14(paths.home, "templates", `${code}-${version2}.json`);
13082
13449
  }
13083
13450
  async function collectTemplateDir(dir) {
13084
13451
  const files = [];
13085
13452
  async function walk(current, prefix) {
13086
13453
  const entries = await readdir3(current, { withFileTypes: true });
13087
13454
  for (const entry of entries) {
13088
- const full = join13(current, entry.name);
13455
+ const full = join14(current, entry.name);
13089
13456
  const rel = prefix === "" ? entry.name : `${prefix}/${entry.name}`;
13090
13457
  if (entry.isDirectory()) {
13091
13458
  await walk(full, rel);
@@ -13117,8 +13484,8 @@ async function loadCachedPackage(paths, code, version2) {
13117
13484
  return pkg;
13118
13485
  }
13119
13486
  async function saveCachedPackage(paths, pkg) {
13120
- await mkdir7(join13(paths.home, "templates"), { recursive: true });
13121
- await writeFile5(cachedPackagePath(paths, pkg.code, pkg.version), JSON.stringify(pkg), "utf8");
13487
+ await mkdir7(join14(paths.home, "templates"), { recursive: true });
13488
+ await writeFile6(cachedPackagePath(paths, pkg.code, pkg.version), JSON.stringify(pkg), "utf8");
13122
13489
  }
13123
13490
  async function downloadTemplatePackage(server, code) {
13124
13491
  let response;
@@ -13203,7 +13570,7 @@ function packageManifestEntry(pkg) {
13203
13570
  async function assertPublishableTemplate(dir, expectedCode) {
13204
13571
  let info;
13205
13572
  try {
13206
- info = await stat5(join13(dir, "template.json"));
13573
+ info = await stat5(join14(dir, "template.json"));
13207
13574
  } catch {
13208
13575
  throw new CliError(
13209
13576
  "TEMPLATE_NOT_PUBLISHABLE",
@@ -13217,7 +13584,7 @@ async function assertPublishableTemplate(dir, expectedCode) {
13217
13584
  code: expectedCode,
13218
13585
  version: "",
13219
13586
  manifest: {},
13220
- files: [{ path: "template.json", content: await readFile10(join13(dir, "template.json"), "utf8") }]
13587
+ files: [{ path: "template.json", content: await readFile10(join14(dir, "template.json"), "utf8") }]
13221
13588
  });
13222
13589
  if (manifest === null) {
13223
13590
  throw new CliError("TEMPLATE_NOT_PUBLISHABLE", `\u76EE\u5F55 ${dir}/template.json \u4E0D\u662F\u5408\u6CD5 JSON`);
@@ -13341,17 +13708,17 @@ function registerTemplates(program2, ctx) {
13341
13708
  import { resolve as resolve10 } from "node:path";
13342
13709
 
13343
13710
  // packages/cli/src/app-build.ts
13344
- import { mkdir as mkdir11, writeFile as writeFile11 } from "node:fs/promises";
13345
- import { join as join21, resolve as resolve8 } from "node:path";
13711
+ import { mkdir as mkdir11, writeFile as writeFile12 } from "node:fs/promises";
13712
+ import { join as join22, resolve as resolve8 } from "node:path";
13346
13713
 
13347
13714
  // packages/cli/src/app-init.ts
13348
- import { cp, mkdir as mkdir8, readdir as readdir5, stat as stat7, writeFile as writeFile6 } from "node:fs/promises";
13349
- import { dirname as dirname9, join as join15, resolve as resolve7 } from "node:path";
13715
+ import { cp, mkdir as mkdir8, readdir as readdir5, stat as stat7, writeFile as writeFile7 } from "node:fs/promises";
13716
+ import { dirname as dirname8, join as join16, resolve as resolve7 } from "node:path";
13350
13717
 
13351
13718
  // packages/cli/src/app-template.ts
13352
13719
  import { readFileSync as readFileSync3 } from "node:fs";
13353
13720
  import { readdir as readdir4, readFile as readFile11, stat as stat6 } from "node:fs/promises";
13354
- import { dirname as dirname8, join as join14 } from "node:path";
13721
+ import { dirname as dirname7, join as join15 } from "node:path";
13355
13722
  import { fileURLToPath as fileURLToPath3 } from "node:url";
13356
13723
  var TEMPLATE_VAR_ALLOWLIST = {
13357
13724
  "app-desktop": /* @__PURE__ */ new Set(["projectSlug", "appName", "appId", "platformUrl"]),
@@ -13399,22 +13766,22 @@ async function collectRelPaths(dir, base) {
13399
13766
  const entries = await readdir4(dir, { withFileTypes: true });
13400
13767
  const nested = await Promise.all(
13401
13768
  entries.filter((entry) => entry.name !== ".DS_Store" && !TEMPLATE_MANIFEST_FILES.has(entry.name)).toSorted((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0).map((entry) => {
13402
- const abs = join14(dir, entry.name);
13769
+ const abs = join15(dir, entry.name);
13403
13770
  return entry.isDirectory() ? (
13404
13771
  // 递归时 base 必须带上子目录前缀,否则深层文件相对路径会丢目录段
13405
13772
  // (app-mobile 是嵌套目录结构:bridge/gate.mjs、plugins/adep-bridge/...)。
13406
- collectRelPaths(abs, join14(base, entry.name))
13407
- ) : Promise.resolve([join14(base, entry.name).split("\\").join("/")]);
13773
+ collectRelPaths(abs, join15(base, entry.name))
13774
+ ) : Promise.resolve([join15(base, entry.name).split("\\").join("/")]);
13408
13775
  })
13409
13776
  );
13410
13777
  return nested.flat();
13411
13778
  }
13412
13779
  async function findCliPackageRoot() {
13413
- let dir = dirname8(fileURLToPath3(import.meta.url));
13780
+ let dir = dirname7(fileURLToPath3(import.meta.url));
13414
13781
  for (; ; ) {
13415
13782
  let raw;
13416
13783
  try {
13417
- raw = readFileSync3(join14(dir, "package.json"), "utf8");
13784
+ raw = readFileSync3(join15(dir, "package.json"), "utf8");
13418
13785
  } catch {
13419
13786
  raw = "";
13420
13787
  }
@@ -13423,7 +13790,7 @@ async function findCliPackageRoot() {
13423
13790
  if (pkg.name === "@adep/cli") return dir;
13424
13791
  } catch {
13425
13792
  }
13426
- const parent = dirname8(dir);
13793
+ const parent = dirname7(dir);
13427
13794
  if (parent === dir) {
13428
13795
  throw new InitError(
13429
13796
  "SHELL_TEMPLATE_MISSING",
@@ -13434,7 +13801,7 @@ async function findCliPackageRoot() {
13434
13801
  }
13435
13802
  }
13436
13803
  async function appShellTemplateDir(code = "app-desktop") {
13437
- const dir = join14(await findCliPackageRoot(), "templates", code);
13804
+ const dir = join15(await findCliPackageRoot(), "templates", code);
13438
13805
  try {
13439
13806
  await stat6(dir);
13440
13807
  } catch {
@@ -13464,7 +13831,7 @@ async function renderAppShellTemplate(vars, code = "app-desktop") {
13464
13831
  };
13465
13832
  return Promise.all(
13466
13833
  rels.map(async (rel) => {
13467
- const raw = await readFile11(join14(templateDir, rel), "utf8");
13834
+ const raw = await readFile11(join15(templateDir, rel), "utf8");
13468
13835
  const content = raw.replace(/\{\{\s*([A-Za-z0-9_-]+)\s*\}\}/g, (whole, name) => {
13469
13836
  if (!allowed.has(name)) {
13470
13837
  throw new InitError(
@@ -33309,16 +33676,16 @@ async function initAppShell(cwd, input2) {
33309
33676
  await Promise.all(
33310
33677
  files.map(async (file2) => {
33311
33678
  if (file2.path === "adep.app.json") return;
33312
- const target = join15(appPath, file2.path);
33313
- await mkdir8(dirname9(target), { recursive: true });
33314
- await writeFile6(target, file2.content);
33679
+ const target = join16(appPath, file2.path);
33680
+ await mkdir8(dirname8(target), { recursive: true });
33681
+ await writeFile7(target, file2.content);
33315
33682
  })
33316
33683
  );
33317
- await writeFile6(join15(appPath, "adep.app.json"), configJson);
33684
+ await writeFile7(join16(appPath, "adep.app.json"), configJson);
33318
33685
  for (const item of reused) {
33319
- await cp(item.from, join15(appPath, item.to), { recursive: true });
33686
+ await cp(item.from, join16(appPath, item.to), { recursive: true });
33320
33687
  }
33321
- const reusedFiles = (await Promise.all(reused.map((item) => listFiles(join15(appPath, item.to), item.to)))).flat();
33688
+ const reusedFiles = (await Promise.all(reused.map((item) => listFiles(join16(appPath, item.to), item.to)))).flat();
33322
33689
  const written = files.map((file2) => file2.path).filter((path) => path !== "adep.app.json");
33323
33690
  return {
33324
33691
  appPath,
@@ -33330,7 +33697,7 @@ async function resolveXtoolReusedSources() {
33330
33697
  const mobileDir = await appShellTemplateDir("app-mobile");
33331
33698
  const resolved = [];
33332
33699
  for (const item of XTOOL_SHELL_REUSED_FROM_MOBILE) {
33333
- const from = join15(mobileDir, item.from);
33700
+ const from = join16(mobileDir, item.from);
33334
33701
  try {
33335
33702
  await stat7(from);
33336
33703
  } catch {
@@ -33349,7 +33716,7 @@ async function listFiles(path, base) {
33349
33716
  const nested = await Promise.all(
33350
33717
  entries.filter((entry) => entry.name !== ".DS_Store").map((entry) => {
33351
33718
  const rel = `${base}/${entry.name}`;
33352
- return entry.isDirectory() ? listFiles(join15(path, entry.name), rel) : Promise.resolve([rel]);
33719
+ return entry.isDirectory() ? listFiles(join16(path, entry.name), rel) : Promise.resolve([rel]);
33353
33720
  })
33354
33721
  );
33355
33722
  return nested.flat().toSorted();
@@ -33423,9 +33790,9 @@ init_shared_source();
33423
33790
  init_validate();
33424
33791
  init_zip();
33425
33792
  import { createHash as createHash2 } from "node:crypto";
33426
- import { mkdir as mkdir9, mkdtemp, readFile as readFile12, rm as rm3, writeFile as writeFile8 } from "node:fs/promises";
33793
+ import { mkdir as mkdir9, mkdtemp, readFile as readFile12, rm as rm3, writeFile as writeFile9 } from "node:fs/promises";
33427
33794
  import { tmpdir } from "node:os";
33428
- import { dirname as dirname10, join as join16, posix } from "node:path";
33795
+ import { dirname as dirname9, join as join17, posix } from "node:path";
33429
33796
  function computeBundleVersion(manifest) {
33430
33797
  const siteEntries = manifest.contents.filter((content) => content.path.startsWith(SITE_PREFIX)).toSorted((left, right) => compareByCodeUnit(left.path, right.path));
33431
33798
  const fingerprint = createHash2("sha256").update(siteEntries.map((content) => `${content.path}:${content.sha256}`).join("\n")).digest("hex").slice(0, 12);
@@ -33515,14 +33882,14 @@ function verifySiteContents(manifest, entries) {
33515
33882
  }
33516
33883
  }
33517
33884
  async function writeSiteTree(shellDir, site) {
33518
- const targetRoot = join16(shellDir, SHELL_SITE_DIR);
33885
+ const targetRoot = join17(shellDir, SHELL_SITE_DIR);
33519
33886
  await rm3(targetRoot, { recursive: true, force: true });
33520
33887
  await mkdir9(targetRoot, { recursive: true });
33521
33888
  const written = [];
33522
33889
  for (const [rel, bytes] of site) {
33523
- const dest = join16(targetRoot, ...rel.split("/"));
33524
- await mkdir9(dirname10(dest), { recursive: true });
33525
- await writeFile8(dest, bytes);
33890
+ const dest = join17(targetRoot, ...rel.split("/"));
33891
+ await mkdir9(dirname9(dest), { recursive: true });
33892
+ await writeFile9(dest, bytes);
33526
33893
  written.push({ path: `${SHELL_SITE_DIR}/${rel}`, size: bytes.length });
33527
33894
  }
33528
33895
  return written;
@@ -33543,9 +33910,9 @@ async function waitForExport(api, jobId, pollIntervalMs, maxPollAttempts) {
33543
33910
  }
33544
33911
  }
33545
33912
  async function fetchAndInjectSite(input2) {
33546
- const workDir = await mkdtemp(join16(tmpdir(), "adep-app-build-"));
33913
+ const workDir = await mkdtemp(join17(tmpdir(), "adep-app-build-"));
33547
33914
  try {
33548
- const zipPath = join16(workDir, "bundle.zip");
33915
+ const zipPath = join17(workDir, "bundle.zip");
33549
33916
  await input2.api.downloadBundle(input2.jobId, zipPath);
33550
33917
  const entries = zipRead(await readFile12(zipPath));
33551
33918
  const manifest = readManifest(entries);
@@ -33564,10 +33931,10 @@ async function fetchAndInjectSite(input2) {
33564
33931
  }
33565
33932
 
33566
33933
  // packages/cli/src/app-build/shell.ts
33567
- import { readFile as readFile13, writeFile as writeFile9 } from "node:fs/promises";
33568
- import { join as join17 } from "node:path";
33934
+ import { readFile as readFile13, writeFile as writeFile10 } from "node:fs/promises";
33935
+ import { join as join18 } from "node:path";
33569
33936
  async function readShellConfig(shellDir) {
33570
- const configPath = join17(shellDir, "adep.app.json");
33937
+ const configPath = join18(shellDir, "adep.app.json");
33571
33938
  let text;
33572
33939
  try {
33573
33940
  text = await readFile13(configPath, "utf8");
@@ -33592,13 +33959,13 @@ async function readShellConfig(shellDir) {
33592
33959
  }
33593
33960
  async function bindVersion(shellDir, raw, binding) {
33594
33961
  const next = { ...raw, build: binding };
33595
- await writeFile9(join17(shellDir, "adep.app.json"), `${JSON.stringify(next, null, 2)}
33962
+ await writeFile10(join18(shellDir, "adep.app.json"), `${JSON.stringify(next, null, 2)}
33596
33963
  `);
33597
33964
  }
33598
33965
 
33599
33966
  // packages/cli/src/app-build/site.ts
33600
- import { copyFile, readFile as readFile14, writeFile as writeFile10 } from "node:fs/promises";
33601
- import { join as join18 } from "node:path";
33967
+ import { copyFile, readFile as readFile14, writeFile as writeFile11 } from "node:fs/promises";
33968
+ import { join as join19 } from "node:path";
33602
33969
  async function readEntryPage(indexPath) {
33603
33970
  try {
33604
33971
  return await readFile14(indexPath, "utf8");
@@ -33617,8 +33984,8 @@ async function readEntryPage(indexPath) {
33617
33984
  }
33618
33985
  }
33619
33986
  async function injectMobileShellAssets(input2) {
33620
- const siteRoot = join18(input2.shellDir, SHELL_SITE_DIR);
33621
- const indexPath = join18(siteRoot, "index.html");
33987
+ const siteRoot = join19(input2.shellDir, SHELL_SITE_DIR);
33988
+ const indexPath = join19(siteRoot, "index.html");
33622
33989
  const html = await readEntryPage(indexPath);
33623
33990
  const permissionsJson = `${JSON.stringify(
33624
33991
  { schemaVersion: 1, permissions: sortPermissions(input2.permissions) },
@@ -33626,21 +33993,21 @@ async function injectMobileShellAssets(input2) {
33626
33993
  2
33627
33994
  )}
33628
33995
  `;
33629
- await writeFile10(join18(siteRoot, MOBILE_SITE_ASSET_FILES.permissions), permissionsJson);
33996
+ await writeFile11(join19(siteRoot, MOBILE_SITE_ASSET_FILES.permissions), permissionsJson);
33630
33997
  await copyFile(
33631
- join18(input2.shellDir, "web", "adep-bridge.js"),
33632
- join18(siteRoot, MOBILE_SITE_ASSET_FILES.bridge)
33998
+ join19(input2.shellDir, "web", "adep-bridge.js"),
33999
+ join19(siteRoot, MOBILE_SITE_ASSET_FILES.bridge)
33633
34000
  );
33634
34001
  await copyFile(
33635
- join18(input2.shellDir, "adep.app.json"),
33636
- join18(siteRoot, MOBILE_SITE_ASSET_FILES.config)
34002
+ join19(input2.shellDir, "adep.app.json"),
34003
+ join19(siteRoot, MOBILE_SITE_ASSET_FILES.config)
33637
34004
  );
33638
34005
  if (html.includes("adep-bridge.js")) return;
33639
34006
  const tag = '<script src="/adep-bridge.js"></script>';
33640
34007
  const next = html.includes("</head>") ? html.replace("</head>", `${tag}
33641
34008
  </head>`) : `${tag}
33642
34009
  ${html}`;
33643
- await writeFile10(indexPath, next);
34010
+ await writeFile11(indexPath, next);
33644
34011
  }
33645
34012
 
33646
34013
  // packages/cli/src/app-build/toolchain.ts
@@ -33648,7 +34015,7 @@ init_config();
33648
34015
  import { spawn as spawn2 } from "node:child_process";
33649
34016
  import { closeSync, openSync } from "node:fs";
33650
34017
  import { copyFile as copyFile2, mkdir as mkdir10, readdir as readdir6 } from "node:fs/promises";
33651
- import { basename as basename2, join as join19 } from "node:path";
34018
+ import { basename as basename2, join as join20 } from "node:path";
33652
34019
  function platformArgs(platform) {
33653
34020
  if (platform === "darwin") return ["--mac"];
33654
34021
  if (platform === "win32") return ["--win"];
@@ -33656,7 +34023,7 @@ function platformArgs(platform) {
33656
34023
  }
33657
34024
  function resolvePackagerBinary(shellDir) {
33658
34025
  const name = process.platform === "win32" ? "electron-builder.cmd" : "electron-builder";
33659
- return join19(shellDir, "node_modules", ".bin", name);
34026
+ return join20(shellDir, "node_modules", ".bin", name);
33660
34027
  }
33661
34028
  function missingDepsError(shellDir) {
33662
34029
  return new InitError(
@@ -33668,17 +34035,17 @@ function missingMobileDepsError(shellDir, platform) {
33668
34035
  if (platform === "ios") {
33669
34036
  return new InitError(
33670
34037
  "APP_SHELL_DEPS_MISSING",
33671
- `\u672A\u627E\u5230 iOS \u539F\u751F\u5DE5\u7A0B\uFF08${join19(shellDir, "ios", "App")}\uFF09\uFF1A\u8BF7\u5148\u5728 ${shellDir} \u6267\u884C npx cap add ios && npx cap sync`
34038
+ `\u672A\u627E\u5230 iOS \u539F\u751F\u5DE5\u7A0B\uFF08${join20(shellDir, "ios", "App")}\uFF09\uFF1A\u8BF7\u5148\u5728 ${shellDir} \u6267\u884C npx cap add ios && npx cap sync`
33672
34039
  );
33673
34040
  }
33674
34041
  return new InitError(
33675
34042
  "APP_SHELL_DEPS_MISSING",
33676
- `\u672A\u627E\u5230 Android \u539F\u751F\u5DE5\u7A0B\uFF08${join19(shellDir, "android", "gradlew")}\uFF09\uFF1A\u8BF7\u5148\u5728 ${shellDir} \u6267\u884C npx cap add android && npx cap sync`
34043
+ `\u672A\u627E\u5230 Android \u539F\u751F\u5DE5\u7A0B\uFF08${join20(shellDir, "android", "gradlew")}\uFF09\uFF1A\u8BF7\u5148\u5728 ${shellDir} \u6267\u884C npx cap add android && npx cap sync`
33677
34044
  );
33678
34045
  }
33679
34046
  function resolveCapBinary(shellDir) {
33680
34047
  const name = process.platform === "win32" ? "cap.cmd" : "cap";
33681
- return join19(shellDir, "node_modules", ".bin", name);
34048
+ return join20(shellDir, "node_modules", ".bin", name);
33682
34049
  }
33683
34050
  async function syncCapacitorAssets(input2) {
33684
34051
  const capBin = resolveCapBinary(input2.shellDir);
@@ -33701,11 +34068,11 @@ async function assertShellPackagerReady(shellDir, platform, prepareOnly, toolcha
33701
34068
  return;
33702
34069
  }
33703
34070
  if (platform === "ios") {
33704
- if (!await pathExists(join19(shellDir, "ios", "App"))) {
33705
- if (await pathExists(join19(shellDir, "xtool.yml"))) {
34071
+ if (!await pathExists(join20(shellDir, "ios", "App"))) {
34072
+ if (await pathExists(join20(shellDir, "xtool.yml"))) {
33706
34073
  throw new InitError(
33707
34074
  "APP_SHELL_DEPS_MISSING",
33708
- `\u672A\u627E\u5230 Capacitor \u7684 iOS \u539F\u751F\u5DE5\u7A0B\uFF08${join19(shellDir, "ios", "App")}\uFF09\uFF1B\u4F46\u68C0\u6D4B\u5230\u8BE5\u76EE\u5F55\u662F xtool \u58F3\u5DE5\u7A0B\uFF08\u6709 xtool.yml\uFF09\u2014\u2014\u672C\u6B21\u8BF7\u52A0 --toolchain xtool`
34075
+ `\u672A\u627E\u5230 Capacitor \u7684 iOS \u539F\u751F\u5DE5\u7A0B\uFF08${join20(shellDir, "ios", "App")}\uFF09\uFF1B\u4F46\u68C0\u6D4B\u5230\u8BE5\u76EE\u5F55\u662F xtool \u58F3\u5DE5\u7A0B\uFF08\u6709 xtool.yml\uFF09\u2014\u2014\u672C\u6B21\u8BF7\u52A0 --toolchain xtool`
33709
34076
  );
33710
34077
  }
33711
34078
  throw missingMobileDepsError(shellDir, "ios");
@@ -33721,16 +34088,16 @@ async function assertShellPackagerReady(shellDir, platform, prepareOnly, toolcha
33721
34088
  if (!await pathExists(resolvePackagerBinary(shellDir))) throw missingDepsError(shellDir);
33722
34089
  }
33723
34090
  async function assertXtoolShellReady(shellDir) {
33724
- if (!await pathExists(join19(shellDir, "xtool.yml")) || !await pathExists(join19(shellDir, "Package.swift"))) {
34091
+ if (!await pathExists(join20(shellDir, "xtool.yml")) || !await pathExists(join20(shellDir, "Package.swift"))) {
33725
34092
  throw new InitError(
33726
34093
  "APP_SHELL_DEPS_MISSING",
33727
- `\u672A\u627E\u5230 xtool \u58F3\u5DE5\u7A0B\uFF08\u9700\u8981 ${join19(shellDir, "xtool.yml")} \u4E0E ${join19(shellDir, "Package.swift")}\uFF09\uFF1A\u8BF7\u7528 adep app init --platform mobile --toolchain xtool \u751F\u6210`
34094
+ `\u672A\u627E\u5230 xtool \u58F3\u5DE5\u7A0B\uFF08\u9700\u8981 ${join20(shellDir, "xtool.yml")} \u4E0E ${join20(shellDir, "Package.swift")}\uFF09\uFF1A\u8BF7\u7528 adep app init --platform mobile --toolchain xtool \u751F\u6210`
33728
34095
  );
33729
34096
  }
33730
- if (!await pathExists(join19(shellDir, "plugins", "adep-bridge", "Package.swift"))) {
34097
+ if (!await pathExists(join20(shellDir, "plugins", "adep-bridge", "Package.swift"))) {
33731
34098
  throw new InitError(
33732
34099
  "APP_SHELL_DEPS_MISSING",
33733
- `xtool \u58F3\u7F3A\u5C11\u539F\u751F\u6865\u63D2\u4EF6\u6E90\u7801\uFF08${join19(shellDir, "plugins", "adep-bridge", "Package.swift")}\uFF09\uFF1A\u58F3\u7684 Package.swift \u4EE5 .package(path:) \u786C\u4F9D\u8D56\u5B83\uFF0C\u7F3A\u5931\u65F6**\u89E3\u6790\u6E05\u5355\u5373\u5931\u8D25**\uFF08\u4E0D\u662F\u8FD0\u884C\u671F\u5C11\u4E2A\u529F\u80FD\uFF09\u3002\u8BF7\u91CD\u65B0 adep app init --platform mobile --toolchain xtool\uFF0C\u6216\u624B\u5DE5\u8865\u8BE5\u76EE\u5F55`
34100
+ `xtool \u58F3\u7F3A\u5C11\u539F\u751F\u6865\u63D2\u4EF6\u6E90\u7801\uFF08${join20(shellDir, "plugins", "adep-bridge", "Package.swift")}\uFF09\uFF1A\u58F3\u7684 Package.swift \u4EE5 .package(path:) \u786C\u4F9D\u8D56\u5B83\uFF0C\u7F3A\u5931\u65F6**\u89E3\u6790\u6E05\u5355\u5373\u5931\u8D25**\uFF08\u4E0D\u662F\u8FD0\u884C\u671F\u5C11\u4E2A\u529F\u80FD\uFF09\u3002\u8BF7\u91CD\u65B0 adep app init --platform mobile --toolchain xtool\uFF0C\u6216\u624B\u5DE5\u8865\u8BE5\u76EE\u5F55`
33734
34101
  );
33735
34102
  }
33736
34103
  }
@@ -33757,8 +34124,8 @@ function probeCommand(command, args) {
33757
34124
  });
33758
34125
  }
33759
34126
  function xcodebuildArgs(shellDir, outDir) {
33760
- const appDir = join19(shellDir, "ios", "App");
33761
- const project2 = join19(appDir, "App.xcodeproj");
34127
+ const appDir = join20(shellDir, "ios", "App");
34128
+ const project2 = join20(appDir, "App.xcodeproj");
33762
34129
  const args = [
33763
34130
  // 有 workspace(pod install 后)用 workspace;否则退到 xcodeproj(无插件的最小工程)。
33764
34131
  "-project",
@@ -33769,7 +34136,7 @@ function xcodebuildArgs(shellDir, outDir) {
33769
34136
  "Release",
33770
34137
  "archive",
33771
34138
  "-archivePath",
33772
- join19(outDir, `${basename2(shellDir)}.xcarchive`),
34139
+ join20(outDir, `${basename2(shellDir)}.xcarchive`),
33773
34140
  // unsigned:平台不出具任何签名(PRD §2.11.6「平台不出具签名」)。
33774
34141
  // 显式 CODE_SIGNING_ALLOWED=NO——不带任何签名身份(CODE_SIGN_IDENTITY / PROVISIONING_PROFILE)。
33775
34142
  "CODE_SIGNING_ALLOWED=NO",
@@ -33778,8 +34145,8 @@ function xcodebuildArgs(shellDir, outDir) {
33778
34145
  return args;
33779
34146
  }
33780
34147
  async function runXcodebuild(input2) {
33781
- const workspace = join19(input2.shellDir, "ios", "App", "App.xcworkspace");
33782
- const project2 = join19(input2.shellDir, "ios", "App", "App.xcodeproj");
34148
+ const workspace = join20(input2.shellDir, "ios", "App", "App.xcworkspace");
34149
+ const project2 = join20(input2.shellDir, "ios", "App", "App.xcodeproj");
33783
34150
  if (!await pathExists(workspace) && !await pathExists(project2)) {
33784
34151
  throw missingMobileDepsError(input2.shellDir, "ios");
33785
34152
  }
@@ -33796,7 +34163,7 @@ async function assertUnsignedIosArchive(archivePath) {
33796
34163
  if (!await pathExists(archivePath)) {
33797
34164
  throw new InitError("APP_ARCHIVE_INCOMPLETE", `iOS archive \u4E0D\u5B58\u5728\uFF1A${archivePath}`);
33798
34165
  }
33799
- const applicationsDir = join19(archivePath, "Products", "Applications");
34166
+ const applicationsDir = join20(archivePath, "Products", "Applications");
33800
34167
  let hasAppBundle = false;
33801
34168
  try {
33802
34169
  const entries = await readdir6(applicationsDir, { withFileTypes: true });
@@ -33826,7 +34193,7 @@ async function assertUnsignedIosArchive(archivePath) {
33826
34193
  continue;
33827
34194
  }
33828
34195
  if (entry.isDirectory()) {
33829
- await walk(join19(dir, entry.name), childRel, depth + 1);
34196
+ await walk(join20(dir, entry.name), childRel, depth + 1);
33830
34197
  }
33831
34198
  }
33832
34199
  };
@@ -33839,10 +34206,10 @@ async function assertUnsignedIosArchive(archivePath) {
33839
34206
  }
33840
34207
  }
33841
34208
  function resolveGradlew(shellDir) {
33842
- return process.platform === "win32" ? join19(shellDir, "android", "gradlew.bat") : join19(shellDir, "android", "gradlew");
34209
+ return process.platform === "win32" ? join20(shellDir, "android", "gradlew.bat") : join20(shellDir, "android", "gradlew");
33843
34210
  }
33844
34211
  async function copyGradleApkToOutDir(shellDir, outDir) {
33845
- const outputsRoot = join19(shellDir, "android", "app", "build", "outputs", "apk");
34212
+ const outputsRoot = join20(shellDir, "android", "app", "build", "outputs", "apk");
33846
34213
  const copied = [];
33847
34214
  const walk = async (dir, depth) => {
33848
34215
  if (depth > 2) return;
@@ -33853,9 +34220,9 @@ async function copyGradleApkToOutDir(shellDir, outDir) {
33853
34220
  return;
33854
34221
  }
33855
34222
  for (const entry of entries) {
33856
- const full = join19(dir, entry.name);
34223
+ const full = join20(dir, entry.name);
33857
34224
  if (entry.isFile() && entry.name.endsWith(".apk")) {
33858
- await copyFile2(full, join19(outDir, entry.name));
34225
+ await copyFile2(full, join20(outDir, entry.name));
33859
34226
  copied.push(entry.name);
33860
34227
  continue;
33861
34228
  }
@@ -33871,7 +34238,7 @@ async function runGradle(input2) {
33871
34238
  const gradlew = resolveGradlew(input2.shellDir);
33872
34239
  if (!await pathExists(gradlew)) throw missingMobileDepsError(input2.shellDir, "android");
33873
34240
  if (process.platform === "win32") {
33874
- await spawnChild(join19(input2.shellDir, "android"), "cmd.exe", [
34241
+ await spawnChild(join20(input2.shellDir, "android"), "cmd.exe", [
33875
34242
  "/d",
33876
34243
  "/s",
33877
34244
  "/c",
@@ -33879,14 +34246,14 @@ async function runGradle(input2) {
33879
34246
  "assembleRelease"
33880
34247
  ]);
33881
34248
  } else {
33882
- await spawnChild(join19(input2.shellDir, "android"), gradlew, ["assembleRelease"]);
34249
+ await spawnChild(join20(input2.shellDir, "android"), gradlew, ["assembleRelease"]);
33883
34250
  }
33884
34251
  await mkdir10(input2.outDir, { recursive: true });
33885
34252
  const copied = await copyGradleApkToOutDir(input2.shellDir, input2.outDir);
33886
34253
  if (copied.length === 0) {
33887
34254
  throw new InitError(
33888
34255
  "APP_ARTIFACT_MISSING",
33889
- `gradle \u5DF2\u6210\u529F\u4F46 ${join19(input2.shellDir, "android", "app", "build", "outputs", "apk")} \u4E0B\u6CA1\u6709 .apk\uFF1AassembleRelease \u53EF\u80FD\u88AB\u964D\u7EA7\u6210\u522B\u7684\u53D8\u4F53\uFF0C\u8BF7\u68C0\u67E5 android \u5DE5\u7A0B\u7684\u6784\u5EFA\u53D8\u4F53\u914D\u7F6E`
34256
+ `gradle \u5DF2\u6210\u529F\u4F46 ${join20(input2.shellDir, "android", "app", "build", "outputs", "apk")} \u4E0B\u6CA1\u6709 .apk\uFF1AassembleRelease \u53EF\u80FD\u88AB\u964D\u7EA7\u6210\u522B\u7684\u53D8\u4F53\uFF0C\u8BF7\u68C0\u67E5 android \u5DE5\u7A0B\u7684\u6784\u5EFA\u53D8\u4F53\u914D\u7F6E`
33890
34257
  );
33891
34258
  }
33892
34259
  }
@@ -33955,7 +34322,7 @@ async function runElectronBuilder(input2) {
33955
34322
 
33956
34323
  // packages/cli/src/app-build/artifacts.ts
33957
34324
  import { readFile as readFile15, readdir as readdir7 } from "node:fs/promises";
33958
- import { join as join20, relative as relative2 } from "node:path";
34325
+ import { join as join21, relative as relative2 } from "node:path";
33959
34326
  function isArtifact(name, isDirectory, platform, toolchain) {
33960
34327
  if (toolchain === "xtool") return !isDirectory && name.endsWith(".ipa");
33961
34328
  if (platform === "ios") return isDirectory && name.endsWith(".xcarchive");
@@ -33968,7 +34335,7 @@ function isArtifact(name, isDirectory, platform, toolchain) {
33968
34335
  }
33969
34336
  async function findArtifacts(shellDir, outDir, platform, toolchain = "capacitor") {
33970
34337
  const found = [];
33971
- const scanRoot = toolchain === "xtool" ? join20(shellDir, XTOOL_ARTIFACT_DIR) : outDir;
34338
+ const scanRoot = toolchain === "xtool" ? join21(shellDir, XTOOL_ARTIFACT_DIR) : outDir;
33972
34339
  const walk = async (dir, depth) => {
33973
34340
  if (depth > 3) return;
33974
34341
  let entries;
@@ -33978,7 +34345,7 @@ async function findArtifacts(shellDir, outDir, platform, toolchain = "capacitor"
33978
34345
  return;
33979
34346
  }
33980
34347
  for (const entry of entries) {
33981
- const full = join20(dir, entry.name);
34348
+ const full = join21(dir, entry.name);
33982
34349
  if (isArtifact(entry.name, entry.isDirectory(), platform, toolchain)) {
33983
34350
  found.push(relative2(shellDir, full).split(/[\\/]/u).join("/"));
33984
34351
  continue;
@@ -34029,7 +34396,7 @@ function linuxTargetSkips(declared, artifacts) {
34029
34396
  }
34030
34397
  async function readLinuxDeclaredTargets(shellDir) {
34031
34398
  try {
34032
- const raw = await readFile15(join20(shellDir, "package.json"), "utf8");
34399
+ const raw = await readFile15(join21(shellDir, "package.json"), "utf8");
34033
34400
  const parsed = JSON.parse(raw);
34034
34401
  const target = parsed.build?.linux?.target;
34035
34402
  if (typeof target === "string") return [target];
@@ -34049,7 +34416,7 @@ async function buildDesktopApp(options, deps) {
34049
34416
  const toolchain = normalizeToolchain(options.toolchain);
34050
34417
  const prepareOnly = options.prepareOnly === true;
34051
34418
  const now = deps.now ?? (() => /* @__PURE__ */ new Date());
34052
- const outDir = join21(shellDir, SHELL_OUT_DIR);
34419
+ const outDir = join22(shellDir, SHELL_OUT_DIR);
34053
34420
  if (isMobilePlatform(platform) && target === "dir") {
34054
34421
  throw new InitError(
34055
34422
  "INVALID_TARGET",
@@ -34121,7 +34488,7 @@ async function buildDesktopApp(options, deps) {
34121
34488
  });
34122
34489
  artifacts = await findArtifacts(shellDir, outDir, platform, toolchain);
34123
34490
  if (artifacts.length === 0) {
34124
- const scanned = toolchain === "xtool" ? join21(shellDir, XTOOL_ARTIFACT_DIR) : outDir;
34491
+ const scanned = toolchain === "xtool" ? join22(shellDir, XTOOL_ARTIFACT_DIR) : outDir;
34125
34492
  const hint = toolchain === "xtool" ? "`xtool dev build --ipa` \u7684\u4EA7\u7269\u5E94\u5728 xtool/<product>.ipa\uFF08\u65E0\u8F93\u51FA\u4F4D\u53C2\u6570\uFF09\uFF1B\u8BF7\u68C0\u67E5 xtool \u662F\u5426\u771F\u7684\u8DD1\u5230\u4E86\u6253\u5305\uFF08\u800C\u4E0D\u662F\u5728\u7F16\u8BD1\u9636\u6BB5\u9000\u51FA\uFF09" : "\u8BF7\u68C0\u67E5\u58F3\u5DE5\u7A0B\u7684\u539F\u751F\u5DE5\u7A0B / build \u914D\u7F6E";
34126
34493
  throw new InitError(
34127
34494
  "APP_ARTIFACT_MISSING",
@@ -34130,7 +34497,7 @@ async function buildDesktopApp(options, deps) {
34130
34497
  }
34131
34498
  if (platform === "ios" && toolchain === "capacitor") {
34132
34499
  for (const artifact of artifacts) {
34133
- await assertUnsignedIosArchive(join21(shellDir, artifact));
34500
+ await assertUnsignedIosArchive(join22(shellDir, artifact));
34134
34501
  }
34135
34502
  }
34136
34503
  if (platform === "linux" && target === "installer") {
@@ -34164,8 +34531,8 @@ async function buildDesktopApp(options, deps) {
34164
34531
  warnings
34165
34532
  };
34166
34533
  await mkdir11(outDir, { recursive: true });
34167
- const reportPath = join21(outDir, REPORT_FILE);
34168
- await writeFile11(reportPath, `${JSON.stringify(report, null, 2)}
34534
+ const reportPath = join22(outDir, REPORT_FILE);
34535
+ await writeFile12(reportPath, `${JSON.stringify(report, null, 2)}
34169
34536
  `);
34170
34537
  return {
34171
34538
  appPath: shellDir,
@@ -34210,16 +34577,16 @@ async function createAppBuildApi(paths, cwd) {
34210
34577
 
34211
34578
  // packages/cli/src/app-doctor.ts
34212
34579
  import { readFile as readFile17, stat as stat9 } from "node:fs/promises";
34213
- import { join as join23 } from "node:path";
34580
+ import { join as join24 } from "node:path";
34214
34581
 
34215
34582
  // packages/cli/src/app-offline-build.ts
34216
34583
  init_zip();
34217
34584
  init_auth();
34218
34585
  import { createHash as createHash3 } from "node:crypto";
34219
- import { access, copyFile as copyFile3, mkdir as mkdir12, mkdtemp as mkdtemp2, readFile as readFile16, rm as rm4, writeFile as writeFile12 } from "node:fs/promises";
34586
+ import { access, copyFile as copyFile3, mkdir as mkdir12, mkdtemp as mkdtemp2, readFile as readFile16, rm as rm4, writeFile as writeFile13 } from "node:fs/promises";
34220
34587
  import { spawn as spawn3 } from "node:child_process";
34221
34588
  import { tmpdir as tmpdir2 } from "node:os";
34222
- import { dirname as dirname11, join as join22, posix as posix2, resolve as resolve9 } from "node:path";
34589
+ import { dirname as dirname10, join as join23, posix as posix2, resolve as resolve9 } from "node:path";
34223
34590
  init_client();
34224
34591
  var SHELL_OFFLINE_DIR = "app/offline";
34225
34592
  var SHELL_SITE_OFFLINE_DIR = "app/site/offline";
@@ -34261,15 +34628,15 @@ function collectOfflineEntries(entries) {
34261
34628
  return collected;
34262
34629
  }
34263
34630
  async function writeOfflineTree(shellDir, collected, targetRel) {
34264
- const targetRoot = join22(shellDir, targetRel);
34631
+ const targetRoot = join23(shellDir, targetRel);
34265
34632
  await rm4(targetRoot, { recursive: true, force: true });
34266
34633
  await mkdir12(targetRoot, { recursive: true });
34267
34634
  const written = [];
34268
34635
  for (const [rel, bytes] of collected) {
34269
34636
  if (rel.length === 0 || rel.endsWith("/")) continue;
34270
- const dest = join22(targetRoot, ...rel.split("/"));
34271
- await mkdir12(dirname11(dest), { recursive: true });
34272
- await writeFile12(dest, bytes);
34637
+ const dest = join23(targetRoot, ...rel.split("/"));
34638
+ await mkdir12(dirname10(dest), { recursive: true });
34639
+ await writeFile13(dest, bytes);
34273
34640
  written.push({ path: `${targetRel}/${rel}`, size: bytes.length });
34274
34641
  }
34275
34642
  return written;
@@ -34363,14 +34730,14 @@ async function buildOfflineApp(options, deps) {
34363
34730
  );
34364
34731
  }
34365
34732
  if (mobileOffline) {
34366
- const entry = join22(shellDir, "app", "site", "index.html");
34733
+ const entry = join23(shellDir, "app", "site", "index.html");
34367
34734
  if (!await fileExists(entry)) {
34368
34735
  throw new InitError(
34369
34736
  "APP_SITE_MISSING",
34370
34737
  `\u79BB\u7EBF\u5305\u7F3A\u9875\u9762\u4EA7\u7269\uFF1A${entry} \u4E0D\u5B58\u5728\u3002\u8BF7\u5148\u6267\u884C ` + (toolchain === "xtool" ? "`adep app build --platform ios --toolchain xtool`\uFF08\u62C9\u53D6\u9875\u9762\u4EA7\u7269\u5E76\u6CE8\u5165\u9875\u9762\u6865 / \u58F3\u914D\u7F6E\uFF09\uFF0C" : "`adep app build --platform android`\uFF08\u62C9\u53D6\u9875\u9762\u4EA7\u7269\u5E76\u6CE8\u5165\u9875\u9762\u6865 / \u58F3\u914D\u7F6E\uFF09\uFF0C") + "\u518D\u6267\u884C\u79BB\u7EBF\u6784\u5EFA\u2014\u2014\u79BB\u7EBF\u6784\u5EFA\u53EA\u8FFD\u52A0 site/offline/ \u5B50\u6811\uFF0C\u4E0D\u4EA7\u751F\u9875\u9762\u672C\u4F53"
34371
34738
  );
34372
34739
  }
34373
- const loaderSource = join22(shellDir, MOBILE_OFFLINE_LOADER.source);
34740
+ const loaderSource = join23(shellDir, MOBILE_OFFLINE_LOADER.source);
34374
34741
  if (!await fileExists(loaderSource)) {
34375
34742
  throw new InitError(
34376
34743
  "OFFLINE_LOADER_MISSING",
@@ -34395,9 +34762,9 @@ ${finished.error ?? "\u670D\u52A1\u7AEF\u672A\u63D0\u4F9B\u539F\u56E0"}
34395
34762
  \uFF08\u8FD9\u4E9B\u51FD\u6570\u4E0D\u53EF\u79FB\u690D\u5230\u8BBE\u5907\u7AEF\uFF1B\u4ECE\u6253\u5305\u914D\u7F6E\u7684\u79BB\u7EBF\u767D\u540D\u5355\u79FB\u9664\u540E\u91CD\u65B0\u4FDD\u5B58\uFF0C\u5373\u53EF\u7EE7\u7EED\u6784\u5EFA\uFF09`
34396
34763
  );
34397
34764
  }
34398
- const workDir = await mkdtemp2(join22(tmpdir2(), "adep-app-offline-build-"));
34765
+ const workDir = await mkdtemp2(join23(tmpdir2(), "adep-app-offline-build-"));
34399
34766
  try {
34400
- const bundlePath = join22(workDir, "bundle.adepack");
34767
+ const bundlePath = join23(workDir, "bundle.adepack");
34401
34768
  await deps.api.downloadBundle(project2.id, finished.id, bundlePath);
34402
34769
  const entries = zipRead(await readFile16(bundlePath));
34403
34770
  const manifest = readManifest(entries, { allowOfflinePortZero: true });
@@ -34409,8 +34776,8 @@ ${finished.error ?? "\u670D\u52A1\u7AEF\u672A\u63D0\u4F9B\u539F\u56E0"}
34409
34776
  const permissions = sortPermissions(await deps.api.getPackagingPermissions(project2.id));
34410
34777
  await injectMobileShellAssets({ shellDir, permissions });
34411
34778
  await copyFile3(
34412
- join22(shellDir, MOBILE_OFFLINE_LOADER.source),
34413
- join22(shellDir, MOBILE_OFFLINE_LOADER.dest)
34779
+ join23(shellDir, MOBILE_OFFLINE_LOADER.source),
34780
+ join23(shellDir, MOBILE_OFFLINE_LOADER.dest)
34414
34781
  );
34415
34782
  }
34416
34783
  const builtAt = now().toISOString();
@@ -34426,12 +34793,12 @@ ${finished.error ?? "\u670D\u52A1\u7AEF\u672A\u63D0\u4F9B\u539F\u56E0"}
34426
34793
  platform: "ios",
34427
34794
  target: "installer",
34428
34795
  toolchain: "xtool",
34429
- outDir: join22(shellDir, "dist")
34796
+ outDir: join23(shellDir, "dist")
34430
34797
  });
34431
- artifacts = await findArtifacts(shellDir, join22(shellDir, "dist"), "ios", "xtool");
34798
+ artifacts = await findArtifacts(shellDir, join23(shellDir, "dist"), "ios", "xtool");
34432
34799
  } else if (androidOffline) {
34433
34800
  await (deps.runCapSync ?? syncCapacitorAssets)({ shellDir, platform: "android" });
34434
- const outDir2 = join22(shellDir, "dist");
34801
+ const outDir2 = join23(shellDir, "dist");
34435
34802
  await mkdir12(outDir2, { recursive: true });
34436
34803
  await runner({
34437
34804
  shellDir,
@@ -34443,7 +34810,7 @@ ${finished.error ?? "\u670D\u52A1\u7AEF\u672A\u63D0\u4F9B\u539F\u56E0"}
34443
34810
  artifacts = await findArtifacts(shellDir, outDir2, "android");
34444
34811
  } else {
34445
34812
  const platform = resolveOfflinePlatform();
34446
- const outDir2 = join22(shellDir, "dist");
34813
+ const outDir2 = join23(shellDir, "dist");
34447
34814
  await mkdir12(outDir2, { recursive: true });
34448
34815
  await runner({
34449
34816
  shellDir,
@@ -34457,7 +34824,7 @@ ${finished.error ?? "\u670D\u52A1\u7AEF\u672A\u63D0\u4F9B\u539F\u56E0"}
34457
34824
  if (artifacts.length === 0) {
34458
34825
  throw new InitError(
34459
34826
  "APP_ARTIFACT_MISSING",
34460
- toolchain === "xtool" ? `\u6253\u5305\u5668\u5DF2\u6267\u884C\u4F46 ${join22(shellDir, "xtool")} \u4E0B\u6CA1\u6709 ios \u4EA7\u7269\uFF1A\`xtool dev build --ipa\` \u7684\u4EA7\u7269\u5E94\u5728 xtool/<product>.ipa\uFF08\u65E0\u8F93\u51FA\u4F4D\u53C2\u6570\uFF09\uFF1B\u8BF7\u68C0\u67E5 xtool \u662F\u5426\u771F\u7684\u8DD1\u5230\u4E86\u6253\u5305\uFF08\u800C\u4E0D\u662F\u5728\u7F16\u8BD1\u9636\u6BB5\u9000\u51FA\uFF09` : androidOffline ? `\u6253\u5305\u5668\u5DF2\u6267\u884C\u4F46 ${join22(shellDir, "dist")} \u4E0B\u6CA1\u6709 android \u4EA7\u7269\uFF1Agradle assembleRelease \u7684 APK \u5E94\u5DF2\u88AB\u590D\u5236\u8FDB dist/\uFF08\u89C1 copyGradleApkToOutDir\uFF09\uFF1B\u8BF7\u68C0\u67E5 android \u5DE5\u7A0B\u7684\u6784\u5EFA\u53D8\u4F53\u914D\u7F6E` : `electron-builder \u5DF2\u6267\u884C\u4F46 ${join22(shellDir, "dist")} \u4E0B\u6CA1\u6709\u4EA7\u7269\uFF1A\u8BF7\u68C0\u67E5\u58F3\u5DE5\u7A0B build \u914D\u7F6E\u7684 target`
34827
+ toolchain === "xtool" ? `\u6253\u5305\u5668\u5DF2\u6267\u884C\u4F46 ${join23(shellDir, "xtool")} \u4E0B\u6CA1\u6709 ios \u4EA7\u7269\uFF1A\`xtool dev build --ipa\` \u7684\u4EA7\u7269\u5E94\u5728 xtool/<product>.ipa\uFF08\u65E0\u8F93\u51FA\u4F4D\u53C2\u6570\uFF09\uFF1B\u8BF7\u68C0\u67E5 xtool \u662F\u5426\u771F\u7684\u8DD1\u5230\u4E86\u6253\u5305\uFF08\u800C\u4E0D\u662F\u5728\u7F16\u8BD1\u9636\u6BB5\u9000\u51FA\uFF09` : androidOffline ? `\u6253\u5305\u5668\u5DF2\u6267\u884C\u4F46 ${join23(shellDir, "dist")} \u4E0B\u6CA1\u6709 android \u4EA7\u7269\uFF1Agradle assembleRelease \u7684 APK \u5E94\u5DF2\u88AB\u590D\u5236\u8FDB dist/\uFF08\u89C1 copyGradleApkToOutDir\uFF09\uFF1B\u8BF7\u68C0\u67E5 android \u5DE5\u7A0B\u7684\u6784\u5EFA\u53D8\u4F53\u914D\u7F6E` : `electron-builder \u5DF2\u6267\u884C\u4F46 ${join23(shellDir, "dist")} \u4E0B\u6CA1\u6709\u4EA7\u7269\uFF1A\u8BF7\u68C0\u67E5\u58F3\u5DE5\u7A0B build \u914D\u7F6E\u7684 target`
34461
34828
  );
34462
34829
  }
34463
34830
  }
@@ -34485,10 +34852,10 @@ ${finished.error ?? "\u670D\u52A1\u7AEF\u672A\u63D0\u4F9B\u539F\u56E0"}
34485
34852
  },
34486
34853
  artifacts
34487
34854
  };
34488
- const outDir = join22(shellDir, "dist");
34855
+ const outDir = join23(shellDir, "dist");
34489
34856
  await mkdir12(outDir, { recursive: true });
34490
- const reportPath = join22(outDir, "build-report.json");
34491
- await writeFile12(reportPath, `${JSON.stringify(report, null, 2)}
34857
+ const reportPath = join23(outDir, "build-report.json");
34858
+ await writeFile13(reportPath, `${JSON.stringify(report, null, 2)}
34492
34859
  `);
34493
34860
  return {
34494
34861
  appPath: shellDir,
@@ -34549,7 +34916,7 @@ async function createAppOfflineBuildApi(paths, cwd) {
34549
34916
  }
34550
34917
  const response = await client.download(downloadUrl, "APP_OFFLINE_BUILD_DOWNLOAD_FAILED");
34551
34918
  const bytes = Buffer.from(await response.arrayBuffer());
34552
- await writeFile12(outputPath, bytes);
34919
+ await writeFile13(outputPath, bytes);
34553
34920
  return { path: outputPath, size: bytes.length };
34554
34921
  },
34555
34922
  // 与在线构建 `AppBuildDeps.getPackagingPermissions` 同一端点同一读法(app-build.ts 同款)。
@@ -34587,7 +34954,7 @@ async function pathExists2(path) {
34587
34954
  }
34588
34955
  async function missingEntries(root, rels) {
34589
34956
  const probed = await Promise.all(
34590
- rels.map(async (rel) => ({ rel, exists: await pathExists2(join23(root, ...rel.split("/"))) }))
34957
+ rels.map(async (rel) => ({ rel, exists: await pathExists2(join24(root, ...rel.split("/"))) }))
34591
34958
  );
34592
34959
  return probed.filter((entry) => !entry.exists).map((entry) => entry.rel);
34593
34960
  }
@@ -34601,10 +34968,10 @@ async function resolveTargets(shellDir, template, platform) {
34601
34968
  if (template === "app-mobile-xtool") return [{ platform: "ios", toolchain: "xtool" }];
34602
34969
  if (template === "app-mobile") {
34603
34970
  const targets = [];
34604
- if (await pathExists2(join23(shellDir, "ios", "App"))) {
34971
+ if (await pathExists2(join24(shellDir, "ios", "App"))) {
34605
34972
  targets.push({ platform: "ios", toolchain: "capacitor" });
34606
34973
  }
34607
- if (await pathExists2(join23(shellDir, "android", "gradlew"))) {
34974
+ if (await pathExists2(join24(shellDir, "android", "gradlew"))) {
34608
34975
  targets.push({ platform: "android", toolchain: "capacitor" });
34609
34976
  }
34610
34977
  return targets;
@@ -34612,7 +34979,7 @@ async function resolveTargets(shellDir, template, platform) {
34612
34979
  return [];
34613
34980
  }
34614
34981
  async function checkConfigDrift(shellDir, config2) {
34615
- const siteConfigPath = join23(shellDir, SHELL_SITE_DIR, MOBILE_SITE_ASSET_FILES.config);
34982
+ const siteConfigPath = join24(shellDir, SHELL_SITE_DIR, MOBILE_SITE_ASSET_FILES.config);
34616
34983
  let text;
34617
34984
  try {
34618
34985
  text = await readFile17(siteConfigPath, "utf8");
@@ -34656,8 +35023,8 @@ async function checkConfigDrift(shellDir, config2) {
34656
35023
  };
34657
35024
  }
34658
35025
  async function checkOffline(shellDir) {
34659
- const desktopRoot = join23(shellDir, SHELL_OFFLINE_DIR);
34660
- const siteRoot = join23(shellDir, SHELL_SITE_OFFLINE_DIR);
35026
+ const desktopRoot = join24(shellDir, SHELL_OFFLINE_DIR);
35027
+ const siteRoot = join24(shellDir, SHELL_SITE_OFFLINE_DIR);
34661
35028
  const hasDesktop = await pathExists2(desktopRoot);
34662
35029
  const hasSite = await pathExists2(siteRoot);
34663
35030
  if (!hasDesktop && !hasSite) {
@@ -34690,7 +35057,7 @@ async function checkOffline(shellDir) {
34690
35057
  let functions = [];
34691
35058
  try {
34692
35059
  const index = JSON.parse(
34693
- await readFile17(join23(root, ...OFFLINE_BUNDLE_PATHS.functionsIndex.split("/")), "utf8")
35060
+ await readFile17(join24(root, ...OFFLINE_BUNDLE_PATHS.functionsIndex.split("/")), "utf8")
34694
35061
  );
34695
35062
  functions = index.functions ?? [];
34696
35063
  } catch (error62) {
@@ -34703,7 +35070,7 @@ async function checkOffline(shellDir) {
34703
35070
  };
34704
35071
  }
34705
35072
  const missingSources = (await missingEntries(
34706
- join23(root, "functions"),
35073
+ join24(root, "functions"),
34707
35074
  functions.map((entry) => typeof entry.name === "string" ? entry.name : "").filter((name) => name !== "").map((name) => `${name}.mjs`)
34708
35075
  )).map((rel) => rel.slice(0, -".mjs".length));
34709
35076
  if (missingSources.length > 0) {
@@ -34731,7 +35098,7 @@ async function checkIdentity(shellDir, desktopShaped) {
34731
35098
  detail: "\u79FB\u52A8\u58F3\u5F62\u6001\uFF1A\u8EAB\u4EFD\u5728 Keychain / Keystore\uFF08\u672C\u9879\u53EA\u8BFB\u684C\u9762\u58F3\u7684\u72B6\u6001\u6587\u4EF6\uFF09"
34732
35099
  };
34733
35100
  }
34734
- const file2 = join23(shellDir, IDENTITY_STATUS_REL);
35101
+ const file2 = join24(shellDir, IDENTITY_STATUS_REL);
34735
35102
  let text;
34736
35103
  try {
34737
35104
  text = await readFile17(file2, "utf8");
@@ -34869,7 +35236,7 @@ async function runShellDoctor(shellDir, deps = {}) {
34869
35236
  }
34870
35237
  let html;
34871
35238
  try {
34872
- html = await readEntryPage(join23(shellDir, SHELL_SITE_DIR, "index.html"));
35239
+ html = await readEntryPage(join24(shellDir, SHELL_SITE_DIR, "index.html"));
34873
35240
  checks.push({
34874
35241
  id: "siteEntry",
34875
35242
  status: "ok",
@@ -34887,7 +35254,7 @@ async function runShellDoctor(shellDir, deps = {}) {
34887
35254
  }
34888
35255
  const desktopShaped = config2.template === "app-desktop";
34889
35256
  if (desktopShaped) {
34890
- if (await pathExists2(join23(shellDir, "preload.cjs"))) {
35257
+ if (await pathExists2(join24(shellDir, "preload.cjs"))) {
34891
35258
  checks.push({
34892
35259
  id: "bridgeTag",
34893
35260
  status: "ok",
@@ -34932,7 +35299,7 @@ async function runShellDoctor(shellDir, deps = {}) {
34932
35299
  });
34933
35300
  } else {
34934
35301
  const missingAssets = await missingEntries(
34935
- join23(shellDir, SHELL_SITE_DIR),
35302
+ join24(shellDir, SHELL_SITE_DIR),
34936
35303
  Object.values(MOBILE_SITE_ASSET_FILES)
34937
35304
  );
34938
35305
  if (missingAssets.length === 0) {
@@ -35002,7 +35369,7 @@ function formatShellDoctorReport(report) {
35002
35369
 
35003
35370
  // packages/cli/src/app-sync.ts
35004
35371
  import { readFile as readFile18 } from "node:fs/promises";
35005
- import { join as join24 } from "node:path";
35372
+ import { join as join25 } from "node:path";
35006
35373
 
35007
35374
  // packages/app-runtime/src/device-sqlite.ts
35008
35375
  function createDeviceSqliteDriver(sqlite) {
@@ -35438,7 +35805,7 @@ var APP_SYNC_CODES = {
35438
35805
  /** 当前运行时无 SQLite 内建模块(需要 Bun 或 Node ≥ 22.5)。 */
35439
35806
  runtimeUnsupported: "APP_SYNC_RUNTIME_UNSUPPORTED"
35440
35807
  };
35441
- var LOCAL_DB_REL = join24("data", "offline.sqlite");
35808
+ var LOCAL_DB_REL = join25("data", "offline.sqlite");
35442
35809
  function resolveOwnerKey(explicit) {
35443
35810
  const fromEnv = process.env["ADEP_OWNER_KEY"];
35444
35811
  const value = (explicit ?? fromEnv ?? "").trim();
@@ -35513,7 +35880,7 @@ async function runAppSync(options) {
35513
35880
  );
35514
35881
  }
35515
35882
  const ownerKey = resolveOwnerKey(options.ownerKey);
35516
- const localDb = join24(shellDir, LOCAL_DB_REL);
35883
+ const localDb = join25(shellDir, LOCAL_DB_REL);
35517
35884
  try {
35518
35885
  await readFile18(localDb);
35519
35886
  } catch (error62) {
@@ -35576,14 +35943,14 @@ function formatAppSyncReport(report) {
35576
35943
  // packages/cli/src/app-open.ts
35577
35944
  import { spawn as spawn4 } from "node:child_process";
35578
35945
  import { stat as stat10 } from "node:fs/promises";
35579
- import { join as join25 } from "node:path";
35946
+ import { join as join26 } from "node:path";
35580
35947
  var OPEN_UNSUPPORTED_HINT = {
35581
35948
  "app-mobile": "\u79FB\u52A8\u58F3\u6CA1\u6709\u5F00\u53D1\u9884\u89C8\u8DEF\u5F84\uFF1A\u4E0B\u4E00\u6B65\u662F npm install && npx cap add ios / android\uFF08\u539F\u751F\u5DE5\u7A0B\u7531 Capacitor \u751F\u6210\uFF09\uFF0C\u968F\u540E\u5728 Xcode / Android Studio \u91CC\u8FD0\u884C",
35582
35949
  "app-mobile-xtool": "xtool \u79FB\u52A8\u58F3\u6CA1\u6709\u5F00\u53D1\u9884\u89C8\u8DEF\u5F84\uFF1A\u5728\u8BE5\u76EE\u5F55\u6267\u884C xtool dev\uFF08\u9009\u8BBE\u5907\uFF09\u2014\u2014\u4E0D\u9700\u8981 npm start"
35583
35950
  };
35584
35951
  function resolveDevBinary(shellDir) {
35585
35952
  const name = process.platform === "win32" ? "electron.cmd" : "electron";
35586
- return join25(shellDir, "node_modules", ".bin", name);
35953
+ return join26(shellDir, "node_modules", ".bin", name);
35587
35954
  }
35588
35955
  function defaultSpawnDev(command, args, options) {
35589
35956
  return spawn4(command, args, { cwd: options.cwd, stdio: "inherit" });
@@ -35869,8 +36236,8 @@ function registerApp(program2, ctx) {
35869
36236
  // packages/cli/src/import-cf.ts
35870
36237
  init_adep_config();
35871
36238
  init_regexp();
35872
- import { copyFile as copyFile4, mkdir as mkdir13, readFile as readFile19, readdir as readdir8, stat as stat11, writeFile as writeFile13 } from "node:fs/promises";
35873
- import { basename as basename3, dirname as dirname12, join as join26, relative as relative3, resolve as resolve11 } from "node:path";
36239
+ import { copyFile as copyFile4, mkdir as mkdir13, readFile as readFile19, readdir as readdir8, stat as stat11, writeFile as writeFile14 } from "node:fs/promises";
36240
+ import { basename as basename3, dirname as dirname11, join as join27, relative as relative3, resolve as resolve11 } from "node:path";
35874
36241
  var TomlSyntaxError = class extends Error {
35875
36242
  constructor(message) {
35876
36243
  super(message);
@@ -36126,8 +36493,8 @@ async function copyWorkerDir(sourceDir, targetDir, mainFile) {
36126
36493
  const renamedIndex = [];
36127
36494
  const entries = await readdir8(sourceDir, { withFileTypes: true });
36128
36495
  for (const entry of entries) {
36129
- const from = join26(sourceDir, entry.name);
36130
- const to = join26(targetDir, entry.name);
36496
+ const from = join27(sourceDir, entry.name);
36497
+ const to = join27(targetDir, entry.name);
36131
36498
  if (SKIP_COPY_NAMES.has(entry.name)) continue;
36132
36499
  if (entry.isDirectory()) {
36133
36500
  await mkdir13(to, { recursive: true });
@@ -36138,7 +36505,7 @@ async function copyWorkerDir(sourceDir, targetDir, mainFile) {
36138
36505
  }
36139
36506
  if (from === mainFile) continue;
36140
36507
  if (entry.name === "index.ts") {
36141
- await copyFile4(from, join26(targetDir, "_index.ts"));
36508
+ await copyFile4(from, join27(targetDir, "_index.ts"));
36142
36509
  renamedIndex.push("_index.ts");
36143
36510
  continue;
36144
36511
  }
@@ -36149,7 +36516,7 @@ async function copyWorkerDir(sourceDir, targetDir, mainFile) {
36149
36516
  }
36150
36517
  async function readDevVars(sourceDir) {
36151
36518
  try {
36152
- const text = await readFile19(join26(sourceDir, ".dev.vars"), "utf8");
36519
+ const text = await readFile19(join27(sourceDir, ".dev.vars"), "utf8");
36153
36520
  const vars = {};
36154
36521
  for (const line of text.split(/\r?\n/)) {
36155
36522
  const trimmed = line.trim();
@@ -36167,12 +36534,12 @@ async function readDevVars(sourceDir) {
36167
36534
  async function copyAssetsToWeb(sourceDir, assetsDir, outDir) {
36168
36535
  const files = [];
36169
36536
  const from = resolve11(sourceDir, assetsDir);
36170
- const target = join26(outDir, "web");
36537
+ const target = join27(outDir, "web");
36171
36538
  await mkdir13(target, { recursive: true });
36172
36539
  const entries = await readdir8(from, { withFileTypes: true });
36173
36540
  for (const entry of entries) {
36174
- const src = join26(from, entry.name);
36175
- const dst = join26(target, entry.name);
36541
+ const src = join27(from, entry.name);
36542
+ const dst = join27(target, entry.name);
36176
36543
  if (entry.isDirectory()) {
36177
36544
  await mkdir13(dst, { recursive: true });
36178
36545
  const sub = await copyAssetsToWeb(src, ".", outDir);
@@ -36428,11 +36795,11 @@ function renderImportPackageJson(name) {
36428
36795
  async function importCfProject(cwd, sourceDir, options = {}) {
36429
36796
  let tomlText;
36430
36797
  try {
36431
- tomlText = await readFile19(join26(sourceDir, "wrangler.toml"), "utf8");
36798
+ tomlText = await readFile19(join27(sourceDir, "wrangler.toml"), "utf8");
36432
36799
  } catch {
36433
36800
  throw new ImportCfError(
36434
36801
  "NO_WRANGLER",
36435
- `\u627E\u4E0D\u5230 ${join26(sourceDir, "wrangler.toml")}\uFF1A\u9700\u5728 Cloudflare \u9879\u76EE\u6839\u6267\u884C\u5BFC\u5165`
36802
+ `\u627E\u4E0D\u5230 ${join27(sourceDir, "wrangler.toml")}\uFF1A\u9700\u5728 Cloudflare \u9879\u76EE\u6839\u6267\u884C\u5BFC\u5165`
36436
36803
  );
36437
36804
  }
36438
36805
  let config2;
@@ -36468,9 +36835,9 @@ async function importCfProject(cwd, sourceDir, options = {}) {
36468
36835
  header: "// \u7531 adep import cf \u751F\u6210\uFF08CF-015\uFF09\uFF1A\u7ED1\u5B9A\u58F0\u660E\u4E0E wrangler.toml \u5BF9\u5E94"
36469
36836
  });
36470
36837
  await mkdir13(outDir, { recursive: true });
36471
- await writeFile13(join26(outDir, "adep.config.ts"), configText, "utf8");
36838
+ await writeFile14(join27(outDir, "adep.config.ts"), configText, "utf8");
36472
36839
  files.push("adep.config.ts");
36473
- await writeFile13(join26(outDir, "package.json"), renderImportPackageJson(workerName), "utf8");
36840
+ await writeFile14(join27(outDir, "package.json"), renderImportPackageJson(workerName), "utf8");
36474
36841
  files.push("package.json");
36475
36842
  let mainCopied = false;
36476
36843
  if (config2.main !== void 0) {
@@ -36484,12 +36851,12 @@ async function importCfProject(cwd, sourceDir, options = {}) {
36484
36851
  if (!mainStat.isFile()) {
36485
36852
  throw new ImportCfError("MAIN_NOT_FILE", `main \u4E0D\u662F\u6587\u4EF6\uFF1A${config2.main}`);
36486
36853
  }
36487
- const fnDir = join26(outDir, "functions", workerName);
36854
+ const fnDir = join27(outDir, "functions", workerName);
36488
36855
  await mkdir13(fnDir, { recursive: true });
36489
- await copyFile4(mainAbs, join26(fnDir, "worker.ts"));
36856
+ await copyFile4(mainAbs, join27(fnDir, "worker.ts"));
36490
36857
  files.push(`functions/${workerName}/worker.ts`);
36491
36858
  mainCopied = true;
36492
- const mainDir = dirname12(mainAbs);
36859
+ const mainDir = dirname11(mainAbs);
36493
36860
  const { copied, renamedIndex } = await copyWorkerDir(mainDir, fnDir, mainAbs);
36494
36861
  if (renamedIndex.length > 0) {
36495
36862
  warnings.push(
@@ -36500,7 +36867,7 @@ async function importCfProject(cwd, sourceDir, options = {}) {
36500
36867
  if (copied.length > 0) {
36501
36868
  warnings.push(`\u5DF2\u590D\u5236\u540C\u76EE\u5F55\u4F9D\u8D56\u6A21\u5757 ${copied.length} \u4E2A\uFF08\u4FDD\u6301\u76F8\u5BF9 import\uFF09`);
36502
36869
  }
36503
- await writeFile13(join26(fnDir, "index.ts"), renderFunctionEntry("worker", cfBindings), "utf8");
36870
+ await writeFile14(join27(fnDir, "index.ts"), renderFunctionEntry("worker", cfBindings), "utf8");
36504
36871
  files.push(`functions/${workerName}/index.ts`);
36505
36872
  }
36506
36873
  let dosMigrated = 0;
@@ -36515,20 +36882,20 @@ async function importCfProject(cwd, sourceDir, options = {}) {
36515
36882
  );
36516
36883
  }
36517
36884
  if (doBindings.length > 0) {
36518
- const fnDir = join26(outDir, "functions", workerName);
36519
- const workerPath = join26(fnDir, "worker.ts");
36885
+ const fnDir = join27(outDir, "functions", workerName);
36886
+ const workerPath = join27(fnDir, "worker.ts");
36520
36887
  const workerText = await readFile19(workerPath, "utf8");
36521
36888
  const { text: stripped, removed } = stripDurableObjectClasses(
36522
36889
  workerText,
36523
36890
  doBindings.map((b) => b.className)
36524
36891
  );
36525
- await writeFile13(workerPath, stripped, "utf8");
36892
+ await writeFile14(workerPath, stripped, "utf8");
36526
36893
  if (removed.length > 0) {
36527
- await mkdir13(join26(fnDir, "durable-objects"), { recursive: true });
36894
+ await mkdir13(join27(fnDir, "durable-objects"), { recursive: true });
36528
36895
  await Promise.all(
36529
36896
  removed.map(async (r) => {
36530
- await writeFile13(
36531
- join26(fnDir, "durable-objects", `${r.className}.ts`),
36897
+ await writeFile14(
36898
+ join27(fnDir, "durable-objects", `${r.className}.ts`),
36532
36899
  `${r.source}
36533
36900
  `,
36534
36901
  "utf8"
@@ -36538,8 +36905,8 @@ async function importCfProject(cwd, sourceDir, options = {}) {
36538
36905
  );
36539
36906
  }
36540
36907
  if (removed.length > 0) {
36541
- await writeFile13(
36542
- join26(fnDir, "state-objects.ts"),
36908
+ await writeFile14(
36909
+ join27(fnDir, "state-objects.ts"),
36543
36910
  renderStateObjectDeclaration(doBindings, removed),
36544
36911
  "utf8"
36545
36912
  );
@@ -36584,7 +36951,7 @@ async function importCfProject(cwd, sourceDir, options = {}) {
36584
36951
  unsupported,
36585
36952
  warnings
36586
36953
  });
36587
- await writeFile13(join26(outDir, "MIGRATION.md"), migration, "utf8");
36954
+ await writeFile14(join27(outDir, "MIGRATION.md"), migration, "utf8");
36588
36955
  files.push("MIGRATION.md");
36589
36956
  if (!mainCopied) {
36590
36957
  warnings.push("wrangler.toml \u672A\u58F0\u660E main\uFF1A\u672A\u751F\u6210\u51FD\u6570\uFF0C\u4EC5\u751F\u6210\u914D\u7F6E\u4E0E\u62A5\u544A");
@@ -36705,7 +37072,7 @@ init_auth();
36705
37072
  init_client();
36706
37073
  init_deploy();
36707
37074
  import { stat as stat16 } from "node:fs/promises";
36708
- import { join as join33, resolve as resolve16 } from "node:path";
37075
+ import { join as join34, resolve as resolve16 } from "node:path";
36709
37076
  async function resolveProjectId2(client, cwd, slug) {
36710
37077
  const resolvedSlug = await resolveSlug(resolve16(cwd), slug);
36711
37078
  const listed = await client.request("/api/v1/projects", {}, "PROJECT_LIST_FAILED");
@@ -36752,8 +37119,8 @@ async function publishStaticFrontend(paths, options) {
36752
37119
  "\u7EAF\u9759\u6001\u7AD9\u6682\u4E0D\u652F\u6301\u53D1\u5230\u5F00\u53D1\u7AD9\u70B9\uFF1A\u8BE5\u901A\u9053\u76F4\u63A5\u4E0A\u4F20 site/\uFF0C\u4F1A\u8986\u76D6\u7EBF\u4E0A\u7AD9\u70B9\u3002\u8BF7\u6539\u7528\u5E73\u53F0\u6784\u5EFA\u901A\u9053\uFF08\u5728 web/ \u58F0\u660E scripts.build\uFF09\uFF0C\u6216\u7528 --only functions \u4E4B\u5916\u7684\u5176\u5B83\u65B9\u5F0F\u9A8C\u8BC1\u3002"
36753
37120
  );
36754
37121
  }
36755
- const webDir = join33(options.cwd, "web");
36756
- const indexStat = await stat16(join33(webDir, "index.html")).catch(() => null);
37122
+ const webDir = join34(options.cwd, "web");
37123
+ const indexStat = await stat16(join34(webDir, "index.html")).catch(() => null);
36757
37124
  if (indexStat === null || !indexStat.isFile()) {
36758
37125
  throw new CliError(
36759
37126
  "FRONTEND_NO_PAGE",
@@ -36806,7 +37173,7 @@ async function runPublish(paths, io, cwd, flags) {
36806
37173
  });
36807
37174
  }
36808
37175
  if (wantFrontend) {
36809
- const webDir = join33(cwd, "web");
37176
+ const webDir = join34(cwd, "web");
36810
37177
  const webStat = await stat16(webDir).catch(() => null);
36811
37178
  if (webStat !== null && webStat.isDirectory()) {
36812
37179
  const { isStaticFrontendDir: isStaticFrontendDir2 } = await Promise.resolve().then(() => (init_frontend(), frontend_exports));
@@ -36874,6 +37241,13 @@ function renderPublish(data) {
36874
37241
  lines.push(`\u2713 frontend built ${status} \xB7 ${fe.siteUrl}`);
36875
37242
  }
36876
37243
  }
37244
+ if (result.functions !== void 0) {
37245
+ lines.push("");
37246
+ lines.push("\u53D1\u5E03\u540E\u4E09\u6B65\uFF08\u9996\u6B21\u53D1\u5E03\u5FC5\u505A\uFF09\uFF1A");
37247
+ lines.push(" 1. adep db start # \u542F\u52A8\u9879\u76EE\u6570\u636E\u5E93\uFF08\u82E5\u5DF2\u542F\u52A8\u8DF3\u8FC7\uFF09");
37248
+ lines.push(" 2. adep db migrate <schema.sql> # \u5EFA\u8868\uFF08\u53D1\u5E03\u4E0D\u542B\u5EFA\u8868\uFF09");
37249
+ lines.push(" 3. adep db migrate <seed.sql> # \u79CD\u5B50\u6570\u636E\uFF08\u53EF\u9009\uFF09");
37250
+ }
36877
37251
  return lines;
36878
37252
  }
36879
37253
  function registerPublish(program2, ctx) {
@@ -36908,7 +37282,7 @@ init_auth();
36908
37282
  init_auth();
36909
37283
  init_client();
36910
37284
  import { readdir as readdir12, readFile as readFile26 } from "node:fs/promises";
36911
- import { join as join34, relative as relative8, resolve as resolve17, sep as sep4 } from "node:path";
37285
+ import { join as join35, relative as relative8, resolve as resolve17, sep as sep4 } from "node:path";
36912
37286
  async function collectWranglerFiles(dir) {
36913
37287
  const root = resolve17(dir);
36914
37288
  const out = {};
@@ -36925,7 +37299,7 @@ async function collectWranglerFiles(dir) {
36925
37299
  }
36926
37300
  for (const entry of entries) {
36927
37301
  if (entry.isDirectory() && skip.has(entry.name)) continue;
36928
- const full = join34(sub, entry.name);
37302
+ const full = join35(sub, entry.name);
36929
37303
  if (entry.isDirectory()) {
36930
37304
  await walk(full);
36931
37305
  } else if (entry.isFile()) {
@@ -37241,20 +37615,21 @@ function registerDb(program2, ctx) {
37241
37615
  });
37242
37616
  });
37243
37617
  db.command("migrate").description(
37244
- "\u6267\u884C SQL \u8FC1\u79FB\u6587\u4EF6\uFF08`;` \u5206\u9694\u9010\u6761\u6267\u884C\uFF0C`--` \u6CE8\u91CA\u5FFD\u7565\uFF1BCREATE \u7B49\u975E\u7834\u574F\u6027\u8BED\u53E5\u514D\u786E\u8BA4\uFF09"
37245
- ).argument("<file>", "\u8FC1\u79FB SQL \u6587\u4EF6\u8DEF\u5F84\uFF08\u76F8\u5BF9\u5F53\u524D\u76EE\u5F55\u6216\u7EDD\u5BF9\u8DEF\u5F84\uFF09").option("-p, --project <slug>", "\u76EE\u6807\u5E73\u53F0\u9879\u76EE slug\uFF08\u7F3A\u7701\u53D6 adep.config.ts \u7684 name\uFF09").action(async (file2, flags) => {
37618
+ "\u6267\u884C SQL \u8FC1\u79FB\u6587\u4EF6\uFF08\u53EF\u591A\u4E2A\uFF0C\u6309\u58F0\u660E\u987A\u5E8F\u6267\u884C\u2014\u2014a.sql \u5EFA\u8868\u3001b.sql \u63D2\u6570\u636E\u7684\u4F9D\u8D56\u987A\u5E8F\u5C31\u662F\u58F0\u660E\u987A\u5E8F\uFF1B\u5931\u8D25\u5373\u505C\u5E76\u6307\u5411\u5931\u8D25\u6587\u4EF6\uFF09"
37619
+ ).argument("<files...>", "\u8FC1\u79FB SQL \u6587\u4EF6\u8DEF\u5F84\uFF08\u76F8\u5BF9\u5F53\u524D\u76EE\u5F55\u6216\u7EDD\u5BF9\u8DEF\u5F84\uFF0C\u6309\u58F0\u660E\u987A\u5E8F\u6267\u884C\uFF09").option("-p, --project <slug>", "\u76EE\u6807\u5E73\u53F0\u9879\u76EE slug\uFF08\u7F3A\u7701\u53D6 adep.config.ts \u7684 name\uFF09").action(async (files, flags) => {
37246
37620
  const command = ctx.io("db migrate");
37247
37621
  await command.run(async () => {
37248
37622
  const { environment, source } = await ctx.env();
37249
37623
  const { dbMigrate: dbMigrate2 } = await Promise.resolve().then(() => (init_db2(), db_exports));
37250
37624
  const result = await dbMigrate2(ctx.paths, {
37251
37625
  cwd: ctx.cwd,
37252
- file: file2,
37626
+ files,
37253
37627
  environment,
37254
37628
  ...flags.project === void 0 ? {} : { slug: flags.project }
37255
37629
  });
37256
37630
  if (result.failed !== void 0) {
37257
- command.fail(result.failed.code, result.failed.message);
37631
+ const f = result.failed;
37632
+ command.fail(f.code, `\u6587\u4EF6 ${f.file} \u4E2D\u7684\u8BED\u53E5\u6267\u884C\u5931\u8D25\uFF1A${f.message}`);
37258
37633
  return;
37259
37634
  }
37260
37635
  command.line(
@@ -37732,28 +38107,40 @@ function registerHosting(program2, ctx) {
37732
38107
  });
37733
38108
  });
37734
38109
  hosting.command("deploy").description(
37735
- "[deprecated] \u63A8\u8350\u4F7F\u7528 adep publish --only frontend\u3002\u90E8\u7F72\u672C\u5730\u76EE\u5F55\u4E3A\u9759\u6001\u7AD9\u70B9\uFF1A\u9012\u5F52\u4E0A\u4F20\u5230 site/ \u5E76\u6253\u5F00\u6258\u7BA1"
37736
- ).argument("<dir>", "\u672C\u5730\u7AD9\u70B9\u76EE\u5F55").option("--spa", "\u6253\u5F00\u6258\u7BA1\u5E76\u542F\u7528 SPA \u56DE\u9000\uFF08\u7F3A\u7701\u4EC5\u6253\u5F00\u6258\u7BA1\uFF09", false).option("-p, --project <slug>", "\u76EE\u6807\u5E73\u53F0\u9879\u76EE slug\uFF08\u7F3A\u7701\u53D6 adep.config.ts \u7684 name\uFF09").action(async (dir, flags) => {
37737
- const command = ctx.io("hosting deploy");
37738
- if (!command.json) {
37739
- process.stderr.write(
37740
- "\u63D0\u793A\uFF1Aadep hosting deploy \u5DF2\u5E9F\u5F03\uFF0C\u63A8\u8350\u4F7F\u7528 adep publish --only frontend\uFF08\u5E73\u53F0\u4FA7\u6784\u5EFA web/ \u8349\u7A3F\uFF09\uFF1B\u5982\u786E\u9700\u4E0A\u4F20\u9884\u6784\u5EFA\u76EE\u5F55\uFF0C\u4ECD\u53EF\u7EE7\u7EED\u4F7F\u7528\u672C\u547D\u4EE4\n"
37741
- );
37742
- }
37743
- await command.run(async () => {
37744
- const { hostingDeploy: hostingDeploy2 } = await Promise.resolve().then(() => (init_hosting(), hosting_exports));
37745
- const result = await hostingDeploy2(ctx.paths, {
37746
- cwd: ctx.cwd,
37747
- dir,
37748
- ...flags.spa === true ? { spa: true } : {},
37749
- ...flags.project === void 0 ? {} : { slug: flags.project }
37750
- });
37751
- command.ok(result, (data) => {
37752
- const r = data;
37753
- return `\u7AD9\u70B9\u5DF2\u4E0A\u7EBF\uFF1A${r.siteUrl}\uFF08${r.uploaded.length} \u4E2A\u6587\u4EF6\uFF0CSPA \u56DE\u9000 ${r.config.spaMode ? "\u5F00" : "\u5173"}\uFF09`;
38110
+ "[deprecated] \u63A8\u8350\u4F7F\u7528 adep publish --only frontend\u3002\u90E8\u7F72\u672C\u5730\u76EE\u5F55\u4E3A\u9759\u6001\u7AD9\u70B9\uFF1A\u589E\u91CF\u6BD4\u5BF9\u53EA\u4F20\u53D8\u66F4\u5E76\u6253\u5F00\u6258\u7BA1"
38111
+ ).argument("<dir>", "\u672C\u5730\u7AD9\u70B9\u76EE\u5F55").option("--spa", "\u6253\u5F00\u6258\u7BA1\u5E76\u542F\u7528 SPA \u56DE\u9000\uFF08\u7F3A\u7701\u4EC5\u6253\u5F00\u6258\u7BA1\uFF09", false).option("--build <cmd>", "\u90E8\u7F72\u524D\u6267\u884C\u7684\u6784\u5EFA\u547D\u4EE4\uFF08\u9879\u76EE\u6839\u76EE\u5F55\u8FD0\u884C\uFF0C\u975E\u96F6\u9000\u51FA\u5373\u4E2D\u6B62\u90E8\u7F72\uFF09").option("-p, --project <slug>", "\u76EE\u6807\u5E73\u53F0\u9879\u76EE slug\uFF08\u7F3A\u7701\u53D6 adep.config.ts \u7684 name\uFF09").action(
38112
+ async (dir, flags) => {
38113
+ const command = ctx.io("hosting deploy");
38114
+ if (!command.json) {
38115
+ process.stderr.write(
38116
+ "\u63D0\u793A\uFF1Aadep hosting deploy \u5DF2\u5E9F\u5F03\uFF0C\u63A8\u8350\u4F7F\u7528 adep publish --only frontend\uFF08\u5E73\u53F0\u4FA7\u6784\u5EFA web/ \u8349\u7A3F\uFF09\uFF1B\u5982\u786E\u9700\u4E0A\u4F20\u9884\u6784\u5EFA\u76EE\u5F55\uFF0C\u4ECD\u53EF\u7EE7\u7EED\u4F7F\u7528\u672C\u547D\u4EE4\n"
38117
+ );
38118
+ }
38119
+ await command.run(async () => {
38120
+ const { hostingDeploy: hostingDeploy2 } = await Promise.resolve().then(() => (init_hosting(), hosting_exports));
38121
+ const result = await hostingDeploy2(ctx.paths, {
38122
+ cwd: ctx.cwd,
38123
+ dir,
38124
+ ...flags.spa === true ? { spa: true } : {},
38125
+ ...flags.build === void 0 ? {} : { build: flags.build },
38126
+ ...flags.project === void 0 ? {} : { slug: flags.project },
38127
+ // 人读模式逐行输出进度;JSON 模式丢弃(stdout 必须恰好一个 JSON 对象)。
38128
+ log: (line) => command.line(line)
38129
+ });
38130
+ command.ok(result, (data) => {
38131
+ const r = data;
38132
+ const lines = [];
38133
+ if (r.identical) {
38134
+ lines.push("\u26A0 \u672C\u6B21\u4E0A\u4F20\u5185\u5BB9\u4E0E\u7EBF\u4E0A\u73B0\u6709\u7248\u672C\u5B8C\u5168\u4E00\u81F4\u2014\u2014\u82E5\u521A\u4FEE\u6539\u8FC7\u6E90\u7801\uFF0C\u53EF\u80FD\u5FD8\u4E86\u5148\u6784\u5EFA\u3002");
38135
+ }
38136
+ lines.push(
38137
+ `\u7AD9\u70B9\u5DF2\u4E0A\u7EBF\uFF1A${r.siteUrl}\uFF08${r.uploaded.length} \u53D8\u66F4 / ${r.reused} \u590D\u7528\uFF0C\u6784\u5EFA\u4E8E ${r.builtAt}\uFF0CSPA \u56DE\u9000 ${r.config.spaMode ? "\u5F00" : "\u5173"}\uFF09`
38138
+ );
38139
+ return lines;
38140
+ });
37754
38141
  });
37755
- });
37756
- });
38142
+ }
38143
+ );
37757
38144
  hosting.command("pull").description("\u62C9\u53D6\u7AD9\u70B9\u516C\u5F00\u6587\u4EF6\u5230\u672C\u5730\u76EE\u5F55\uFF08\u8DF3\u8FC7\u6258\u7BA1\u914D\u7F6E\uFF09").option("-o, --output <dir>", "\u672C\u5730\u8F93\u51FA\u76EE\u5F55\uFF08\u7F3A\u7701\u5199\u5230 cwd\uFF09").option("-p, --project <slug>", "\u76EE\u6807\u5E73\u53F0\u9879\u76EE slug\uFF08\u7F3A\u7701\u53D6 adep.config.ts \u7684 name\uFF09").action(async (flags) => {
37758
38145
  const command = ctx.io("hosting pull");
37759
38146
  await command.run(async () => {