@adep/cli 0.4.5 → 0.4.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. package/README.md +44 -3
  2. package/dist/index.js +1206 -742
  3. package/dist/vite.js +218 -35
  4. package/package.json +4 -4
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;
@@ -1001,6 +1077,9 @@ function depsKeyOf(dependencies) {
1001
1077
  const canonical = Object.entries(dependencies).map(([name, version2]) => `${name}@${version2}`).toSorted().join("\n");
1002
1078
  return createHash("sha256").update(canonical).digest("hex").slice(0, 16);
1003
1079
  }
1080
+ function parseNameList(value) {
1081
+ return value.split(",").map((item) => item.trim()).filter((item) => item.length > 0);
1082
+ }
1004
1083
  var PACKAGE_NAME_PATTERN, COMPARATOR_PATTERN, MANIFEST_MAX_DEPS;
1005
1084
  var init_manifest = __esm({
1006
1085
  "packages/runtime/src/functions/deps/manifest.ts"() {
@@ -1035,22 +1114,22 @@ var init_resolve = __esm({
1035
1114
  // packages/runtime/src/functions/runtime/worker-executor.ts
1036
1115
  import { readFileSync as readFileSync2 } from "node:fs";
1037
1116
  import { fileURLToPath as fileURLToPath2, pathToFileURL } from "node:url";
1038
- import { dirname as dirname4, join as join3 } from "node:path";
1117
+ import { dirname as dirname3, join as join4 } from "node:path";
1039
1118
  import { Worker } from "node:worker_threads";
1040
1119
  function resolveWorkerEntry(baseDir = fileURLToPath2(new URL(".", import.meta.url))) {
1041
1120
  const candidates = [
1042
- join3(baseDir, "worker-entry.js"),
1043
- join3(baseDir, "worker-entry.ts"),
1044
- join3(baseDir, "domains/functions/runtime/worker-entry.js"),
1045
- 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")
1046
1125
  ];
1047
1126
  let current = baseDir;
1048
1127
  for (let depth = 0; depth < 8; depth += 1) {
1049
1128
  candidates.push(
1050
- join3(current, "packages/runtime/src/functions/runtime/worker-entry.js"),
1051
- 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")
1052
1131
  );
1053
- const parent = dirname4(current);
1132
+ const parent = dirname3(current);
1054
1133
  if (parent === current) break;
1055
1134
  current = parent;
1056
1135
  }
@@ -1920,6 +1999,20 @@ var init_builder = __esm({
1920
1999
 
1921
2000
  // packages/runtime/src/database/sdk/cloud.ts
1922
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
+ }
1923
2016
  const code = typeof error62 === "object" && error62 !== null && typeof error62.code === "string" ? error62.code : void 0;
1924
2017
  if (code !== void 0 && error62 instanceof Error) {
1925
2018
  return new Error(`[${code}] ${error62.message}`);
@@ -3257,13 +3350,13 @@ var init_cloud2 = __esm({
3257
3350
  });
3258
3351
 
3259
3352
  // packages/runtime/src/storage/driver/local.ts
3260
- import { mkdir as mkdir3, readFile as readFile2, readdir, rm as rm2, stat as stat3, unlink, writeFile as writeFile2 } from "node:fs/promises";
3261
- 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";
3262
3355
  function createLocalStorageDriver(options) {
3263
3356
  const quotaBytes = options.quotaBytes ?? PROJECT_QUOTA_BYTES;
3264
- const bucketDir = (projectId) => join4(options.dir, projectId);
3265
- const objectPath = (projectId, path) => join4(bucketDir(projectId), path);
3266
- 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}`);
3267
3360
  const readStoredMeta = async (projectId, path) => {
3268
3361
  const raw = await readFile2(metaPath(projectId, path), "utf8");
3269
3362
  return JSON.parse(raw);
@@ -3275,7 +3368,7 @@ function createLocalStorageDriver(options) {
3275
3368
  updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
3276
3369
  ...meta3.contentType === void 0 ? {} : { contentType: meta3.contentType }
3277
3370
  };
3278
- await writeFile2(metaPath(projectId, path), JSON.stringify(payload), "utf8");
3371
+ await writeFile3(metaPath(projectId, path), JSON.stringify(payload), "utf8");
3279
3372
  };
3280
3373
  const totalSize = async (projectId) => {
3281
3374
  const root = bucketDir(projectId);
@@ -3289,7 +3382,7 @@ function createLocalStorageDriver(options) {
3289
3382
  }
3290
3383
  const tasks = [];
3291
3384
  for (const entry of entries) {
3292
- const full = join4(dir, entry.name);
3385
+ const full = join5(dir, entry.name);
3293
3386
  if (entry.isDirectory()) {
3294
3387
  tasks.push(walk(full));
3295
3388
  } else if (entry.isFile() && !entry.name.endsWith(META_SUFFIX)) {
@@ -3333,8 +3426,8 @@ function createLocalStorageDriver(options) {
3333
3426
  );
3334
3427
  }
3335
3428
  const dest = objectPath(projectId, path);
3336
- await mkdir3(dirname5(dest), { recursive: true });
3337
- await writeFile2(dest, data);
3429
+ await mkdir3(dirname4(dest), { recursive: true });
3430
+ await writeFile3(dest, data);
3338
3431
  await writeStoredMeta(projectId, path, {
3339
3432
  visibility: putOptions.visibility,
3340
3433
  size: data.byteLength,
@@ -3412,7 +3505,7 @@ function createLocalStorageDriver(options) {
3412
3505
  const tasks = [];
3413
3506
  for (const entry of entries) {
3414
3507
  if (entry.name.endsWith(META_SUFFIX)) continue;
3415
- const full = join4(dir, entry.name);
3508
+ const full = join5(dir, entry.name);
3416
3509
  const rel = relative10 === "" ? entry.name : `${relative10}/${entry.name}`;
3417
3510
  if (entry.isFile()) {
3418
3511
  if (prefix !== void 0 && !rel.startsWith(prefix)) continue;
@@ -3461,9 +3554,9 @@ var init_local = __esm({
3461
3554
  });
3462
3555
 
3463
3556
  // packages/cli/src/sim/storage.ts
3464
- import { join as join5 } from "node:path";
3557
+ import { join as join6 } from "node:path";
3465
3558
  function createSimStorageCapability(options) {
3466
- const dir = join5(options.cwd, ".adep", "sim", "storage");
3559
+ const dir = join6(options.cwd, ".adep", "sim", "storage");
3467
3560
  const driver = createLocalStorageDriver({ dir });
3468
3561
  const signer = {
3469
3562
  secret: options.secret ?? SIM_SIGN_SECRET,
@@ -3638,13 +3731,13 @@ var init_merge = __esm({
3638
3731
  });
3639
3732
 
3640
3733
  // packages/cli/src/sim/runtime.ts
3641
- import { mkdir as mkdir4, readFile as readFile3, writeFile as writeFile3 } from "node:fs/promises";
3642
- 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";
3643
3736
  function simDir(cwd) {
3644
- return join6(cwd, ".adep", "sim");
3737
+ return join7(cwd, ".adep", "sim");
3645
3738
  }
3646
3739
  function jsonStorage(cwd) {
3647
- const file2 = join6(simDir(cwd), "db.json");
3740
+ const file2 = join7(simDir(cwd), "db.json");
3648
3741
  return {
3649
3742
  async load() {
3650
3743
  try {
@@ -3655,8 +3748,8 @@ function jsonStorage(cwd) {
3655
3748
  }
3656
3749
  },
3657
3750
  async save(tables) {
3658
- await mkdir4(dirname6(file2), { recursive: true });
3659
- await writeFile3(file2, JSON.stringify(tables), "utf8");
3751
+ await mkdir4(dirname5(file2), { recursive: true });
3752
+ await writeFile4(file2, JSON.stringify(tables), "utf8");
3660
3753
  }
3661
3754
  };
3662
3755
  }
@@ -3811,6 +3904,63 @@ var init_client = __esm({
3811
3904
  }
3812
3905
  });
3813
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
+
3814
3964
  // packages/cli/src/db.ts
3815
3965
  var db_exports = {};
3816
3966
  __export(db_exports, {
@@ -3912,61 +4062,20 @@ async function dbRollback(paths, options) {
3912
4062
  { method: "POST", body: { to: options.to } }
3913
4063
  );
3914
4064
  }
3915
- function splitSqlStatements(source) {
3916
- const statements = [];
3917
- let buffer = "";
3918
- let inQuote = false;
3919
- const lines = source.split("\n");
3920
- for (const rawLine of lines) {
3921
- const trimmed = rawLine.trim();
3922
- if (!inQuote && (trimmed.length === 0 || trimmed.startsWith("--"))) continue;
3923
- for (let i = 0; i < rawLine.length; i++) {
3924
- const ch = rawLine[i];
3925
- if (inQuote) {
3926
- if (ch === "'") {
3927
- if (rawLine[i + 1] === "'") {
3928
- buffer += ch + rawLine[i + 1];
3929
- i++;
3930
- continue;
3931
- }
3932
- inQuote = false;
3933
- }
3934
- buffer += ch;
3935
- continue;
3936
- }
3937
- if (ch === "'") {
3938
- inQuote = true;
3939
- buffer += ch;
3940
- continue;
3941
- }
3942
- if (ch === "-" && rawLine[i + 1] === "-") break;
3943
- if (ch === ";") {
3944
- const statement = buffer.trim();
3945
- if (statement.length > 0) statements.push(statement);
3946
- buffer = "";
3947
- continue;
3948
- }
3949
- buffer += ch;
3950
- }
3951
- buffer += inQuote ? "\n" : " ";
3952
- }
3953
- if (inQuote) {
3954
- throw new Error(`SQL \u8FC1\u79FB\u6587\u4EF6\u5F15\u53F7\u672A\u95ED\u5408\uFF1A${buffer.trim().slice(0, 80)}\u2026`);
3955
- }
3956
- const tail = buffer.trim();
3957
- if (tail.length > 0) statements.push(tail);
3958
- return statements;
3959
- }
3960
4065
  async function dbMigrate(paths, options) {
3961
- const source = await readFile4(resolve3(options.file), "utf8");
3962
- const statements = splitSqlStatements(source);
3963
- if (statements.length === 0) {
3964
- 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 });
3965
4074
  }
3966
4075
  const { project: project2 } = await open2(paths, options);
3967
4076
  const applied = [];
3968
4077
  const changes = [];
3969
- for (const statement of statements) {
4078
+ for (const { file: file2, statement } of queue) {
3970
4079
  try {
3971
4080
  const result = await dbExec(paths, {
3972
4081
  cwd: options.cwd,
@@ -3985,7 +4094,7 @@ async function dbMigrate(paths, options) {
3985
4094
  projectId: project2,
3986
4095
  applied,
3987
4096
  changes,
3988
- failed: { statement, code, message }
4097
+ failed: { file: file2, statement, code, message }
3989
4098
  };
3990
4099
  }
3991
4100
  }
@@ -3996,12 +4105,14 @@ var init_db2 = __esm({
3996
4105
  "use strict";
3997
4106
  init_auth();
3998
4107
  init_client();
4108
+ init_sql_split();
4109
+ init_sql_split();
3999
4110
  }
4000
4111
  });
4001
4112
 
4002
4113
  // packages/cli/src/serve/sqlite-driver.ts
4003
4114
  import { mkdir as mkdir5 } from "node:fs/promises";
4004
- import { dirname as dirname7, resolve as resolve4 } from "node:path";
4115
+ import { dirname as dirname6, resolve as resolve4 } from "node:path";
4005
4116
  function isBun(versions) {
4006
4117
  return versions["bun"] !== void 0 && versions["bun"] !== "";
4007
4118
  }
@@ -4051,7 +4162,7 @@ async function openSqliteProjectDriver(file2, options = {}) {
4051
4162
  throw new Error(`${moduleName} \u672A\u5BFC\u51FA ${ctorName}\uFF1A\u5F53\u524D\u8FD0\u884C\u65F6\u7684 SQLite \u5185\u5EFA\u6A21\u5757\u4E0D\u53EF\u7528`);
4052
4163
  }
4053
4164
  const target = file2 === ":memory:" ? file2 : resolve4(file2);
4054
- if (target !== ":memory:") await mkdir5(dirname7(target), { recursive: true });
4165
+ if (target !== ":memory:") await mkdir5(dirname6(target), { recursive: true });
4055
4166
  const database = new Ctor(target);
4056
4167
  database.exec("PRAGMA journal_mode = WAL; PRAGMA foreign_keys = ON;");
4057
4168
  return {
@@ -4090,7 +4201,7 @@ var init_sqlite_driver = __esm({
4090
4201
 
4091
4202
  // packages/cli/src/serve/db-mode.ts
4092
4203
  import { readFile as readFile5 } from "node:fs/promises";
4093
- import { join as join7, relative, resolve as resolve5 } from "node:path";
4204
+ import { join as join8, relative, resolve as resolve5 } from "node:path";
4094
4205
  function isServeDbMode(value) {
4095
4206
  return SERVE_DB_MODES.includes(value.trim().toLowerCase());
4096
4207
  }
@@ -4125,7 +4236,7 @@ function displayPath(cwd, target) {
4125
4236
  return rel.startsWith("..") ? target : rel.split(/[\\/]/u).join("/");
4126
4237
  }
4127
4238
  function simDbTarget(cwd) {
4128
- return displayPath(cwd, join7(simDir(cwd), "db.json"));
4239
+ return displayPath(cwd, join8(simDir(cwd), "db.json"));
4129
4240
  }
4130
4241
  function resolveLocalDbTarget(cwd, options) {
4131
4242
  const mode = resolveServeDbMode(options.db);
@@ -4211,7 +4322,7 @@ var init_db_mode = __esm({
4211
4322
 
4212
4323
  // packages/cli/src/sim/env.ts
4213
4324
  import { readFile as readFile6 } from "node:fs/promises";
4214
- import { join as join8 } from "node:path";
4325
+ import { join as join9 } from "node:path";
4215
4326
  function parseEnv(content) {
4216
4327
  const env = {};
4217
4328
  for (const raw of content.split(/\r?\n/)) {
@@ -4226,8 +4337,8 @@ function parseEnv(content) {
4226
4337
  return env;
4227
4338
  }
4228
4339
  async function loadSimEnv(cwd, config2 = {}) {
4229
- const envRoot = await readFile6(join8(cwd, ".env"), "utf8").catch(() => "");
4230
- 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(() => "");
4231
4342
  const merged = { ...parseEnv(envRoot), ...parseEnv(envLocal) };
4232
4343
  for (const secret of config2.secrets ?? []) {
4233
4344
  if (merged[secret] !== void 0) continue;
@@ -4247,6 +4358,32 @@ var init_env = __esm({
4247
4358
  }
4248
4359
  });
4249
4360
 
4361
+ // packages/cli/src/sim/fetch-config.ts
4362
+ function resolveLocalFetchConfig(simEnv) {
4363
+ const rawAllowlist = simEnv.FUNCTIONS_FETCH_ALLOWLIST;
4364
+ if (rawAllowlist === void 0) return void 0;
4365
+ const rawTimeout = simEnv.FUNCTIONS_FETCH_TIMEOUT_MS;
4366
+ let timeoutMs = LOCAL_FETCH_TIMEOUT_MS_DEFAULT;
4367
+ if (rawTimeout !== void 0 && rawTimeout.trim() !== "") {
4368
+ const parsed = Number(rawTimeout);
4369
+ if (!Number.isInteger(parsed) || parsed <= 0) {
4370
+ throw new Error(
4371
+ `[adep] FUNCTIONS_FETCH_TIMEOUT_MS \u975E\u6CD5\uFF1A"${rawTimeout}"\uFF08\u987B\u4E3A\u6B63\u6574\u6570\u6BEB\u79D2\u6570\uFF1B\u4E0D\u914D\u5219\u7F3A\u7701 ${LOCAL_FETCH_TIMEOUT_MS_DEFAULT}\uFF09`
4372
+ );
4373
+ }
4374
+ timeoutMs = parsed;
4375
+ }
4376
+ return { allowlist: parseNameList(rawAllowlist), timeoutMs };
4377
+ }
4378
+ var LOCAL_FETCH_TIMEOUT_MS_DEFAULT;
4379
+ var init_fetch_config = __esm({
4380
+ "packages/cli/src/sim/fetch-config.ts"() {
4381
+ "use strict";
4382
+ init_manifest();
4383
+ LOCAL_FETCH_TIMEOUT_MS_DEFAULT = 1e4;
4384
+ }
4385
+ });
4386
+
4250
4387
  // packages/cli/src/sim/invoke.ts
4251
4388
  function resolveFunctionEntry(files, fnName) {
4252
4389
  const flat = `${fnName}.ts`;
@@ -4376,6 +4513,11 @@ var init_boundary = __esm({
4376
4513
  kind: "diff",
4377
4514
  title: "\u4E0D\u8BA1\u91CF",
4378
4515
  detail: "\u672C\u6A21\u62DF\u8FD0\u884C\u65F6\u4E0D\u4EA7\u51FA\u8BA1\u91CF\u4E8B\u4EF6\uFF0C\u4E5F\u4E0D\u5199 billing\uFF1B\u79BB\u7EBF\u5F00\u53D1\u4E0D\u8BA1\u8D39\u3002"
4516
+ },
4517
+ {
4518
+ kind: "diff",
4519
+ title: "\u51FA\u7F51\u7531\u767D\u540D\u5355\u63A7\u5236",
4520
+ detail: "cloud.fetch \u9ED8\u8BA4\u65E0\u7F51\u7EDC\uFF08\u672A\u914D\u7F6E\u65F6\u8C03\u7528\u629B FN_FETCH_DISABLED\uFF09\uFF1B.env \u914D FUNCTIONS_FETCH_ALLOWLIST\uFF08\u9017\u53F7\u5206\u9694\u4E3B\u673A\uFF0C*. \u901A\u914D\uFF1BFUNCTIONS_FETCH_TIMEOUT_MS \u7F3A\u7701 10s\uFF09\u540E\u91CD\u542F\u6CE8\u5165\u53D7\u63A7 fetch\u2014\u2014\u95E8\u7981\u4E0E\u7EBF\u4E0A\u4E00\u81F4\uFF08\u767D\u540D\u5355 / \u8D85\u65F6 / \u91CD\u5B9A\u5411\u9010\u8DF3\u590D\u68C0\uFF09\uFF0C\u4F46\u672C\u5730\u7531\u5F00\u53D1\u673A\u7F51\u7EDC\u6808\u76F4\u8FDE\uFF0C\u65E0\u5E73\u53F0\u51FA\u7F51\u4E2D\u7EE7\u4E0E\u5BA1\u8BA1\u3002"
4379
4521
  }
4380
4522
  ];
4381
4523
  }
@@ -4383,9 +4525,9 @@ var init_boundary = __esm({
4383
4525
 
4384
4526
  // packages/cli/src/ts-config.ts
4385
4527
  import { stat as stat4, readFile as readFile7 } from "node:fs/promises";
4386
- import { join as join9 } from "node:path";
4528
+ import { join as join10 } from "node:path";
4387
4529
  async function loadAdepConfigModule(cwd) {
4388
- const configPath = join9(cwd, "adep.config.ts");
4530
+ const configPath = join10(cwd, "adep.config.ts");
4389
4531
  try {
4390
4532
  await stat4(configPath);
4391
4533
  } catch {
@@ -5746,7 +5888,7 @@ var init_chain = __esm({
5746
5888
  // packages/runtime/src/functions/runtime/worker-entry.ts
5747
5889
  import { parentPort, workerData } from "node:worker_threads";
5748
5890
  import { createRequire } from "node:module";
5749
- import { join as join10 } from "node:path";
5891
+ import { join as join11 } from "node:path";
5750
5892
  function errorMessageOf2(error62) {
5751
5893
  if (error62 instanceof Error) return error62.message;
5752
5894
  if (typeof error62 === "object" && error62 !== null && "message" in error62) {
@@ -5801,7 +5943,7 @@ function errorMessageWithLocation(error62, files) {
5801
5943
  }
5802
5944
  function createBareResolver(deps) {
5803
5945
  const platformRequire = createRequire(import.meta.url);
5804
- 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"));
5805
5947
  return (request) => {
5806
5948
  if (deps.builtin.includes(request)) return platformRequire(request);
5807
5949
  const root = splitBareSpecifier(request);
@@ -5994,13 +6136,127 @@ var init_function_source = __esm({
5994
6136
  }
5995
6137
  });
5996
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
+
5997
6247
  // packages/cli/src/dev-shared.ts
5998
6248
  import { readdir as readdir2, readFile as readFile8 } from "node:fs/promises";
5999
- import { join as join11 } from "node:path";
6000
- function bearerUserResolverFromEnv() {
6001
- const raw = process.env.ADEP_AUTH_ISSUER;
6002
- if (raw === void 0 || raw.trim() === "") return void 0;
6003
- 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;
6004
6260
  }
6005
6261
  function createBearerUserResolver(issuer) {
6006
6262
  const userinfoUrl = `${issuer.replace(/\/+$/, "")}/oauth/userinfo`;
@@ -6037,7 +6293,7 @@ async function collectFunctions(dir, readImpl = (path) => readFile8(path, "utf8"
6037
6293
  }
6038
6294
  for (const entry of entries) {
6039
6295
  const rel = prefix.length === 0 ? entry.name : `${prefix}/${entry.name}`;
6040
- const full = join11(sub, entry.name);
6296
+ const full = join12(sub, entry.name);
6041
6297
  if (entry.isDirectory()) {
6042
6298
  await walk(full, rel);
6043
6299
  } else if (entry.isFile() && isRuntimeSource(entry.name)) {
@@ -6067,25 +6323,41 @@ function mergeSharedIntoFunctions(files) {
6067
6323
  }
6068
6324
  return out;
6069
6325
  }
6070
- function bodyOf(req) {
6071
- return new Promise((resolveBody, rejectBody) => {
6326
+ function readRawBody(req) {
6327
+ return new Promise((resolveRaw, rejectRaw) => {
6072
6328
  const chunks = [];
6073
6329
  req.on("data", (chunk) => chunks.push(chunk));
6074
- req.on("end", () => {
6075
- const raw = Buffer.concat(chunks).toString("utf8");
6076
- if (raw.length === 0) {
6077
- resolveBody(void 0);
6078
- return;
6079
- }
6080
- try {
6081
- resolveBody(JSON.parse(raw));
6082
- } catch {
6083
- resolveBody(raw);
6084
- }
6085
- });
6086
- req.on("error", rejectBody);
6330
+ req.on("end", () => resolveRaw(Buffer.concat(chunks)));
6331
+ req.on("error", rejectRaw);
6087
6332
  });
6088
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
+ }
6089
6361
  function writeJson(res, status, payload) {
6090
6362
  res.writeHead(status, { "content-type": "application/json" });
6091
6363
  res.end(JSON.stringify(payload));
@@ -6100,13 +6372,14 @@ async function requestInput(url2, req, readBody) {
6100
6372
  for (const [key, value] of Object.entries(req.headers)) {
6101
6373
  if (typeof value === "string") headers[key] = value;
6102
6374
  }
6103
- 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);
6104
6376
  return {
6105
6377
  method: req.method ?? "GET",
6106
6378
  path: url2.pathname,
6107
6379
  query,
6108
6380
  headers,
6109
- ...body === void 0 ? {} : { body }
6381
+ ...parsed?.body === void 0 ? {} : { body: parsed.body },
6382
+ ...parsed?.files === void 0 ? {} : { files: parsed.files }
6110
6383
  };
6111
6384
  }
6112
6385
  var BEARER_TOKEN_RE;
@@ -6115,6 +6388,8 @@ var init_dev_shared = __esm({
6115
6388
  "use strict";
6116
6389
  init_function_source();
6117
6390
  init_shared_source();
6391
+ init_multipart();
6392
+ init_executor_runtime();
6118
6393
  init_invoke();
6119
6394
  BEARER_TOKEN_RE = /^Bearer\s+(.+)$/i;
6120
6395
  }
@@ -6130,8 +6405,8 @@ __export(dev_exports, {
6130
6405
  });
6131
6406
  import { createServer } from "node:http";
6132
6407
  import { watch } from "node:fs";
6133
- import { mkdir as mkdir6, readFile as readFile9, writeFile as writeFile4 } from "node:fs/promises";
6134
- 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";
6135
6410
  async function loadConfig(cwd) {
6136
6411
  const name = basename(resolve6(cwd));
6137
6412
  const config2 = await loadAdepConfigModule(cwd);
@@ -6176,10 +6451,10 @@ function printBoundaries(log) {
6176
6451
  }
6177
6452
  }
6178
6453
  async function ensureGitignore(cwd) {
6179
- const gitignorePath = join12(cwd, ".gitignore");
6454
+ const gitignorePath = join13(cwd, ".gitignore");
6180
6455
  const existing = await readFile9(gitignorePath, "utf8").catch(() => "");
6181
6456
  if (existing.split(/\r?\n/).includes(".adep/")) return;
6182
- await writeFile4(gitignorePath, `${existing.replace(/\n+$/, "")}
6457
+ await writeFile5(gitignorePath, `${existing.replace(/\n+$/, "")}
6183
6458
  .adep/
6184
6459
  `, "utf8");
6185
6460
  }
@@ -6191,16 +6466,25 @@ async function startDevServer(options) {
6191
6466
  if (options.prefix !== void 0) {
6192
6467
  config2.functionsPrefix = options.prefix.replace(/^\/+|\/+$/g, "");
6193
6468
  }
6194
- const functionsDir = join12(cwd, config2.functionsDir);
6469
+ const functionsDir = join13(cwd, config2.functionsDir);
6195
6470
  const coldStartAt = Date.now();
6196
6471
  const dbTarget = resolveLocalDbTarget(cwd, {
6197
6472
  ...options.db === void 0 ? {} : { db: options.db },
6198
6473
  ...options.dbFile === void 0 ? {} : { dbFile: options.dbFile }
6199
6474
  });
6200
- const bearerUser = bearerUserResolverFromEnv();
6475
+ const simEnv = await loadSimEnv(cwd).catch(() => ({}));
6476
+ let bearerUser = bearerUserResolverFromEnv(simEnv);
6477
+ const fetchConfig = resolveLocalFetchConfig(simEnv);
6201
6478
  const executor = new WorkerFunctionExecutor({
6202
- deps: { rootDir: cwd, builtin: LOCAL_BUILTIN_DEPS }
6479
+ deps: { rootDir: cwd, builtin: LOCAL_BUILTIN_DEPS },
6480
+ // GAME-007 本地接线:配置白名单才注入受控 fetch,语义与线上逐字一致。
6481
+ ...fetchConfig === void 0 ? {} : { fetch: fetchConfig }
6203
6482
  });
6483
+ if (fetchConfig !== void 0) {
6484
+ log(
6485
+ `[adep] \u53D7\u63A7 fetch \u5DF2\u6CE8\u5165\uFF08FUNCTIONS_FETCH_ALLOWLIST\uFF09\uFF1A\u767D\u540D\u5355 ${fetchConfig.allowlist.length} \u9879\uFF0C\u8D85\u65F6 ${fetchConfig.timeoutMs}ms`
6486
+ );
6487
+ }
6204
6488
  await mkdir6(functionsDir, { recursive: true });
6205
6489
  const db = await openLocalDbDriver(dbTarget, { cwd, tag: "adep", log });
6206
6490
  const runtime = await createSimRuntime({
@@ -6223,7 +6507,7 @@ async function startDevServer(options) {
6223
6507
  let files = mergeSharedIntoFunctions(await collectFunctions(functionsDir));
6224
6508
  let env = {
6225
6509
  ...config2.environment,
6226
- ...await loadSimEnv(cwd).catch(() => ({}))
6510
+ ...simEnv
6227
6511
  };
6228
6512
  const dbBundle = runtime.bundle;
6229
6513
  const invokeHandler = createSimInvokeHandler({ executor, files });
@@ -6299,12 +6583,13 @@ async function startDevServer(options) {
6299
6583
  const reload = async () => {
6300
6584
  const [nextFiles, envText2] = await Promise.all([
6301
6585
  collectFunctions(functionsDir).then(mergeSharedIntoFunctions),
6302
- readFile9(join12(cwd, ".env.local"), "utf8").catch(() => "")
6586
+ readFile9(join13(cwd, ".env.local"), "utf8").catch(() => "")
6303
6587
  ]);
6304
6588
  files = nextFiles;
6305
6589
  env = { ...config2.environment, ...parseEnvFile(envText2) };
6590
+ bearerUser = bearerUserResolverFromEnv(await loadSimEnv(cwd).catch(() => ({})));
6306
6591
  };
6307
- const envText = await readFile9(join12(cwd, ".env.local"), "utf8").catch(() => "");
6592
+ const envText = await readFile9(join13(cwd, ".env.local"), "utf8").catch(() => "");
6308
6593
  env = { ...config2.environment, ...parseEnvFile(envText) };
6309
6594
  let debounceTimer;
6310
6595
  let watcher;
@@ -6320,7 +6605,7 @@ async function startDevServer(options) {
6320
6605
  }
6321
6606
  const buildInput = async (fnName, entry, url2, req) => {
6322
6607
  const hasEnv = Object.keys(env).length > 0;
6323
- const request = await requestInput(url2, req, bodyOf);
6608
+ const request = await requestInput(url2, req, bodyWithFiles);
6324
6609
  if (bearerUser !== void 0) request.user = await bearerUser(request.headers);
6325
6610
  return {
6326
6611
  project: { id: "local", slug: config2.name },
@@ -6394,9 +6679,9 @@ async function startDevServer(options) {
6394
6679
  writeJson(res, 404, { error: { code: "FN_NOT_FOUND", message: `\u51FD\u6570 "${fnName}" \u4E0D\u5B58\u5728` } });
6395
6680
  return;
6396
6681
  }
6397
- const input2 = await buildInput(fnName, entry, url2, req);
6398
6682
  const startedAt = performance.now();
6399
6683
  try {
6684
+ const input2 = await buildInput(fnName, entry, url2, req);
6400
6685
  const result = await executor.execute(input2);
6401
6686
  const durationMs = Math.round(performance.now() - startedAt);
6402
6687
  for (const line of result.logs) log(`[adep] ${line}`);
@@ -6469,7 +6754,9 @@ async function startDevServer(options) {
6469
6754
  log(`[adep] curl \u793A\u4F8B\uFF1Acurl ${baseUrl}${curlPath}`);
6470
6755
  printBoundaries(log);
6471
6756
  if (bearerUser !== void 0) {
6472
- 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
+ );
6473
6760
  }
6474
6761
  log(`[adep] \u6570\u636E\u5E93\uFF1A${dbLabel} \u2192 ${dbTargetText}`);
6475
6762
  startStateAlarmScheduler();
@@ -6496,6 +6783,7 @@ var init_dev = __esm({
6496
6783
  init_runtime();
6497
6784
  init_db_mode();
6498
6785
  init_env();
6786
+ init_fetch_config();
6499
6787
  init_invoke();
6500
6788
  init_builtin_deps2();
6501
6789
  init_boundary();
@@ -6549,6 +6837,75 @@ var init_prompt = __esm({
6549
6837
  }
6550
6838
  });
6551
6839
 
6840
+ // packages/cli/src/export/client.ts
6841
+ var client_exports2 = {};
6842
+ __export(client_exports2, {
6843
+ createExportApiClient: () => createExportApiClient
6844
+ });
6845
+ import { writeFile as writeFile8 } from "node:fs/promises";
6846
+ function toExportJob(view) {
6847
+ return {
6848
+ id: view.id,
6849
+ status: view.status,
6850
+ progress: view.progress,
6851
+ createdAt: view.createdAt,
6852
+ ...view.stage === void 0 ? {} : { stage: view.stage },
6853
+ ...view.error === void 0 ? {} : { error: view.error },
6854
+ ...view.downloadUrl === void 0 ? {} : { downloadUrl: view.downloadUrl },
6855
+ ...view.bundleSize === void 0 ? {} : { bundleSize: view.bundleSize },
6856
+ ...view.completedAt === void 0 ? {} : { completedAt: view.completedAt }
6857
+ };
6858
+ }
6859
+ async function createExportApiClient(paths) {
6860
+ const client = await createClient(paths);
6861
+ return {
6862
+ async triggerExport(projectId, options) {
6863
+ const view = await client.request(
6864
+ `/api/v1/projects/${encodeURIComponent(projectId)}/export`,
6865
+ {
6866
+ method: "POST",
6867
+ body: {
6868
+ withData: options.withData,
6869
+ withSource: options.withSource,
6870
+ ...options.withoutSource === true ? { withoutSource: true } : {}
6871
+ }
6872
+ },
6873
+ "EXPORT_TRIGGER_FAILED"
6874
+ );
6875
+ return toExportJob(view);
6876
+ },
6877
+ async getJobStatus(jobId) {
6878
+ const view = await client.request(
6879
+ `/api/v1/exports/${encodeURIComponent(jobId)}`,
6880
+ {},
6881
+ "EXPORT_STATUS_FAILED"
6882
+ );
6883
+ return toExportJob(view);
6884
+ },
6885
+ async downloadBundle(jobId, outputPath) {
6886
+ const download = await client.request(
6887
+ `/api/v1/exports/${encodeURIComponent(jobId)}/download`,
6888
+ {},
6889
+ "EXPORT_DOWNLOAD_FAILED"
6890
+ );
6891
+ if (download.downloadUrl.length === 0) {
6892
+ throw new CliError("EXPORT_BUNDLE_UNAVAILABLE", "\u5BFC\u51FA\u4EA7\u7269\u4E0B\u8F7D URL \u4E3A\u7A7A\uFF0C\u4EA7\u7269\u53EF\u80FD\u5C1A\u4E0D\u53EF\u7528");
6893
+ }
6894
+ const response = await client.download(download.downloadUrl, "EXPORT_DOWNLOAD_FAILED");
6895
+ const bytes = Buffer.from(await response.arrayBuffer());
6896
+ await writeFile8(outputPath, bytes);
6897
+ return { path: outputPath, size: bytes.length };
6898
+ }
6899
+ };
6900
+ }
6901
+ var init_client2 = __esm({
6902
+ "packages/cli/src/export/client.ts"() {
6903
+ "use strict";
6904
+ init_auth();
6905
+ init_client();
6906
+ }
6907
+ });
6908
+
6552
6909
  // shared/deploy-bundle/manifest.ts
6553
6910
  var CURRENT_SCHEMA_VERSION, BundleContentKind, ALLOWED_CONTENT_KINDS;
6554
6911
  var init_manifest2 = __esm({
@@ -6820,7 +7177,7 @@ function zipRead(buf) {
6820
7177
  if (eocd < 0) throw new ZipFormatError("\u627E\u4E0D\u5230 EOCD \u7B7E\u540D");
6821
7178
  const total = r.u16(eocd + 10);
6822
7179
  const centralOffset = r.u32(eocd + 16);
6823
- const decoder2 = new TextDecoder();
7180
+ const decoder3 = new TextDecoder();
6824
7181
  const out = /* @__PURE__ */ new Map();
6825
7182
  let cursor = centralOffset;
6826
7183
  for (let i = 0; i < total; i++) {
@@ -6834,7 +7191,7 @@ function zipRead(buf) {
6834
7191
  const commentLen = r.u16(cursor + 32);
6835
7192
  const localHeaderOffset = r.u32(cursor + 42);
6836
7193
  if (localHeaderOffset + 30 > buf.length) throw new ZipFormatError("\u672C\u5730\u5934\u504F\u79FB\u8D8A\u754C");
6837
- const name = decoder2.decode(r.slice(cursor + 46, nameLen));
7194
+ const name = decoder3.decode(r.slice(cursor + 46, nameLen));
6838
7195
  const localNameLen = r.u16(localHeaderOffset + 26);
6839
7196
  const localExtraLen = r.u16(localHeaderOffset + 28);
6840
7197
  const dataStart = localHeaderOffset + 30 + localNameLen + localExtraLen;
@@ -6892,75 +7249,6 @@ var init_zip = __esm({
6892
7249
  }
6893
7250
  });
6894
7251
 
6895
- // packages/cli/src/export/client.ts
6896
- var client_exports2 = {};
6897
- __export(client_exports2, {
6898
- createExportApiClient: () => createExportApiClient
6899
- });
6900
- import { writeFile as writeFile7 } from "node:fs/promises";
6901
- function toExportJob(view) {
6902
- return {
6903
- id: view.id,
6904
- status: view.status,
6905
- progress: view.progress,
6906
- createdAt: view.createdAt,
6907
- ...view.stage === void 0 ? {} : { stage: view.stage },
6908
- ...view.error === void 0 ? {} : { error: view.error },
6909
- ...view.downloadUrl === void 0 ? {} : { downloadUrl: view.downloadUrl },
6910
- ...view.bundleSize === void 0 ? {} : { bundleSize: view.bundleSize },
6911
- ...view.completedAt === void 0 ? {} : { completedAt: view.completedAt }
6912
- };
6913
- }
6914
- async function createExportApiClient(paths) {
6915
- const client = await createClient(paths);
6916
- return {
6917
- async triggerExport(projectId, options) {
6918
- const view = await client.request(
6919
- `/api/v1/projects/${encodeURIComponent(projectId)}/export`,
6920
- {
6921
- method: "POST",
6922
- body: {
6923
- withData: options.withData,
6924
- withSource: options.withSource,
6925
- ...options.withoutSource === true ? { withoutSource: true } : {}
6926
- }
6927
- },
6928
- "EXPORT_TRIGGER_FAILED"
6929
- );
6930
- return toExportJob(view);
6931
- },
6932
- async getJobStatus(jobId) {
6933
- const view = await client.request(
6934
- `/api/v1/exports/${encodeURIComponent(jobId)}`,
6935
- {},
6936
- "EXPORT_STATUS_FAILED"
6937
- );
6938
- return toExportJob(view);
6939
- },
6940
- async downloadBundle(jobId, outputPath) {
6941
- const download = await client.request(
6942
- `/api/v1/exports/${encodeURIComponent(jobId)}/download`,
6943
- {},
6944
- "EXPORT_DOWNLOAD_FAILED"
6945
- );
6946
- if (download.downloadUrl.length === 0) {
6947
- throw new CliError("EXPORT_BUNDLE_UNAVAILABLE", "\u5BFC\u51FA\u4EA7\u7269\u4E0B\u8F7D URL \u4E3A\u7A7A\uFF0C\u4EA7\u7269\u53EF\u80FD\u5C1A\u4E0D\u53EF\u7528");
6948
- }
6949
- const response = await client.download(download.downloadUrl, "EXPORT_DOWNLOAD_FAILED");
6950
- const bytes = Buffer.from(await response.arrayBuffer());
6951
- await writeFile7(outputPath, bytes);
6952
- return { path: outputPath, size: bytes.length };
6953
- }
6954
- };
6955
- }
6956
- var init_client2 = __esm({
6957
- "packages/cli/src/export/client.ts"() {
6958
- "use strict";
6959
- init_auth();
6960
- init_client();
6961
- }
6962
- });
6963
-
6964
7252
  // packages/cli/src/serve/banner.ts
6965
7253
  function isLoopback(host) {
6966
7254
  return host === "127.0.0.1" || host === "localhost" || host === "::1" || host === "[::1]";
@@ -7029,6 +7317,58 @@ var init_banner = __esm({
7029
7317
  }
7030
7318
  });
7031
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
+
7032
7372
  // shared/sdk/template-params.ts
7033
7373
  function extractTemplateFields(root) {
7034
7374
  if (root === null || typeof root !== "object") {
@@ -7155,8 +7495,8 @@ var init_template_params = __esm({
7155
7495
  });
7156
7496
 
7157
7497
  // packages/cli/src/serve/template-params.ts
7158
- import { readFile as readFile17 } from "node:fs/promises";
7159
- import { join as join22 } from "node:path";
7498
+ import { readFile as readFile20 } from "node:fs/promises";
7499
+ import { join as join28 } from "node:path";
7160
7500
  import { parse as parse3 } from "yaml";
7161
7501
  function mergeTemplateEnvSource(source) {
7162
7502
  return { ...source.processEnv, ...source.dotenv, ...source.dotenvLocal };
@@ -7164,7 +7504,7 @@ function mergeTemplateEnvSource(source) {
7164
7504
  async function loadTemplateFields(cwd) {
7165
7505
  let text;
7166
7506
  try {
7167
- text = await readFile17(join22(cwd, TEMPLATE_PARAMS_FILE), "utf8");
7507
+ text = await readFile20(join28(cwd, TEMPLATE_PARAMS_FILE), "utf8");
7168
7508
  } catch {
7169
7509
  return null;
7170
7510
  }
@@ -7180,7 +7520,7 @@ async function loadTemplateFields(cwd) {
7180
7520
  return extractTemplateFields(root);
7181
7521
  }
7182
7522
  async function readDotenvFile(cwd, name) {
7183
- const text = await readFile17(join22(cwd, name), "utf8").catch(() => "");
7523
+ const text = await readFile20(join28(cwd, name), "utf8").catch(() => "");
7184
7524
  if (text === "") return {};
7185
7525
  return parseEnvFile(text);
7186
7526
  }
@@ -7235,8 +7575,8 @@ __export(server_exports, {
7235
7575
  });
7236
7576
  import { createServer as createServer2 } from "node:http";
7237
7577
  import { watch as watch2 } from "node:fs";
7238
- import { mkdir as mkdir12, readFile as readFile18, stat as stat12 } from "node:fs/promises";
7239
- import { extname, join as join23, relative as relative4, resolve as resolve12 } from "node:path";
7578
+ import { mkdir as mkdir14, readFile as readFile21, stat as stat12 } from "node:fs/promises";
7579
+ import { extname, join as join29, relative as relative4, resolve as resolve12 } from "node:path";
7240
7580
  function envNumber(name) {
7241
7581
  const raw = process.env[name];
7242
7582
  if (raw === void 0 || raw.trim() === "") return void 0;
@@ -7269,8 +7609,7 @@ async function startServeServer(options) {
7269
7609
  ...options.dbFile === void 0 ? {} : { dbFile: options.dbFile }
7270
7610
  });
7271
7611
  const config2 = await loadConfig(cwd);
7272
- const functionsDir = join23(cwd, config2.functionsDir);
7273
- const bearerUser = bearerUserResolverFromEnv();
7612
+ const functionsDir = join29(cwd, config2.functionsDir);
7274
7613
  let hasStatic = false;
7275
7614
  try {
7276
7615
  const publicStat = await stat12(staticDir);
@@ -7281,9 +7620,10 @@ async function startServeServer(options) {
7281
7620
  const loadFunctionFiles = async () => mergeSharedIntoFunctions(await collectFunctions(functionsDir));
7282
7621
  let files = await loadFunctionFiles();
7283
7622
  let functionNames = listFunctionNames(files);
7284
- const envText = await readFile18(join23(cwd, ".env.local"), "utf8").catch(() => "");
7623
+ const envText = await readFile21(join29(cwd, ".env.local"), "utf8").catch(() => "");
7285
7624
  let env = parseEnvFile(envText);
7286
7625
  let simEnv = await loadSimEnv(cwd).catch(() => ({}));
7626
+ let bearerUser = bearerUserResolverFromEnv(simEnv);
7287
7627
  const dotenvFile = await readDotenvFile(cwd, ".env");
7288
7628
  let templateEnv;
7289
7629
  try {
@@ -7322,21 +7662,35 @@ async function startServeServer(options) {
7322
7662
  log
7323
7663
  });
7324
7664
  }
7665
+ const fetchConfig = resolveLocalFetchConfig(simEnv);
7325
7666
  const executor = new WorkerFunctionExecutor({
7326
- deps: { rootDir: cwd, builtin: LOCAL_BUILTIN_DEPS }
7667
+ deps: { rootDir: cwd, builtin: LOCAL_BUILTIN_DEPS },
7668
+ ...fetchConfig === void 0 ? {} : { fetch: fetchConfig }
7327
7669
  });
7670
+ if (fetchConfig !== void 0) {
7671
+ log(
7672
+ `[adep] \u53D7\u63A7 fetch \u5DF2\u6CE8\u5165\uFF08FUNCTIONS_FETCH_ALLOWLIST\uFF09\uFF1A\u767D\u540D\u5355 ${fetchConfig.allowlist.length} \u9879\uFF0C\u8D85\u65F6 ${fetchConfig.timeoutMs}ms`
7673
+ );
7674
+ }
7328
7675
  const dbBundle = runtime.bundle;
7329
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
+ });
7330
7683
  let stopWatch;
7331
7684
  if (options.watch === true) {
7332
7685
  const reload = async () => {
7333
7686
  const [nextFiles, envLocalText] = await Promise.all([
7334
7687
  loadFunctionFiles(),
7335
- readFile18(join23(cwd, ".env.local"), "utf8").catch(() => "")
7688
+ readFile21(join29(cwd, ".env.local"), "utf8").catch(() => "")
7336
7689
  ]);
7337
7690
  files = nextFiles;
7338
7691
  env = parseEnvFile(envLocalText);
7339
7692
  simEnv = await loadSimEnv(cwd).catch(() => ({}));
7693
+ bearerUser = bearerUserResolverFromEnv(simEnv);
7340
7694
  invokeHandler = createSimInvokeHandler({ executor, files });
7341
7695
  functionNames = listFunctionNames(files);
7342
7696
  log(`[serve] \u70ED\u91CD\u8F7D\uFF1A\u68C0\u6D4B\u5230\u53D8\u66F4\uFF0C\u5DF2\u91CD\u65B0\u52A0\u8F7D ${functionNames.length} \u4E2A\u51FD\u6570`);
@@ -7349,7 +7703,7 @@ async function startServeServer(options) {
7349
7703
  void reload();
7350
7704
  }, 120);
7351
7705
  };
7352
- await mkdir12(functionsDir, { recursive: true }).catch(() => void 0);
7706
+ await mkdir14(functionsDir, { recursive: true }).catch(() => void 0);
7353
7707
  try {
7354
7708
  watchers.push(watch2(functionsDir, { recursive: true }, scheduleReload));
7355
7709
  } catch {
@@ -7367,7 +7721,7 @@ async function startServeServer(options) {
7367
7721
  const buildInput = async (fnName, entry, url2, req) => {
7368
7722
  const hasEnv = Object.keys(env).length > 0 || Object.keys(simEnv).length > 0 || Object.keys(config2.environment ?? {}).length > 0;
7369
7723
  const mergedEnv = { ...config2.environment, ...simEnv, ...env };
7370
- const request = await requestInput(url2, req, bodyOf);
7724
+ const request = await requestInput(url2, req, bodyWithFiles);
7371
7725
  if (bearerUser !== void 0) request.user = await bearerUser(request.headers);
7372
7726
  return {
7373
7727
  project: { id: "local", slug: config2.name },
@@ -7404,31 +7758,31 @@ async function startServeServer(options) {
7404
7758
  const serveStatic = async (pathname, res) => {
7405
7759
  if (!hasStatic) return false;
7406
7760
  const safePath = pathname.replace(/\.\.\//g, "").replace(/^\//, "");
7407
- const filePath = join23(staticDir, safePath);
7408
- const resolvedPath = safePath === "" || safePath === "/" ? join23(filePath, "index.html") : filePath;
7761
+ const filePath = join29(staticDir, safePath);
7762
+ const resolvedPath = safePath === "" || safePath === "/" ? join29(filePath, "index.html") : filePath;
7409
7763
  try {
7410
7764
  const fileStat = await stat12(resolvedPath);
7411
7765
  if (fileStat.isDirectory()) {
7412
- const indexPath = join23(resolvedPath, "index.html");
7766
+ const indexPath = join29(resolvedPath, "index.html");
7413
7767
  try {
7414
7768
  const indexStat = await stat12(indexPath);
7415
7769
  if (indexStat.isFile()) {
7416
- sendStaticFile(res, indexPath, await readFile18(indexPath));
7770
+ sendStaticFile(res, indexPath, await readFile21(indexPath));
7417
7771
  return true;
7418
7772
  }
7419
7773
  } catch {
7420
7774
  }
7421
7775
  return false;
7422
7776
  }
7423
- sendStaticFile(res, resolvedPath, await readFile18(resolvedPath));
7777
+ sendStaticFile(res, resolvedPath, await readFile21(resolvedPath));
7424
7778
  return true;
7425
7779
  } catch {
7426
7780
  if (options.spaFallback === true) {
7427
7781
  const ext = extname(pathname);
7428
7782
  if (ext === "" || ext === ".html") {
7429
7783
  try {
7430
- const indexContent = await readFile18(join23(staticDir, "index.html"));
7431
- sendStaticFile(res, join23(staticDir, "index.html"), indexContent);
7784
+ const indexContent = await readFile21(join29(staticDir, "index.html"));
7785
+ sendStaticFile(res, join29(staticDir, "index.html"), indexContent);
7432
7786
  return true;
7433
7787
  } catch {
7434
7788
  }
@@ -7511,15 +7865,16 @@ async function startServeServer(options) {
7511
7865
  });
7512
7866
  return;
7513
7867
  }
7868
+ await stalenessGuard?.check();
7514
7869
  const entry = resolveFunctionEntry(files, fnName);
7515
7870
  if (entry === void 0) {
7516
7871
  log(`[serve] ${req.method ?? "GET"} ${pathname} -> 404\uFF08\u51FD\u6570\u4E0D\u5B58\u5728\uFF09`);
7517
7872
  writeJson(res, 404, { error: { code: "FN_NOT_FOUND", message: `\u51FD\u6570 "${fnName}" \u4E0D\u5B58\u5728` } });
7518
7873
  return;
7519
7874
  }
7520
- const input2 = await buildInput(fnName, entry, url2, req);
7521
7875
  const startedAt = performance.now();
7522
7876
  try {
7877
+ const input2 = await buildInput(fnName, entry, url2, req);
7523
7878
  const result = await executor.execute(input2);
7524
7879
  const durationMs = Math.round(performance.now() - startedAt);
7525
7880
  if (options.watch === true) {
@@ -7656,9 +8011,11 @@ var init_server = __esm({
7656
8011
  init_runtime();
7657
8012
  init_storage();
7658
8013
  init_env();
8014
+ init_fetch_config();
7659
8015
  init_invoke();
7660
8016
  init_dev();
7661
8017
  init_banner();
8018
+ init_staleness();
7662
8019
  init_template_params2();
7663
8020
  init_adep_env_inject();
7664
8021
  init_template_params();
@@ -7688,6 +8045,20 @@ var init_server = __esm({
7688
8045
  }
7689
8046
  });
7690
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
+
7691
8062
  // packages/cli/src/deploy.ts
7692
8063
  var deploy_exports = {};
7693
8064
  __export(deploy_exports, {
@@ -7696,9 +8067,8 @@ __export(deploy_exports, {
7696
8067
  collectShared: () => collectShared,
7697
8068
  deploy: () => deploy
7698
8069
  });
7699
- import { createHash as createHash4 } from "node:crypto";
7700
- import { readdir as readdir8, readFile as readFile19 } from "node:fs/promises";
7701
- import { join as join24, resolve as resolve13, basename as basename4, relative as relative5, sep } from "node:path";
8070
+ import { readdir as readdir9, readFile as readFile22 } from "node:fs/promises";
8071
+ import { join as join30, resolve as resolve13, basename as basename4, relative as relative5, sep } from "node:path";
7702
8072
  function functionUrlBase(prefix) {
7703
8073
  const raw = (prefix ?? "/api").trim();
7704
8074
  const normalized = raw === "/" ? "/" : raw.replace(/\/+$/, "");
@@ -7710,7 +8080,7 @@ function isRuntimeSource2(name) {
7710
8080
  async function collectFunctionFiles(functionsDir) {
7711
8081
  let dirents;
7712
8082
  try {
7713
- dirents = await readdir8(functionsDir, { withFileTypes: true });
8083
+ dirents = await readdir9(functionsDir, { withFileTypes: true });
7714
8084
  } catch {
7715
8085
  return {};
7716
8086
  }
@@ -7724,10 +8094,10 @@ async function collectFunctionFiles(functionsDir) {
7724
8094
  if (conflicting.length > 0) throw new AmbiguousFunctionError(functionsDir, conflicting);
7725
8095
  const out = {};
7726
8096
  for (const name of flatNames) {
7727
- out[name] = { [`${name}.ts`]: await readFile19(join24(functionsDir, `${name}.ts`), "utf8") };
8097
+ out[name] = { [`${name}.ts`]: await readFile22(join30(functionsDir, `${name}.ts`), "utf8") };
7728
8098
  }
7729
8099
  for (const name of dirNames) {
7730
- const files = await collectFunctionDir(join24(functionsDir, name));
8100
+ const files = await collectFunctionDir(join30(functionsDir, name));
7731
8101
  if (files["index.ts"] === void 0) continue;
7732
8102
  out[name] = files;
7733
8103
  }
@@ -7738,7 +8108,7 @@ async function collectFunctionDir(absDir) {
7738
8108
  const walk = async (dir, prefix) => {
7739
8109
  let entries;
7740
8110
  try {
7741
- entries = await readdir8(dir, { withFileTypes: true });
8111
+ entries = await readdir9(dir, { withFileTypes: true });
7742
8112
  } catch {
7743
8113
  return;
7744
8114
  }
@@ -7746,39 +8116,36 @@ async function collectFunctionDir(absDir) {
7746
8116
  const rel = prefix === "" ? entry.name : `${prefix}/${entry.name}`;
7747
8117
  if (entry.isDirectory()) {
7748
8118
  if (entry.name === "__tests__" || IGNORED_DIRS.has(entry.name)) continue;
7749
- await walk(join24(dir, entry.name), rel);
8119
+ await walk(join30(dir, entry.name), rel);
7750
8120
  continue;
7751
8121
  }
7752
8122
  if (!isRuntimeSource2(entry.name)) continue;
7753
- files[rel] = await readFile19(join24(dir, entry.name), "utf8");
8123
+ files[rel] = await readFile22(join30(dir, entry.name), "utf8");
7754
8124
  }
7755
8125
  };
7756
8126
  await walk(absDir, "");
7757
8127
  return files;
7758
8128
  }
7759
- function sha256Hex(content) {
7760
- return createHash4("sha256").update(content).digest("hex");
7761
- }
7762
8129
  async function collectShared(functionsDir) {
7763
- const sharedDir = join24(functionsDir, FUNCTION_SHARED_DIR);
8130
+ const sharedDir = join30(functionsDir, FUNCTION_SHARED_DIR);
7764
8131
  const files = {};
7765
8132
  const walk = async (dir) => {
7766
8133
  let entries;
7767
8134
  try {
7768
- entries = await readdir8(dir, { withFileTypes: true });
8135
+ entries = await readdir9(dir, { withFileTypes: true });
7769
8136
  } catch {
7770
8137
  return;
7771
8138
  }
7772
8139
  for (const entry of entries) {
7773
8140
  if (entry.isDirectory()) {
7774
8141
  if (entry.name === "__tests__" || entry.name === "node_modules") continue;
7775
- await walk(join24(dir, entry.name));
8142
+ await walk(join30(dir, entry.name));
7776
8143
  continue;
7777
8144
  }
7778
8145
  if (!isRuntimeSource2(entry.name)) continue;
7779
- const full = join24(dir, entry.name);
8146
+ const full = join30(dir, entry.name);
7780
8147
  const rel = relative5(sharedDir, full).split(sep).join("/");
7781
- files[`${SHARED_SOURCE_ROOT}${rel}`] = await readFile19(full, "utf8");
8148
+ files[`${SHARED_SOURCE_ROOT}${rel}`] = await readFile22(full, "utf8");
7782
8149
  }
7783
8150
  };
7784
8151
  await walk(sharedDir);
@@ -7790,7 +8157,7 @@ async function deploy(paths, options) {
7790
8157
  const cwd = resolve13(options.cwd);
7791
8158
  const config2 = await loadConfig(cwd);
7792
8159
  const slug = options.slug ?? config2.name;
7793
- const functionsDir = options.functionsDir === void 0 ? join24(cwd, config2.functionsDir) : resolve13(cwd, options.functionsDir);
8160
+ const functionsDir = options.functionsDir === void 0 ? join30(cwd, config2.functionsDir) : resolve13(cwd, options.functionsDir);
7794
8161
  const local = await collectFunctionFiles(functionsDir);
7795
8162
  if (Object.keys(local).length === 0) {
7796
8163
  throw new CliError("NO_FUNCTIONS", `${functionsDir} \u4E0B\u6CA1\u6709\u51FD\u6570\u6587\u4EF6`);
@@ -7894,6 +8261,7 @@ var init_deploy = __esm({
7894
8261
  init_function_source();
7895
8262
  init_auth();
7896
8263
  init_client();
8264
+ init_hash();
7897
8265
  init_dev();
7898
8266
  init_net();
7899
8267
  init_shared_source();
@@ -7921,8 +8289,8 @@ __export(storage_exports, {
7921
8289
  storageRemove: () => storageRemove,
7922
8290
  storageUpload: () => storageUpload
7923
8291
  });
7924
- import { mkdir as mkdir13, readFile as readFile20, stat as stat13, writeFile as writeFile11 } from "node:fs/promises";
7925
- import { basename as basename5, dirname as dirname13, extname as extname2, join as join25, 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";
7926
8294
  function envQuery2(options) {
7927
8295
  return options.environment === void 0 ? "" : `?environment=${options.environment}`;
7928
8296
  }
@@ -7967,7 +8335,7 @@ async function storageUpload(paths, options) {
7967
8335
  throw new CliError("FILE_NOT_FOUND", `\u672C\u5730\u6587\u4EF6\u4E0D\u5B58\u5728\uFF1A${local}`);
7968
8336
  }
7969
8337
  const visibility = options.visibility ?? "private";
7970
- const bytes = await readFile20(local);
8338
+ const bytes = await readFile23(local);
7971
8339
  const form = new FormData();
7972
8340
  form.set("path", options.path);
7973
8341
  form.set("visibility", visibility);
@@ -8014,9 +8382,9 @@ async function storageDownload(paths, options) {
8014
8382
  const url2 = await resolveDownloadUrl(client, project2, options.path, options.environment);
8015
8383
  const response = await client.download(url2, "STORAGE_DOWNLOAD_FAILED");
8016
8384
  const bytes = Buffer.from(await response.arrayBuffer());
8017
- const output2 = resolve14(options.output ?? join25(resolve14(options.cwd), basename5(options.path)));
8018
- await mkdir13(dirname13(output2), { recursive: true });
8019
- await writeFile11(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);
8020
8388
  return { path: options.path, output: output2, size: bytes.length };
8021
8389
  }
8022
8390
  async function storageRemove(paths, options) {
@@ -8042,8 +8410,9 @@ __export(hosting_exports, {
8042
8410
  hostingInfo: () => hostingInfo,
8043
8411
  hostingPull: () => hostingPull
8044
8412
  });
8045
- import { readdir as readdir9, readFile as readFile21, stat as stat14 } from "node:fs/promises";
8046
- import { dirname as dirname14, join as join26, relative as relative6, resolve as resolve15, sep as sep2 } from "node:path";
8413
+ import { readdir as readdir10, readFile as readFile24, stat as stat14 } from "node:fs/promises";
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";
8047
8416
  async function open5(paths, options) {
8048
8417
  const client = await createClient(paths);
8049
8418
  const project2 = await resolveSlug(resolve15(options.cwd), options.slug);
@@ -8064,12 +8433,12 @@ async function collectSiteFiles(dir) {
8064
8433
  const walk = async (sub) => {
8065
8434
  let entries;
8066
8435
  try {
8067
- entries = await readdir9(sub, { withFileTypes: true });
8436
+ entries = await readdir10(sub, { withFileTypes: true });
8068
8437
  } catch {
8069
8438
  return;
8070
8439
  }
8071
8440
  for (const entry of entries) {
8072
- const full = join26(sub, entry.name);
8441
+ const full = join32(sub, entry.name);
8073
8442
  if (entry.isDirectory()) {
8074
8443
  await walk(full);
8075
8444
  } else if (entry.isFile()) {
@@ -8085,25 +8454,70 @@ async function hostingDeploy(paths, options) {
8085
8454
  const { client, project: project2 } = await open5(paths, options);
8086
8455
  const log = options.log ?? ((line) => process.stdout.write(`${line}
8087
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
+ }
8088
8471
  const files = await collectSiteFiles(options.dir);
8089
8472
  if (files.size === 0) {
8090
8473
  throw new CliError("NO_SITE_FILES", `\u7AD9\u70B9\u76EE\u5F55\u4E3A\u7A7A\uFF1A${resolve15(options.dir)}`);
8091
8474
  }
8092
- const uploaded = [];
8475
+ let newestMtimeMs = 0;
8476
+ const localEntries = /* @__PURE__ */ new Map();
8093
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
+ }
8094
8505
  log(`[adep] \u4E0A\u4F20 site/${rel}`);
8095
- const info2 = await stat14(full);
8096
- const bytes = await readFile21(full);
8097
8506
  const form = new FormData();
8098
8507
  form.set("path", `site/${rel}`);
8099
8508
  form.set("visibility", "public");
8100
8509
  form.set(
8101
8510
  "file",
8102
- new Blob([bytes], { type: contentTypeOf(rel) }),
8511
+ new Blob([local.bytes], { type: contentTypeOf(rel) }),
8103
8512
  rel.split("/").pop()
8104
8513
  );
8105
8514
  await client.upload(`/api/v1/projects/${project2}/files`, form, "HOSTING_UPLOAD_FAILED");
8106
- 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");
8107
8521
  }
8108
8522
  const config2 = await client.request(
8109
8523
  `/api/v1/projects/${project2}/hosting`,
@@ -8113,7 +8527,7 @@ async function hostingDeploy(paths, options) {
8113
8527
  }
8114
8528
  );
8115
8529
  const info = await hostingInfo(paths, options);
8116
- return { config: config2.config, siteUrl: info.siteUrl, uploaded };
8530
+ return { config: config2.config, siteUrl: info.siteUrl, uploaded, reused, identical, builtAt };
8117
8531
  }
8118
8532
  async function hostingPull(paths, options) {
8119
8533
  const { client } = await open5(paths, options);
@@ -8121,7 +8535,7 @@ async function hostingPull(paths, options) {
8121
8535
  `));
8122
8536
  const info = await hostingInfo(paths, options);
8123
8537
  const outputDir = resolve15(options.output ?? resolve15(options.cwd));
8124
- const { mkdir: mkdir15, writeFile: writeFile13 } = await import("node:fs/promises");
8538
+ const { mkdir: mkdir17, writeFile: writeFile17 } = await import("node:fs/promises");
8125
8539
  const files = [];
8126
8540
  for (const entry of info.files) {
8127
8541
  if (entry.visibility !== "public" || entry.path === HOSTING_CONFIG_PATH) continue;
@@ -8131,9 +8545,9 @@ async function hostingPull(paths, options) {
8131
8545
  const response = await client.download(url2, "HOSTING_DOWNLOAD_FAILED");
8132
8546
  const bytes = Buffer.from(await response.arrayBuffer());
8133
8547
  const rel = entry.path.replace(/^site\//, "");
8134
- const target = join26(outputDir, ...rel.split("/"));
8135
- await mkdir15(dirname14(target), { recursive: true });
8136
- await writeFile13(target, bytes);
8548
+ const target = join32(outputDir, ...rel.split("/"));
8549
+ await mkdir17(dirname13(target), { recursive: true });
8550
+ await writeFile17(target, bytes);
8137
8551
  files.push({ path: entry.path, size: bytes.length });
8138
8552
  }
8139
8553
  return { siteUrl: info.siteUrl, outputDir, files };
@@ -8155,6 +8569,7 @@ var init_hosting = __esm({
8155
8569
  "use strict";
8156
8570
  init_client();
8157
8571
  init_auth();
8572
+ init_hash();
8158
8573
  init_storage2();
8159
8574
  HOSTING_CONFIG_PATH = "site/.hosting.json";
8160
8575
  }
@@ -8187,22 +8602,22 @@ __export(frontend_exports, {
8187
8602
  frontendSync: () => frontendSync,
8188
8603
  isStaticFrontendDir: () => isStaticFrontendDir
8189
8604
  });
8190
- import { readdir as readdir10, readFile as readFile22, stat as stat15 } from "node:fs/promises";
8191
- import { join as join27, relative as relative7, sep as sep3 } from "node:path";
8605
+ import { readdir as readdir11, readFile as readFile25, stat as stat15 } from "node:fs/promises";
8606
+ import { join as join33, relative as relative7, sep as sep3 } from "node:path";
8192
8607
  async function collectFiles(root, dir) {
8193
8608
  const files = /* @__PURE__ */ new Map();
8194
8609
  const skipped = [];
8195
- const entries = await readdir10(dir, { withFileTypes: true });
8610
+ const entries = await readdir11(dir, { withFileTypes: true });
8196
8611
  for (const entry of entries) {
8197
8612
  if (entry.isDirectory()) {
8198
8613
  if (IGNORED_DIRS2.has(entry.name)) continue;
8199
- const nested = await collectFiles(root, join27(dir, entry.name));
8614
+ const nested = await collectFiles(root, join33(dir, entry.name));
8200
8615
  for (const [path, content] of nested.files) files.set(path, content);
8201
8616
  skipped.push(...nested.skipped);
8202
8617
  continue;
8203
8618
  }
8204
8619
  if (IGNORED_FILES.has(entry.name)) continue;
8205
- const full = join27(dir, entry.name);
8620
+ const full = join33(dir, entry.name);
8206
8621
  const rel = relative7(root, full).split(sep3).join("/");
8207
8622
  const info = await stat15(full);
8208
8623
  if (info.size > 1024 * 1024) {
@@ -8210,7 +8625,7 @@ async function collectFiles(root, dir) {
8210
8625
  continue;
8211
8626
  }
8212
8627
  try {
8213
- const content = await readFile22(full, "utf8");
8628
+ const content = await readFile25(full, "utf8");
8214
8629
  if (content.includes("\0")) {
8215
8630
  skipped.push(rel);
8216
8631
  continue;
@@ -8225,7 +8640,7 @@ async function collectFiles(root, dir) {
8225
8640
  async function frontendSync(paths, options) {
8226
8641
  const log = options.silent === true ? () => void 0 : options.log ?? ((line) => process.stdout.write(`${line}
8227
8642
  `));
8228
- const webDir = options.dir ?? join27(options.cwd, "web");
8643
+ const webDir = options.dir ?? join33(options.cwd, "web");
8229
8644
  const rootStat = await stat15(webDir).catch(() => null);
8230
8645
  if (rootStat === null || !rootStat.isDirectory()) {
8231
8646
  throw new CliError(
@@ -8285,14 +8700,14 @@ function declaresBuildScript(pkgJson) {
8285
8700
  return typeof build === "string" && build.trim().length > 0;
8286
8701
  }
8287
8702
  async function isStaticFrontendDir(dir) {
8288
- const pkg = await readFile22(join27(dir, "package.json"), "utf8").catch(() => void 0);
8703
+ const pkg = await readFile25(join33(dir, "package.json"), "utf8").catch(() => void 0);
8289
8704
  if (declaresBuildScript(pkg)) return false;
8290
8705
  const walk = async (sub) => {
8291
- const entries = await readdir10(sub, { withFileTypes: true });
8706
+ const entries = await readdir11(sub, { withFileTypes: true });
8292
8707
  for (const entry of entries) {
8293
8708
  if (entry.isDirectory()) {
8294
8709
  if (IGNORED_DIRS2.has(entry.name)) continue;
8295
- if (!await walk(join27(sub, entry.name))) return false;
8710
+ if (!await walk(join33(sub, entry.name))) return false;
8296
8711
  continue;
8297
8712
  }
8298
8713
  if (FRONTEND_TRANSFORM_EXTENSIONS.some((ext) => entry.name.endsWith(ext))) return false;
@@ -8328,12 +8743,12 @@ var fs_exports = {};
8328
8743
  __export(fs_exports, {
8329
8744
  createExportFileSystem: () => createExportFileSystem
8330
8745
  });
8331
- import { mkdir as mkdir14, readFile as readFile24, rm as rm5, stat as stat17, writeFile as writeFile12 } from "node:fs/promises";
8332
- import { dirname as dirname15, join as join30 } 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";
8333
8748
  function createExportFileSystem() {
8334
8749
  return {
8335
- readFile: (path) => readFile24(path),
8336
- writeFile: (path, content) => writeFile12(path, content),
8750
+ readFile: (path) => readFile27(path),
8751
+ writeFile: (path, content) => writeFile16(path, content),
8337
8752
  // 同时用于清理解压临时目录(${zip}.tmp 是个目录)——递归强制删除,缺失不报错。
8338
8753
  deleteFile: async (path) => {
8339
8754
  await rm5(path, { recursive: true, force: true });
@@ -8347,14 +8762,14 @@ function createExportFileSystem() {
8347
8762
  }
8348
8763
  },
8349
8764
  mkdir: async (path) => {
8350
- await mkdir14(path, { recursive: true });
8765
+ await mkdir16(path, { recursive: true });
8351
8766
  },
8352
8767
  unzip: async (zipPath, targetDir) => {
8353
- const entries = zipRead(await readFile24(zipPath));
8768
+ const entries = zipRead(await readFile27(zipPath));
8354
8769
  for (const [name, data] of entries) {
8355
- const dest = join30(targetDir, name);
8356
- await mkdir14(dirname15(dest), { recursive: true });
8357
- await writeFile12(dest, data);
8770
+ const dest = join36(targetDir, name);
8771
+ await mkdir16(dirname14(dest), { recursive: true });
8772
+ await writeFile16(dest, data);
8358
8773
  }
8359
8774
  }
8360
8775
  };
@@ -8598,8 +9013,8 @@ ${detail}`);
8598
9013
  });
8599
9014
 
8600
9015
  // packages/cli/src/sandbox-scan.ts
8601
- import { readdir as readdir12, readFile as readFile25 } from "node:fs/promises";
8602
- import { join as join31, relative as relative9, sep as sep5 } from "node:path";
9016
+ import { readdir as readdir13, readFile as readFile28 } from "node:fs/promises";
9017
+ import { join as join37, relative as relative9, sep as sep5 } from "node:path";
8603
9018
  function extractSpecifiers(line) {
8604
9019
  const out = [];
8605
9020
  const patterns = [
@@ -8643,17 +9058,17 @@ function classify(specifier) {
8643
9058
  return null;
8644
9059
  }
8645
9060
  async function scanFunctionSources(rootDir, functionsDir) {
8646
- const base = join31(rootDir, functionsDir);
9061
+ const base = join37(rootDir, functionsDir);
8647
9062
  const findings = [];
8648
9063
  async function walk(current) {
8649
9064
  let entries;
8650
9065
  try {
8651
- entries = await readdir12(current, { withFileTypes: true });
9066
+ entries = await readdir13(current, { withFileTypes: true });
8652
9067
  } catch {
8653
9068
  return;
8654
9069
  }
8655
9070
  for (const entry of entries) {
8656
- const abs = join31(current, entry.name);
9071
+ const abs = join37(current, entry.name);
8657
9072
  if (entry.isDirectory()) {
8658
9073
  if (SKIP_DIRS.has(entry.name)) continue;
8659
9074
  await walk(abs);
@@ -8664,7 +9079,7 @@ async function scanFunctionSources(rootDir, functionsDir) {
8664
9079
  if (entry.name.endsWith(".d.ts")) continue;
8665
9080
  let content;
8666
9081
  try {
8667
- content = await readFile25(abs, "utf8");
9082
+ content = await readFile28(abs, "utf8");
8668
9083
  } catch {
8669
9084
  continue;
8670
9085
  }
@@ -8787,6 +9202,7 @@ __export(doctor_exports, {
8787
9202
  runDoctor: () => runDoctor
8788
9203
  });
8789
9204
  import { stat as stat18 } from "node:fs/promises";
9205
+ import { join as join38 } from "node:path";
8790
9206
  async function probeServer(server) {
8791
9207
  const controller = new AbortController();
8792
9208
  const timer = setTimeout(() => controller.abort(), SERVER_PROBE_TIMEOUT_MS);
@@ -8814,14 +9230,15 @@ async function credentialMode(file2) {
8814
9230
  async function runDoctor(paths, cwd = process.cwd()) {
8815
9231
  const credentials = await loadCredentials(paths);
8816
9232
  const server = credentials?.server ?? resolveServer();
8817
- 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);
8818
9235
  const offline = await isOffline();
8819
9236
  const health = await probeServer(server);
8820
9237
  const sandbox = await scanSandbox(cwd);
8821
9238
  const report = {
8822
9239
  server,
8823
9240
  credentials: {
8824
- file: paths.credentialsFile,
9241
+ file: credentialsFile,
8825
9242
  present: credentials !== null,
8826
9243
  ...mode === void 0 ? {} : { mode }
8827
9244
  },
@@ -8833,7 +9250,7 @@ async function runDoctor(paths, cwd = process.cwd()) {
8833
9250
  };
8834
9251
  if (credentials !== null) report.credentials.email = credentials.email;
8835
9252
  if (mode !== void 0 && mode !== "600") {
8836
- 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}`;
8837
9254
  }
8838
9255
  return report;
8839
9256
  }
@@ -9278,12 +9695,12 @@ import { createRequire as createRequire2 } from "node:module";
9278
9695
  init_auth();
9279
9696
 
9280
9697
  // packages/cli/src/init.ts
9281
- import { mkdir as mkdir2, stat as stat2, writeFile } from "node:fs/promises";
9282
- 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";
9283
9700
 
9284
9701
  // packages/cli/src/templates/registry.ts
9285
9702
  import { readFileSync } from "node:fs";
9286
- import { dirname as dirname2, join } from "node:path";
9703
+ import { dirname, join as join2 } from "node:path";
9287
9704
  import { fileURLToPath } from "node:url";
9288
9705
 
9289
9706
  // packages/cli/src/templates/generated.ts
@@ -12668,15 +13085,15 @@ var TEMPLATE_CODES = [
12668
13085
  ];
12669
13086
  var TEMPLATE_NAMES = TEMPLATE_CODES;
12670
13087
  function findCliPackageJson() {
12671
- let dir = dirname2(fileURLToPath(import.meta.url));
13088
+ let dir = dirname(fileURLToPath(import.meta.url));
12672
13089
  for (; ; ) {
12673
- const candidate = join(dir, "package.json");
13090
+ const candidate = join2(dir, "package.json");
12674
13091
  try {
12675
13092
  const pkg = JSON.parse(readFileSync(candidate, "utf8"));
12676
13093
  if (pkg.name === "@adep/cli") return candidate;
12677
13094
  } catch {
12678
13095
  }
12679
- const parent = dirname2(dir);
13096
+ const parent = dirname(dir);
12680
13097
  if (parent === dir) {
12681
13098
  throw new Error("\u627E\u4E0D\u5230 @adep/cli \u7684 package.json\uFF08\u5DF2\u904D\u5386\u5230\u6587\u4EF6\u7CFB\u7EDF\u6839\uFF09");
12682
13099
  }
@@ -12688,10 +13105,10 @@ function cliVersionOf() {
12688
13105
  return pkg.version;
12689
13106
  }
12690
13107
  function cliPackageRoot() {
12691
- return dirname2(findCliPackageJson());
13108
+ return dirname(findCliPackageJson());
12692
13109
  }
12693
13110
  function localTemplateDir(code) {
12694
- return join(cliPackageRoot(), "src", "templates", code);
13111
+ return join2(cliPackageRoot(), "src", "templates", code);
12695
13112
  }
12696
13113
  function templateFiles(code, name) {
12697
13114
  const generated = GENERATED_TEMPLATES[code];
@@ -12752,9 +13169,9 @@ async function initProject(cwd, name, template, filesOverride) {
12752
13169
  await mkdir2(projectPath, { recursive: true });
12753
13170
  await Promise.all(
12754
13171
  files.map(async (file2) => {
12755
- const target = join2(projectPath, file2.path);
12756
- await mkdir2(dirname3(target), { recursive: true });
12757
- 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);
12758
13175
  })
12759
13176
  );
12760
13177
  return { projectPath, files: files.map((file2) => file2.path) };
@@ -12945,7 +13362,8 @@ function registerAuth(program2, ctx) {
12945
13362
  });
12946
13363
  command.ok(result2, (data) => {
12947
13364
  const d = data;
12948
- 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`;
12949
13367
  });
12950
13368
  return;
12951
13369
  }
@@ -12966,7 +13384,8 @@ function registerAuth(program2, ctx) {
12966
13384
  });
12967
13385
  command.ok(result, (data) => {
12968
13386
  const d = data;
12969
- 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`;
12970
13389
  });
12971
13390
  });
12972
13391
  }
@@ -13023,17 +13442,17 @@ async function fetchTemplates(server) {
13023
13442
  // packages/cli/src/template-package.ts
13024
13443
  init_auth();
13025
13444
  init_credentials();
13026
- import { mkdir as mkdir7, readFile as readFile10, readdir as readdir3, stat as stat5, writeFile as writeFile5 } from "node:fs/promises";
13027
- 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";
13028
13447
  function cachedPackagePath(paths, code, version2) {
13029
- return join13(paths.home, "templates", `${code}-${version2}.json`);
13448
+ return join14(paths.home, "templates", `${code}-${version2}.json`);
13030
13449
  }
13031
13450
  async function collectTemplateDir(dir) {
13032
13451
  const files = [];
13033
13452
  async function walk(current, prefix) {
13034
13453
  const entries = await readdir3(current, { withFileTypes: true });
13035
13454
  for (const entry of entries) {
13036
- const full = join13(current, entry.name);
13455
+ const full = join14(current, entry.name);
13037
13456
  const rel = prefix === "" ? entry.name : `${prefix}/${entry.name}`;
13038
13457
  if (entry.isDirectory()) {
13039
13458
  await walk(full, rel);
@@ -13065,8 +13484,8 @@ async function loadCachedPackage(paths, code, version2) {
13065
13484
  return pkg;
13066
13485
  }
13067
13486
  async function saveCachedPackage(paths, pkg) {
13068
- await mkdir7(join13(paths.home, "templates"), { recursive: true });
13069
- 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");
13070
13489
  }
13071
13490
  async function downloadTemplatePackage(server, code) {
13072
13491
  let response;
@@ -13151,7 +13570,7 @@ function packageManifestEntry(pkg) {
13151
13570
  async function assertPublishableTemplate(dir, expectedCode) {
13152
13571
  let info;
13153
13572
  try {
13154
- info = await stat5(join13(dir, "template.json"));
13573
+ info = await stat5(join14(dir, "template.json"));
13155
13574
  } catch {
13156
13575
  throw new CliError(
13157
13576
  "TEMPLATE_NOT_PUBLISHABLE",
@@ -13165,7 +13584,7 @@ async function assertPublishableTemplate(dir, expectedCode) {
13165
13584
  code: expectedCode,
13166
13585
  version: "",
13167
13586
  manifest: {},
13168
- 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") }]
13169
13588
  });
13170
13589
  if (manifest === null) {
13171
13590
  throw new CliError("TEMPLATE_NOT_PUBLISHABLE", `\u76EE\u5F55 ${dir}/template.json \u4E0D\u662F\u5408\u6CD5 JSON`);
@@ -13289,15 +13708,150 @@ function registerTemplates(program2, ctx) {
13289
13708
  import { resolve as resolve10 } from "node:path";
13290
13709
 
13291
13710
  // packages/cli/src/app-build.ts
13292
- init_shared_source();
13293
- init_validate();
13294
- init_zip();
13295
- import { spawn as spawn2 } from "node:child_process";
13296
- import { createHash as createHash2 } from "node:crypto";
13297
- import { closeSync, openSync } from "node:fs";
13298
- import { copyFile, mkdir as mkdir9, mkdtemp, readFile as readFile12, readdir as readdir6, rm as rm3, stat as stat8, writeFile as writeFile8 } from "node:fs/promises";
13299
- import { tmpdir } from "node:os";
13300
- import { basename as basename2, dirname as dirname10, join as join16, posix, relative as relative2, 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";
13713
+
13714
+ // packages/cli/src/app-init.ts
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";
13717
+
13718
+ // packages/cli/src/app-template.ts
13719
+ import { readFileSync as readFileSync3 } from "node:fs";
13720
+ import { readdir as readdir4, readFile as readFile11, stat as stat6 } from "node:fs/promises";
13721
+ import { dirname as dirname7, join as join15 } from "node:path";
13722
+ import { fileURLToPath as fileURLToPath3 } from "node:url";
13723
+ var TEMPLATE_VAR_ALLOWLIST = {
13724
+ "app-desktop": /* @__PURE__ */ new Set(["projectSlug", "appName", "appId", "platformUrl"]),
13725
+ "app-mobile": /* @__PURE__ */ new Set([
13726
+ "projectSlug",
13727
+ "appName",
13728
+ "platformUrl",
13729
+ "iosBundleId",
13730
+ "androidPackageId"
13731
+ ]),
13732
+ // xtool 只做 iOS ⇒ 没有 androidPackageId。少这一个变量是**刻意的**:
13733
+ // 模板里若写了它,渲染期会 fail loud(而不是渲染出一个没有 Android 目标的空值)。
13734
+ "app-mobile-xtool": /* @__PURE__ */ new Set(["projectSlug", "appName", "platformUrl", "iosBundleId"])
13735
+ };
13736
+ function shellTemplateForPlatform(platform) {
13737
+ return platform === "mobile" ? "app-mobile" : "app-desktop";
13738
+ }
13739
+ function normalizeToolchain(input2) {
13740
+ if (input2 === void 0 || input2.length === 0) return "capacitor";
13741
+ if (input2 === "capacitor" || input2 === "xtool") return input2;
13742
+ throw new InitError(
13743
+ "INVALID_TOOLCHAIN",
13744
+ `--toolchain \u987B\u4E3A capacitor | xtool\uFF0C\u6536\u5230 "${input2}"\uFF08\u7F3A\u7701 capacitor\uFF09`
13745
+ );
13746
+ }
13747
+ function shellTemplateFor(platform, toolchain) {
13748
+ if (toolchain === "xtool") {
13749
+ if (platform !== "mobile") {
13750
+ throw new InitError(
13751
+ "INVALID_TOOLCHAIN",
13752
+ `--toolchain xtool \u53EA\u652F\u6301 --platform mobile\uFF08xtool \u4EA7\u51FA iOS \u539F\u751F app\uFF09\uFF0C\u6536\u5230 --platform ${platform}`
13753
+ );
13754
+ }
13755
+ return "app-mobile-xtool";
13756
+ }
13757
+ return shellTemplateForPlatform(platform);
13758
+ }
13759
+ var XTOOL_SHELL_REUSED_FROM_MOBILE = [
13760
+ { from: "plugins/adep-bridge", to: "plugins/adep-bridge" },
13761
+ { from: "web/adep-bridge.js", to: "web/adep-bridge.js" },
13762
+ { from: "web/offline-runtime.js", to: "web/offline-runtime.js" }
13763
+ ];
13764
+ var TEMPLATE_MANIFEST_FILES = /* @__PURE__ */ new Set(["template.json"]);
13765
+ async function collectRelPaths(dir, base) {
13766
+ const entries = await readdir4(dir, { withFileTypes: true });
13767
+ const nested = await Promise.all(
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) => {
13769
+ const abs = join15(dir, entry.name);
13770
+ return entry.isDirectory() ? (
13771
+ // 递归时 base 必须带上子目录前缀,否则深层文件相对路径会丢目录段
13772
+ // (app-mobile 是嵌套目录结构:bridge/gate.mjs、plugins/adep-bridge/...)。
13773
+ collectRelPaths(abs, join15(base, entry.name))
13774
+ ) : Promise.resolve([join15(base, entry.name).split("\\").join("/")]);
13775
+ })
13776
+ );
13777
+ return nested.flat();
13778
+ }
13779
+ async function findCliPackageRoot() {
13780
+ let dir = dirname7(fileURLToPath3(import.meta.url));
13781
+ for (; ; ) {
13782
+ let raw;
13783
+ try {
13784
+ raw = readFileSync3(join15(dir, "package.json"), "utf8");
13785
+ } catch {
13786
+ raw = "";
13787
+ }
13788
+ try {
13789
+ const pkg = JSON.parse(raw);
13790
+ if (pkg.name === "@adep/cli") return dir;
13791
+ } catch {
13792
+ }
13793
+ const parent = dirname7(dir);
13794
+ if (parent === dir) {
13795
+ throw new InitError(
13796
+ "SHELL_TEMPLATE_MISSING",
13797
+ "\u627E\u4E0D\u5230 @adep/cli \u7684 package.json\uFF08\u5DF2\u904D\u5386\u5230\u6587\u4EF6\u7CFB\u7EDF\u6839\uFF09"
13798
+ );
13799
+ }
13800
+ dir = parent;
13801
+ }
13802
+ }
13803
+ async function appShellTemplateDir(code = "app-desktop") {
13804
+ const dir = join15(await findCliPackageRoot(), "templates", code);
13805
+ try {
13806
+ await stat6(dir);
13807
+ } catch {
13808
+ throw new InitError(
13809
+ "SHELL_TEMPLATE_MISSING",
13810
+ `\u58F3\u6A21\u677F\u76EE\u5F55\u7F3A\u5931\uFF1A${dir}\uFF08\u5B89\u88C5\u4EA7\u7269\u5E94\u5305\u542B templates/\uFF0C\u68C0\u67E5 package.json \u7684 files \u5B57\u6BB5\uFF09`
13811
+ );
13812
+ }
13813
+ return dir;
13814
+ }
13815
+ async function renderAppShellTemplate(vars, code = "app-desktop") {
13816
+ const templateDir = await appShellTemplateDir(code);
13817
+ const rels = await collectRelPaths(templateDir, ".");
13818
+ const allowed = TEMPLATE_VAR_ALLOWLIST[code];
13819
+ const values = {
13820
+ projectSlug: vars.projectSlug,
13821
+ appName: vars.appName,
13822
+ platformUrl: vars.platformUrl,
13823
+ // ⚠️ 判据是「desktop 与 mobile 族」而不是「是不是 app-mobile」——`app-mobile-xtool`
13824
+ // 同样要 iosBundleId。原来写成 `code === 'app-mobile' ? ... : { appId }` 时,
13825
+ // 新 code 会落进 else 分支:`{{iosBundleId}}` 取到 `undefined → ''`,
13826
+ // 渲染出一个 **bundle id 为空** 的工程(SwiftPM/xtool 都在更晚的环节才报错)。
13827
+ ...code === "app-desktop" ? { appId: vars.appId ?? "" } : {
13828
+ iosBundleId: vars.iosBundleId ?? "",
13829
+ androidPackageId: vars.androidPackageId ?? ""
13830
+ }
13831
+ };
13832
+ return Promise.all(
13833
+ rels.map(async (rel) => {
13834
+ const raw = await readFile11(join15(templateDir, rel), "utf8");
13835
+ const content = raw.replace(/\{\{\s*([A-Za-z0-9_-]+)\s*\}\}/g, (whole, name) => {
13836
+ if (!allowed.has(name)) {
13837
+ throw new InitError(
13838
+ "SHELL_TEMPLATE_INVALID",
13839
+ `\u58F3\u6A21\u677F ${code} \u7684\u6587\u4EF6 ${rel} \u4F7F\u7528\u4E86\u672A\u652F\u6301\u53D8\u91CF "${whole}"\uFF1A\u5141\u8BB8 ${[...allowed].join(" | ")}`
13840
+ );
13841
+ }
13842
+ return values[name] ?? "";
13843
+ });
13844
+ const leftover = /\{\{\s*[A-Za-z0-9_-]+\s*\}\}/.exec(content);
13845
+ if (leftover !== null) {
13846
+ throw new InitError(
13847
+ "SHELL_TEMPLATE_INVALID",
13848
+ `\u58F3\u6A21\u677F ${code} \u7684\u6587\u4EF6 ${rel} \u6E32\u67D3\u540E\u4ECD\u6709\u672A\u66FF\u6362\u5360\u4F4D\u7B26 "${leftover[0]}"`
13849
+ );
13850
+ }
13851
+ return { path: rel, content };
13852
+ })
13853
+ );
13854
+ }
13301
13855
 
13302
13856
  // node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/classic/external.js
13303
13857
  var external_exports = {};
@@ -33050,148 +33604,6 @@ function parseAdepAppConfig(input2) {
33050
33604
  return parsed.data;
33051
33605
  }
33052
33606
 
33053
- // packages/cli/src/app-init.ts
33054
- import { cp, mkdir as mkdir8, readdir as readdir5, stat as stat7, writeFile as writeFile6 } from "node:fs/promises";
33055
- import { dirname as dirname9, join as join15, resolve as resolve7 } from "node:path";
33056
-
33057
- // packages/cli/src/app-template.ts
33058
- import { readFileSync as readFileSync3 } from "node:fs";
33059
- import { readdir as readdir4, readFile as readFile11, stat as stat6 } from "node:fs/promises";
33060
- import { dirname as dirname8, join as join14 } from "node:path";
33061
- import { fileURLToPath as fileURLToPath3 } from "node:url";
33062
- var TEMPLATE_VAR_ALLOWLIST = {
33063
- "app-desktop": /* @__PURE__ */ new Set(["projectSlug", "appName", "appId", "platformUrl"]),
33064
- "app-mobile": /* @__PURE__ */ new Set([
33065
- "projectSlug",
33066
- "appName",
33067
- "platformUrl",
33068
- "iosBundleId",
33069
- "androidPackageId"
33070
- ]),
33071
- // xtool 只做 iOS ⇒ 没有 androidPackageId。少这一个变量是**刻意的**:
33072
- // 模板里若写了它,渲染期会 fail loud(而不是渲染出一个没有 Android 目标的空值)。
33073
- "app-mobile-xtool": /* @__PURE__ */ new Set(["projectSlug", "appName", "platformUrl", "iosBundleId"])
33074
- };
33075
- function shellTemplateForPlatform(platform) {
33076
- return platform === "mobile" ? "app-mobile" : "app-desktop";
33077
- }
33078
- function normalizeToolchain(input2) {
33079
- if (input2 === void 0 || input2.length === 0) return "capacitor";
33080
- if (input2 === "capacitor" || input2 === "xtool") return input2;
33081
- throw new InitError(
33082
- "INVALID_TOOLCHAIN",
33083
- `--toolchain \u987B\u4E3A capacitor | xtool\uFF0C\u6536\u5230 "${input2}"\uFF08\u7F3A\u7701 capacitor\uFF09`
33084
- );
33085
- }
33086
- function shellTemplateFor(platform, toolchain) {
33087
- if (toolchain === "xtool") {
33088
- if (platform !== "mobile") {
33089
- throw new InitError(
33090
- "INVALID_TOOLCHAIN",
33091
- `--toolchain xtool \u53EA\u652F\u6301 --platform mobile\uFF08xtool \u4EA7\u51FA iOS \u539F\u751F app\uFF09\uFF0C\u6536\u5230 --platform ${platform}`
33092
- );
33093
- }
33094
- return "app-mobile-xtool";
33095
- }
33096
- return shellTemplateForPlatform(platform);
33097
- }
33098
- var XTOOL_SHELL_REUSED_FROM_MOBILE = [
33099
- { from: "plugins/adep-bridge", to: "plugins/adep-bridge" },
33100
- { from: "web/adep-bridge.js", to: "web/adep-bridge.js" },
33101
- { from: "web/offline-runtime.js", to: "web/offline-runtime.js" }
33102
- ];
33103
- var TEMPLATE_MANIFEST_FILES = /* @__PURE__ */ new Set(["template.json"]);
33104
- async function collectRelPaths(dir, base) {
33105
- const entries = await readdir4(dir, { withFileTypes: true });
33106
- const nested = await Promise.all(
33107
- 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) => {
33108
- const abs = join14(dir, entry.name);
33109
- return entry.isDirectory() ? (
33110
- // 递归时 base 必须带上子目录前缀,否则深层文件相对路径会丢目录段
33111
- // (app-mobile 是嵌套目录结构:bridge/gate.mjs、plugins/adep-bridge/...)。
33112
- collectRelPaths(abs, join14(base, entry.name))
33113
- ) : Promise.resolve([join14(base, entry.name).split("\\").join("/")]);
33114
- })
33115
- );
33116
- return nested.flat();
33117
- }
33118
- async function findCliPackageRoot() {
33119
- let dir = dirname8(fileURLToPath3(import.meta.url));
33120
- for (; ; ) {
33121
- let raw;
33122
- try {
33123
- raw = readFileSync3(join14(dir, "package.json"), "utf8");
33124
- } catch {
33125
- raw = "";
33126
- }
33127
- try {
33128
- const pkg = JSON.parse(raw);
33129
- if (pkg.name === "@adep/cli") return dir;
33130
- } catch {
33131
- }
33132
- const parent = dirname8(dir);
33133
- if (parent === dir) {
33134
- throw new InitError(
33135
- "SHELL_TEMPLATE_MISSING",
33136
- "\u627E\u4E0D\u5230 @adep/cli \u7684 package.json\uFF08\u5DF2\u904D\u5386\u5230\u6587\u4EF6\u7CFB\u7EDF\u6839\uFF09"
33137
- );
33138
- }
33139
- dir = parent;
33140
- }
33141
- }
33142
- async function appShellTemplateDir(code = "app-desktop") {
33143
- const dir = join14(await findCliPackageRoot(), "templates", code);
33144
- try {
33145
- await stat6(dir);
33146
- } catch {
33147
- throw new InitError(
33148
- "SHELL_TEMPLATE_MISSING",
33149
- `\u58F3\u6A21\u677F\u76EE\u5F55\u7F3A\u5931\uFF1A${dir}\uFF08\u5B89\u88C5\u4EA7\u7269\u5E94\u5305\u542B templates/\uFF0C\u68C0\u67E5 package.json \u7684 files \u5B57\u6BB5\uFF09`
33150
- );
33151
- }
33152
- return dir;
33153
- }
33154
- async function renderAppShellTemplate(vars, code = "app-desktop") {
33155
- const templateDir = await appShellTemplateDir(code);
33156
- const rels = await collectRelPaths(templateDir, ".");
33157
- const allowed = TEMPLATE_VAR_ALLOWLIST[code];
33158
- const values = {
33159
- projectSlug: vars.projectSlug,
33160
- appName: vars.appName,
33161
- platformUrl: vars.platformUrl,
33162
- // ⚠️ 判据是「desktop 与 mobile 族」而不是「是不是 app-mobile」——`app-mobile-xtool`
33163
- // 同样要 iosBundleId。原来写成 `code === 'app-mobile' ? ... : { appId }` 时,
33164
- // 新 code 会落进 else 分支:`{{iosBundleId}}` 取到 `undefined → ''`,
33165
- // 渲染出一个 **bundle id 为空** 的工程(SwiftPM/xtool 都在更晚的环节才报错)。
33166
- ...code === "app-desktop" ? { appId: vars.appId ?? "" } : {
33167
- iosBundleId: vars.iosBundleId ?? "",
33168
- androidPackageId: vars.androidPackageId ?? ""
33169
- }
33170
- };
33171
- return Promise.all(
33172
- rels.map(async (rel) => {
33173
- const raw = await readFile11(join14(templateDir, rel), "utf8");
33174
- const content = raw.replace(/\{\{\s*([A-Za-z0-9_-]+)\s*\}\}/g, (whole, name) => {
33175
- if (!allowed.has(name)) {
33176
- throw new InitError(
33177
- "SHELL_TEMPLATE_INVALID",
33178
- `\u58F3\u6A21\u677F ${code} \u7684\u6587\u4EF6 ${rel} \u4F7F\u7528\u4E86\u672A\u652F\u6301\u53D8\u91CF "${whole}"\uFF1A\u5141\u8BB8 ${[...allowed].join(" | ")}`
33179
- );
33180
- }
33181
- return values[name] ?? "";
33182
- });
33183
- const leftover = /\{\{\s*[A-Za-z0-9_-]+\s*\}\}/.exec(content);
33184
- if (leftover !== null) {
33185
- throw new InitError(
33186
- "SHELL_TEMPLATE_INVALID",
33187
- `\u58F3\u6A21\u677F ${code} \u7684\u6587\u4EF6 ${rel} \u6E32\u67D3\u540E\u4ECD\u6709\u672A\u66FF\u6362\u5360\u4F4D\u7B26 "${leftover[0]}"`
33188
- );
33189
- }
33190
- return { path: rel, content };
33191
- })
33192
- );
33193
- }
33194
-
33195
33607
  // packages/cli/src/app-init.ts
33196
33608
  function appIdForSlug(slug) {
33197
33609
  return `top.adep.${slug}`;
@@ -33264,16 +33676,16 @@ async function initAppShell(cwd, input2) {
33264
33676
  await Promise.all(
33265
33677
  files.map(async (file2) => {
33266
33678
  if (file2.path === "adep.app.json") return;
33267
- const target = join15(appPath, file2.path);
33268
- await mkdir8(dirname9(target), { recursive: true });
33269
- 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);
33270
33682
  })
33271
33683
  );
33272
- await writeFile6(join15(appPath, "adep.app.json"), configJson);
33684
+ await writeFile7(join16(appPath, "adep.app.json"), configJson);
33273
33685
  for (const item of reused) {
33274
- await cp(item.from, join15(appPath, item.to), { recursive: true });
33686
+ await cp(item.from, join16(appPath, item.to), { recursive: true });
33275
33687
  }
33276
- 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();
33277
33689
  const written = files.map((file2) => file2.path).filter((path) => path !== "adep.app.json");
33278
33690
  return {
33279
33691
  appPath,
@@ -33285,7 +33697,7 @@ async function resolveXtoolReusedSources() {
33285
33697
  const mobileDir = await appShellTemplateDir("app-mobile");
33286
33698
  const resolved = [];
33287
33699
  for (const item of XTOOL_SHELL_REUSED_FROM_MOBILE) {
33288
- const from = join15(mobileDir, item.from);
33700
+ const from = join16(mobileDir, item.from);
33289
33701
  try {
33290
33702
  await stat7(from);
33291
33703
  } catch {
@@ -33304,7 +33716,7 @@ async function listFiles(path, base) {
33304
33716
  const nested = await Promise.all(
33305
33717
  entries.filter((entry) => entry.name !== ".DS_Store").map((entry) => {
33306
33718
  const rel = `${base}/${entry.name}`;
33307
- 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]);
33308
33720
  })
33309
33721
  );
33310
33722
  return nested.flat().toSorted();
@@ -33312,8 +33724,10 @@ async function listFiles(path, base) {
33312
33724
 
33313
33725
  // packages/cli/src/app-build.ts
33314
33726
  init_client();
33315
- init_config();
33316
33727
  init_client2();
33728
+
33729
+ // packages/cli/src/app-build/shared.ts
33730
+ import { stat as stat8 } from "node:fs/promises";
33317
33731
  var SITE_PREFIX = "site/";
33318
33732
  var SHELL_SITE_DIR = "app/site";
33319
33733
  var MOBILE_SITE_ASSET_FILES = {
@@ -33370,30 +33784,15 @@ async function pathExists(path) {
33370
33784
  return false;
33371
33785
  }
33372
33786
  }
33373
- async function readShellConfig(shellDir) {
33374
- const configPath = join16(shellDir, "adep.app.json");
33375
- let text;
33376
- try {
33377
- text = await readFile12(configPath, "utf8");
33378
- } catch {
33379
- throw new InitError(
33380
- "APP_CONFIG_NOT_FOUND",
33381
- `\u672A\u627E\u5230 ${configPath}\uFF1A\u8BE5\u76EE\u5F55\u4E0D\u662F\u684C\u9762\u58F3\u5DE5\u7A0B\uFF0C\u6216\u5C1A\u672A\u6267\u884C adep app init --dir ${shellDir}`
33382
- );
33383
- }
33384
- let parsed;
33385
- try {
33386
- parsed = JSON.parse(text);
33387
- } catch (error62) {
33388
- throw new InitError(
33389
- "APP_CONFIG_INVALID",
33390
- `adep.app.json \u4E0D\u662F\u5408\u6CD5 JSON\uFF1A${error62 instanceof Error ? error62.message : String(error62)}`
33391
- );
33392
- }
33393
- const config2 = parseAdepAppConfig(parsed);
33394
- const raw = parsed ?? {};
33395
- return { raw, config: config2 };
33396
- }
33787
+
33788
+ // packages/cli/src/app-build/bundle.ts
33789
+ init_shared_source();
33790
+ init_validate();
33791
+ init_zip();
33792
+ import { createHash as createHash2 } from "node:crypto";
33793
+ import { mkdir as mkdir9, mkdtemp, readFile as readFile12, rm as rm3, writeFile as writeFile9 } from "node:fs/promises";
33794
+ import { tmpdir } from "node:os";
33795
+ import { dirname as dirname9, join as join17, posix } from "node:path";
33397
33796
  function computeBundleVersion(manifest) {
33398
33797
  const siteEntries = manifest.contents.filter((content) => content.path.startsWith(SITE_PREFIX)).toSorted((left, right) => compareByCodeUnit(left.path, right.path));
33399
33798
  const fingerprint = createHash2("sha256").update(siteEntries.map((content) => `${content.path}:${content.sha256}`).join("\n")).digest("hex").slice(0, 12);
@@ -33483,23 +33882,18 @@ function verifySiteContents(manifest, entries) {
33483
33882
  }
33484
33883
  }
33485
33884
  async function writeSiteTree(shellDir, site) {
33486
- const targetRoot = join16(shellDir, SHELL_SITE_DIR);
33885
+ const targetRoot = join17(shellDir, SHELL_SITE_DIR);
33487
33886
  await rm3(targetRoot, { recursive: true, force: true });
33488
33887
  await mkdir9(targetRoot, { recursive: true });
33489
33888
  const written = [];
33490
33889
  for (const [rel, bytes] of site) {
33491
- const dest = join16(targetRoot, ...rel.split("/"));
33492
- await mkdir9(dirname10(dest), { recursive: true });
33493
- await writeFile8(dest, bytes);
33890
+ const dest = join17(targetRoot, ...rel.split("/"));
33891
+ await mkdir9(dirname9(dest), { recursive: true });
33892
+ await writeFile9(dest, bytes);
33494
33893
  written.push({ path: `${SHELL_SITE_DIR}/${rel}`, size: bytes.length });
33495
33894
  }
33496
33895
  return written;
33497
33896
  }
33498
- async function bindVersion(shellDir, raw, binding) {
33499
- const next = { ...raw, build: binding };
33500
- await writeFile8(join16(shellDir, "adep.app.json"), `${JSON.stringify(next, null, 2)}
33501
- `);
33502
- }
33503
33897
  async function waitForExport(api, jobId, pollIntervalMs, maxPollAttempts) {
33504
33898
  let attempts = 0;
33505
33899
  for (; ; ) {
@@ -33515,6 +33909,113 @@ async function waitForExport(api, jobId, pollIntervalMs, maxPollAttempts) {
33515
33909
  await new Promise((resolvePromise) => setTimeout(resolvePromise, pollIntervalMs));
33516
33910
  }
33517
33911
  }
33912
+ async function fetchAndInjectSite(input2) {
33913
+ const workDir = await mkdtemp(join17(tmpdir(), "adep-app-build-"));
33914
+ try {
33915
+ const zipPath = join17(workDir, "bundle.zip");
33916
+ await input2.api.downloadBundle(input2.jobId, zipPath);
33917
+ const entries = zipRead(await readFile12(zipPath));
33918
+ const manifest = readManifest(entries);
33919
+ verifySiteContents(manifest, entries);
33920
+ const site = collectSiteEntries(entries);
33921
+ if (site.size === 0) {
33922
+ throw new InitError(
33923
+ "APP_NO_PUBLISHED_FRONTEND",
33924
+ `\u9879\u76EE "${input2.projectSlug}" \u6CA1\u6709\u5DF2\u53D1\u5E03\u7684\u9875\u9762\u4EA7\u7269\uFF08\u5BFC\u51FA\u5305\u5185\u6CA1\u6709 ${SITE_PREFIX}\uFF09\uFF1A\u8BF7\u5148\u6267\u884C adep publish --only frontend --project ${input2.projectSlug}`
33925
+ );
33926
+ }
33927
+ return { manifest, written: await writeSiteTree(input2.shellDir, site) };
33928
+ } finally {
33929
+ await rm3(workDir, { recursive: true, force: true });
33930
+ }
33931
+ }
33932
+
33933
+ // packages/cli/src/app-build/shell.ts
33934
+ import { readFile as readFile13, writeFile as writeFile10 } from "node:fs/promises";
33935
+ import { join as join18 } from "node:path";
33936
+ async function readShellConfig(shellDir) {
33937
+ const configPath = join18(shellDir, "adep.app.json");
33938
+ let text;
33939
+ try {
33940
+ text = await readFile13(configPath, "utf8");
33941
+ } catch {
33942
+ throw new InitError(
33943
+ "APP_CONFIG_NOT_FOUND",
33944
+ `\u672A\u627E\u5230 ${configPath}\uFF1A\u8BE5\u76EE\u5F55\u4E0D\u662F\u684C\u9762\u58F3\u5DE5\u7A0B\uFF0C\u6216\u5C1A\u672A\u6267\u884C adep app init --dir ${shellDir}`
33945
+ );
33946
+ }
33947
+ let parsed;
33948
+ try {
33949
+ parsed = JSON.parse(text);
33950
+ } catch (error62) {
33951
+ throw new InitError(
33952
+ "APP_CONFIG_INVALID",
33953
+ `adep.app.json \u4E0D\u662F\u5408\u6CD5 JSON\uFF1A${error62 instanceof Error ? error62.message : String(error62)}`
33954
+ );
33955
+ }
33956
+ const config2 = parseAdepAppConfig(parsed);
33957
+ const raw = parsed ?? {};
33958
+ return { raw, config: config2 };
33959
+ }
33960
+ async function bindVersion(shellDir, raw, binding) {
33961
+ const next = { ...raw, build: binding };
33962
+ await writeFile10(join18(shellDir, "adep.app.json"), `${JSON.stringify(next, null, 2)}
33963
+ `);
33964
+ }
33965
+
33966
+ // packages/cli/src/app-build/site.ts
33967
+ import { copyFile, readFile as readFile14, writeFile as writeFile11 } from "node:fs/promises";
33968
+ import { join as join19 } from "node:path";
33969
+ async function readEntryPage(indexPath) {
33970
+ try {
33971
+ return await readFile14(indexPath, "utf8");
33972
+ } catch (error62) {
33973
+ const code = typeof error62 === "object" && error62 !== null ? error62.code : void 0;
33974
+ if (code === "ENOENT") {
33975
+ throw new InitError(
33976
+ "APP_SITE_MISSING",
33977
+ `\u7AD9\u70B9\u4EA7\u7269\u7F3A\u5165\u53E3\u9875\uFF1A${indexPath} \u4E0D\u5B58\u5728\u3002\u79FB\u52A8\u58F3\u7684 WebView \u6052\u52A0\u8F7D index.html\uFF0C\u7F3A\u4E86\u88C5\u673A\u5C31\u662F\u767D\u5C4F\u2014\u2014\u8BF7\u786E\u8BA4\u7AD9\u70B9\u5DF2\u53D1\u5E03\u4E14\u5165\u53E3\u9875\u662F**\u6839\u7EA7** index.html\uFF08\`adep publish --only frontend\`\uFF09\uFF0C\u518D\u91CD\u8DD1 adep app build`
33978
+ );
33979
+ }
33980
+ throw new InitError(
33981
+ "APP_SITE_UNREADABLE",
33982
+ `\u7AD9\u70B9\u5165\u53E3\u9875\u8BFB\u4E0D\u51FA\u6765\uFF1A${indexPath}\uFF08${error62 instanceof Error ? error62.message : String(error62)}\uFF09`
33983
+ );
33984
+ }
33985
+ }
33986
+ async function injectMobileShellAssets(input2) {
33987
+ const siteRoot = join19(input2.shellDir, SHELL_SITE_DIR);
33988
+ const indexPath = join19(siteRoot, "index.html");
33989
+ const html = await readEntryPage(indexPath);
33990
+ const permissionsJson = `${JSON.stringify(
33991
+ { schemaVersion: 1, permissions: sortPermissions(input2.permissions) },
33992
+ null,
33993
+ 2
33994
+ )}
33995
+ `;
33996
+ await writeFile11(join19(siteRoot, MOBILE_SITE_ASSET_FILES.permissions), permissionsJson);
33997
+ await copyFile(
33998
+ join19(input2.shellDir, "web", "adep-bridge.js"),
33999
+ join19(siteRoot, MOBILE_SITE_ASSET_FILES.bridge)
34000
+ );
34001
+ await copyFile(
34002
+ join19(input2.shellDir, "adep.app.json"),
34003
+ join19(siteRoot, MOBILE_SITE_ASSET_FILES.config)
34004
+ );
34005
+ if (html.includes("adep-bridge.js")) return;
34006
+ const tag = '<script src="/adep-bridge.js"></script>';
34007
+ const next = html.includes("</head>") ? html.replace("</head>", `${tag}
34008
+ </head>`) : `${tag}
34009
+ ${html}`;
34010
+ await writeFile11(indexPath, next);
34011
+ }
34012
+
34013
+ // packages/cli/src/app-build/toolchain.ts
34014
+ init_config();
34015
+ import { spawn as spawn2 } from "node:child_process";
34016
+ import { closeSync, openSync } from "node:fs";
34017
+ import { copyFile as copyFile2, mkdir as mkdir10, readdir as readdir6 } from "node:fs/promises";
34018
+ import { basename as basename2, join as join20 } from "node:path";
33518
34019
  function platformArgs(platform) {
33519
34020
  if (platform === "darwin") return ["--mac"];
33520
34021
  if (platform === "win32") return ["--win"];
@@ -33522,7 +34023,7 @@ function platformArgs(platform) {
33522
34023
  }
33523
34024
  function resolvePackagerBinary(shellDir) {
33524
34025
  const name = process.platform === "win32" ? "electron-builder.cmd" : "electron-builder";
33525
- return join16(shellDir, "node_modules", ".bin", name);
34026
+ return join20(shellDir, "node_modules", ".bin", name);
33526
34027
  }
33527
34028
  function missingDepsError(shellDir) {
33528
34029
  return new InitError(
@@ -33534,17 +34035,17 @@ function missingMobileDepsError(shellDir, platform) {
33534
34035
  if (platform === "ios") {
33535
34036
  return new InitError(
33536
34037
  "APP_SHELL_DEPS_MISSING",
33537
- `\u672A\u627E\u5230 iOS \u539F\u751F\u5DE5\u7A0B\uFF08${join16(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`
33538
34039
  );
33539
34040
  }
33540
34041
  return new InitError(
33541
34042
  "APP_SHELL_DEPS_MISSING",
33542
- `\u672A\u627E\u5230 Android \u539F\u751F\u5DE5\u7A0B\uFF08${join16(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`
33543
34044
  );
33544
34045
  }
33545
34046
  function resolveCapBinary(shellDir) {
33546
34047
  const name = process.platform === "win32" ? "cap.cmd" : "cap";
33547
- return join16(shellDir, "node_modules", ".bin", name);
34048
+ return join20(shellDir, "node_modules", ".bin", name);
33548
34049
  }
33549
34050
  async function syncCapacitorAssets(input2) {
33550
34051
  const capBin = resolveCapBinary(input2.shellDir);
@@ -33567,11 +34068,11 @@ async function assertShellPackagerReady(shellDir, platform, prepareOnly, toolcha
33567
34068
  return;
33568
34069
  }
33569
34070
  if (platform === "ios") {
33570
- if (!await pathExists(join16(shellDir, "ios", "App"))) {
33571
- if (await pathExists(join16(shellDir, "xtool.yml"))) {
34071
+ if (!await pathExists(join20(shellDir, "ios", "App"))) {
34072
+ if (await pathExists(join20(shellDir, "xtool.yml"))) {
33572
34073
  throw new InitError(
33573
34074
  "APP_SHELL_DEPS_MISSING",
33574
- `\u672A\u627E\u5230 Capacitor \u7684 iOS \u539F\u751F\u5DE5\u7A0B\uFF08${join16(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`
33575
34076
  );
33576
34077
  }
33577
34078
  throw missingMobileDepsError(shellDir, "ios");
@@ -33587,16 +34088,16 @@ async function assertShellPackagerReady(shellDir, platform, prepareOnly, toolcha
33587
34088
  if (!await pathExists(resolvePackagerBinary(shellDir))) throw missingDepsError(shellDir);
33588
34089
  }
33589
34090
  async function assertXtoolShellReady(shellDir) {
33590
- if (!await pathExists(join16(shellDir, "xtool.yml")) || !await pathExists(join16(shellDir, "Package.swift"))) {
34091
+ if (!await pathExists(join20(shellDir, "xtool.yml")) || !await pathExists(join20(shellDir, "Package.swift"))) {
33591
34092
  throw new InitError(
33592
34093
  "APP_SHELL_DEPS_MISSING",
33593
- `\u672A\u627E\u5230 xtool \u58F3\u5DE5\u7A0B\uFF08\u9700\u8981 ${join16(shellDir, "xtool.yml")} \u4E0E ${join16(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`
33594
34095
  );
33595
34096
  }
33596
- if (!await pathExists(join16(shellDir, "plugins", "adep-bridge", "Package.swift"))) {
34097
+ if (!await pathExists(join20(shellDir, "plugins", "adep-bridge", "Package.swift"))) {
33597
34098
  throw new InitError(
33598
34099
  "APP_SHELL_DEPS_MISSING",
33599
- `xtool \u58F3\u7F3A\u5C11\u539F\u751F\u6865\u63D2\u4EF6\u6E90\u7801\uFF08${join16(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`
33600
34101
  );
33601
34102
  }
33602
34103
  }
@@ -33623,8 +34124,8 @@ function probeCommand(command, args) {
33623
34124
  });
33624
34125
  }
33625
34126
  function xcodebuildArgs(shellDir, outDir) {
33626
- const appDir = join16(shellDir, "ios", "App");
33627
- const project2 = join16(appDir, "App.xcodeproj");
34127
+ const appDir = join20(shellDir, "ios", "App");
34128
+ const project2 = join20(appDir, "App.xcodeproj");
33628
34129
  const args = [
33629
34130
  // 有 workspace(pod install 后)用 workspace;否则退到 xcodeproj(无插件的最小工程)。
33630
34131
  "-project",
@@ -33635,7 +34136,7 @@ function xcodebuildArgs(shellDir, outDir) {
33635
34136
  "Release",
33636
34137
  "archive",
33637
34138
  "-archivePath",
33638
- join16(outDir, `${basename2(shellDir)}.xcarchive`),
34139
+ join20(outDir, `${basename2(shellDir)}.xcarchive`),
33639
34140
  // unsigned:平台不出具任何签名(PRD §2.11.6「平台不出具签名」)。
33640
34141
  // 显式 CODE_SIGNING_ALLOWED=NO——不带任何签名身份(CODE_SIGN_IDENTITY / PROVISIONING_PROFILE)。
33641
34142
  "CODE_SIGNING_ALLOWED=NO",
@@ -33644,8 +34145,8 @@ function xcodebuildArgs(shellDir, outDir) {
33644
34145
  return args;
33645
34146
  }
33646
34147
  async function runXcodebuild(input2) {
33647
- const workspace = join16(input2.shellDir, "ios", "App", "App.xcworkspace");
33648
- const project2 = join16(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");
33649
34150
  if (!await pathExists(workspace) && !await pathExists(project2)) {
33650
34151
  throw missingMobileDepsError(input2.shellDir, "ios");
33651
34152
  }
@@ -33662,7 +34163,7 @@ async function assertUnsignedIosArchive(archivePath) {
33662
34163
  if (!await pathExists(archivePath)) {
33663
34164
  throw new InitError("APP_ARCHIVE_INCOMPLETE", `iOS archive \u4E0D\u5B58\u5728\uFF1A${archivePath}`);
33664
34165
  }
33665
- const applicationsDir = join16(archivePath, "Products", "Applications");
34166
+ const applicationsDir = join20(archivePath, "Products", "Applications");
33666
34167
  let hasAppBundle = false;
33667
34168
  try {
33668
34169
  const entries = await readdir6(applicationsDir, { withFileTypes: true });
@@ -33692,7 +34193,7 @@ async function assertUnsignedIosArchive(archivePath) {
33692
34193
  continue;
33693
34194
  }
33694
34195
  if (entry.isDirectory()) {
33695
- await walk(join16(dir, entry.name), childRel, depth + 1);
34196
+ await walk(join20(dir, entry.name), childRel, depth + 1);
33696
34197
  }
33697
34198
  }
33698
34199
  };
@@ -33705,10 +34206,10 @@ async function assertUnsignedIosArchive(archivePath) {
33705
34206
  }
33706
34207
  }
33707
34208
  function resolveGradlew(shellDir) {
33708
- return process.platform === "win32" ? join16(shellDir, "android", "gradlew.bat") : join16(shellDir, "android", "gradlew");
34209
+ return process.platform === "win32" ? join20(shellDir, "android", "gradlew.bat") : join20(shellDir, "android", "gradlew");
33709
34210
  }
33710
34211
  async function copyGradleApkToOutDir(shellDir, outDir) {
33711
- const outputsRoot = join16(shellDir, "android", "app", "build", "outputs", "apk");
34212
+ const outputsRoot = join20(shellDir, "android", "app", "build", "outputs", "apk");
33712
34213
  const copied = [];
33713
34214
  const walk = async (dir, depth) => {
33714
34215
  if (depth > 2) return;
@@ -33719,9 +34220,9 @@ async function copyGradleApkToOutDir(shellDir, outDir) {
33719
34220
  return;
33720
34221
  }
33721
34222
  for (const entry of entries) {
33722
- const full = join16(dir, entry.name);
34223
+ const full = join20(dir, entry.name);
33723
34224
  if (entry.isFile() && entry.name.endsWith(".apk")) {
33724
- await copyFile(full, join16(outDir, entry.name));
34225
+ await copyFile2(full, join20(outDir, entry.name));
33725
34226
  copied.push(entry.name);
33726
34227
  continue;
33727
34228
  }
@@ -33737,7 +34238,7 @@ async function runGradle(input2) {
33737
34238
  const gradlew = resolveGradlew(input2.shellDir);
33738
34239
  if (!await pathExists(gradlew)) throw missingMobileDepsError(input2.shellDir, "android");
33739
34240
  if (process.platform === "win32") {
33740
- await spawnChild(join16(input2.shellDir, "android"), "cmd.exe", [
34241
+ await spawnChild(join20(input2.shellDir, "android"), "cmd.exe", [
33741
34242
  "/d",
33742
34243
  "/s",
33743
34244
  "/c",
@@ -33745,14 +34246,14 @@ async function runGradle(input2) {
33745
34246
  "assembleRelease"
33746
34247
  ]);
33747
34248
  } else {
33748
- await spawnChild(join16(input2.shellDir, "android"), gradlew, ["assembleRelease"]);
34249
+ await spawnChild(join20(input2.shellDir, "android"), gradlew, ["assembleRelease"]);
33749
34250
  }
33750
- await mkdir9(input2.outDir, { recursive: true });
34251
+ await mkdir10(input2.outDir, { recursive: true });
33751
34252
  const copied = await copyGradleApkToOutDir(input2.shellDir, input2.outDir);
33752
34253
  if (copied.length === 0) {
33753
34254
  throw new InitError(
33754
34255
  "APP_ARTIFACT_MISSING",
33755
- `gradle \u5DF2\u6210\u529F\u4F46 ${join16(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`
33756
34257
  );
33757
34258
  }
33758
34259
  }
@@ -33818,6 +34319,10 @@ async function runElectronBuilder(input2) {
33818
34319
  }
33819
34320
  await spawnChild(input2.shellDir, binary, args, void 0, env);
33820
34321
  }
34322
+
34323
+ // packages/cli/src/app-build/artifacts.ts
34324
+ import { readFile as readFile15, readdir as readdir7 } from "node:fs/promises";
34325
+ import { join as join21, relative as relative2 } from "node:path";
33821
34326
  function isArtifact(name, isDirectory, platform, toolchain) {
33822
34327
  if (toolchain === "xtool") return !isDirectory && name.endsWith(".ipa");
33823
34328
  if (platform === "ios") return isDirectory && name.endsWith(".xcarchive");
@@ -33830,17 +34335,17 @@ function isArtifact(name, isDirectory, platform, toolchain) {
33830
34335
  }
33831
34336
  async function findArtifacts(shellDir, outDir, platform, toolchain = "capacitor") {
33832
34337
  const found = [];
33833
- const scanRoot = toolchain === "xtool" ? join16(shellDir, XTOOL_ARTIFACT_DIR) : outDir;
34338
+ const scanRoot = toolchain === "xtool" ? join21(shellDir, XTOOL_ARTIFACT_DIR) : outDir;
33834
34339
  const walk = async (dir, depth) => {
33835
34340
  if (depth > 3) return;
33836
34341
  let entries;
33837
34342
  try {
33838
- entries = await readdir6(dir, { withFileTypes: true });
34343
+ entries = await readdir7(dir, { withFileTypes: true });
33839
34344
  } catch {
33840
34345
  return;
33841
34346
  }
33842
34347
  for (const entry of entries) {
33843
- const full = join16(dir, entry.name);
34348
+ const full = join21(dir, entry.name);
33844
34349
  if (isArtifact(entry.name, entry.isDirectory(), platform, toolchain)) {
33845
34350
  found.push(relative2(shellDir, full).split(/[\\/]/u).join("/"));
33846
34351
  continue;
@@ -33891,7 +34396,7 @@ function linuxTargetSkips(declared, artifacts) {
33891
34396
  }
33892
34397
  async function readLinuxDeclaredTargets(shellDir) {
33893
34398
  try {
33894
- const raw = await readFile12(join16(shellDir, "package.json"), "utf8");
34399
+ const raw = await readFile15(join21(shellDir, "package.json"), "utf8");
33895
34400
  const parsed = JSON.parse(raw);
33896
34401
  const target = parsed.build?.linux?.target;
33897
34402
  if (typeof target === "string") return [target];
@@ -33902,69 +34407,8 @@ async function readLinuxDeclaredTargets(shellDir) {
33902
34407
  return [];
33903
34408
  }
33904
34409
  }
33905
- async function fetchAndInjectSite(input2) {
33906
- const workDir = await mkdtemp(join16(tmpdir(), "adep-app-build-"));
33907
- try {
33908
- const zipPath = join16(workDir, "bundle.zip");
33909
- await input2.api.downloadBundle(input2.jobId, zipPath);
33910
- const entries = zipRead(await readFile12(zipPath));
33911
- const manifest = readManifest(entries);
33912
- verifySiteContents(manifest, entries);
33913
- const site = collectSiteEntries(entries);
33914
- if (site.size === 0) {
33915
- throw new InitError(
33916
- "APP_NO_PUBLISHED_FRONTEND",
33917
- `\u9879\u76EE "${input2.projectSlug}" \u6CA1\u6709\u5DF2\u53D1\u5E03\u7684\u9875\u9762\u4EA7\u7269\uFF08\u5BFC\u51FA\u5305\u5185\u6CA1\u6709 ${SITE_PREFIX}\uFF09\uFF1A\u8BF7\u5148\u6267\u884C adep publish --only frontend --project ${input2.projectSlug}`
33918
- );
33919
- }
33920
- return { manifest, written: await writeSiteTree(input2.shellDir, site) };
33921
- } finally {
33922
- await rm3(workDir, { recursive: true, force: true });
33923
- }
33924
- }
33925
- async function readEntryPage(indexPath) {
33926
- try {
33927
- return await readFile12(indexPath, "utf8");
33928
- } catch (error62) {
33929
- const code = typeof error62 === "object" && error62 !== null ? error62.code : void 0;
33930
- if (code === "ENOENT") {
33931
- throw new InitError(
33932
- "APP_SITE_MISSING",
33933
- `\u7AD9\u70B9\u4EA7\u7269\u7F3A\u5165\u53E3\u9875\uFF1A${indexPath} \u4E0D\u5B58\u5728\u3002\u79FB\u52A8\u58F3\u7684 WebView \u6052\u52A0\u8F7D index.html\uFF0C\u7F3A\u4E86\u88C5\u673A\u5C31\u662F\u767D\u5C4F\u2014\u2014\u8BF7\u786E\u8BA4\u7AD9\u70B9\u5DF2\u53D1\u5E03\u4E14\u5165\u53E3\u9875\u662F**\u6839\u7EA7** index.html\uFF08\`adep publish --only frontend\`\uFF09\uFF0C\u518D\u91CD\u8DD1 adep app build`
33934
- );
33935
- }
33936
- throw new InitError(
33937
- "APP_SITE_UNREADABLE",
33938
- `\u7AD9\u70B9\u5165\u53E3\u9875\u8BFB\u4E0D\u51FA\u6765\uFF1A${indexPath}\uFF08${error62 instanceof Error ? error62.message : String(error62)}\uFF09`
33939
- );
33940
- }
33941
- }
33942
- async function injectMobileShellAssets(input2) {
33943
- const siteRoot = join16(input2.shellDir, SHELL_SITE_DIR);
33944
- const indexPath = join16(siteRoot, "index.html");
33945
- const html = await readEntryPage(indexPath);
33946
- const permissionsJson = `${JSON.stringify(
33947
- { schemaVersion: 1, permissions: sortPermissions(input2.permissions) },
33948
- null,
33949
- 2
33950
- )}
33951
- `;
33952
- await writeFile8(join16(siteRoot, MOBILE_SITE_ASSET_FILES.permissions), permissionsJson);
33953
- await copyFile(
33954
- join16(input2.shellDir, "web", "adep-bridge.js"),
33955
- join16(siteRoot, MOBILE_SITE_ASSET_FILES.bridge)
33956
- );
33957
- await copyFile(
33958
- join16(input2.shellDir, "adep.app.json"),
33959
- join16(siteRoot, MOBILE_SITE_ASSET_FILES.config)
33960
- );
33961
- if (html.includes("adep-bridge.js")) return;
33962
- const tag = '<script src="/adep-bridge.js"></script>';
33963
- const next = html.includes("</head>") ? html.replace("</head>", `${tag}
33964
- </head>`) : `${tag}
33965
- ${html}`;
33966
- await writeFile8(indexPath, next);
33967
- }
34410
+
34411
+ // packages/cli/src/app-build.ts
33968
34412
  async function buildDesktopApp(options, deps) {
33969
34413
  const shellDir = resolve8(options.dir);
33970
34414
  const platform = normalizePlatform(options.platform);
@@ -33972,7 +34416,7 @@ async function buildDesktopApp(options, deps) {
33972
34416
  const toolchain = normalizeToolchain(options.toolchain);
33973
34417
  const prepareOnly = options.prepareOnly === true;
33974
34418
  const now = deps.now ?? (() => /* @__PURE__ */ new Date());
33975
- const outDir = join16(shellDir, SHELL_OUT_DIR);
34419
+ const outDir = join22(shellDir, SHELL_OUT_DIR);
33976
34420
  if (isMobilePlatform(platform) && target === "dir") {
33977
34421
  throw new InitError(
33978
34422
  "INVALID_TARGET",
@@ -34033,7 +34477,7 @@ async function buildDesktopApp(options, deps) {
34033
34477
  if (toolchain === "capacitor" && (platform === "ios" || platform === "android")) {
34034
34478
  await (deps.runCapSync ?? syncCapacitorAssets)({ shellDir, platform });
34035
34479
  }
34036
- await mkdir9(outDir, { recursive: true });
34480
+ await mkdir11(outDir, { recursive: true });
34037
34481
  await (deps.runPackager ?? runPlatformPackager)({
34038
34482
  shellDir,
34039
34483
  platform,
@@ -34044,7 +34488,7 @@ async function buildDesktopApp(options, deps) {
34044
34488
  });
34045
34489
  artifacts = await findArtifacts(shellDir, outDir, platform, toolchain);
34046
34490
  if (artifacts.length === 0) {
34047
- const scanned = toolchain === "xtool" ? join16(shellDir, XTOOL_ARTIFACT_DIR) : outDir;
34491
+ const scanned = toolchain === "xtool" ? join22(shellDir, XTOOL_ARTIFACT_DIR) : outDir;
34048
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";
34049
34493
  throw new InitError(
34050
34494
  "APP_ARTIFACT_MISSING",
@@ -34053,7 +34497,7 @@ async function buildDesktopApp(options, deps) {
34053
34497
  }
34054
34498
  if (platform === "ios" && toolchain === "capacitor") {
34055
34499
  for (const artifact of artifacts) {
34056
- await assertUnsignedIosArchive(join16(shellDir, artifact));
34500
+ await assertUnsignedIosArchive(join22(shellDir, artifact));
34057
34501
  }
34058
34502
  }
34059
34503
  if (platform === "linux" && target === "installer") {
@@ -34086,9 +34530,9 @@ async function buildDesktopApp(options, deps) {
34086
34530
  artifacts,
34087
34531
  warnings
34088
34532
  };
34089
- await mkdir9(outDir, { recursive: true });
34090
- const reportPath = join16(outDir, REPORT_FILE);
34091
- await writeFile8(reportPath, `${JSON.stringify(report, null, 2)}
34533
+ await mkdir11(outDir, { recursive: true });
34534
+ const reportPath = join22(outDir, REPORT_FILE);
34535
+ await writeFile12(reportPath, `${JSON.stringify(report, null, 2)}
34092
34536
  `);
34093
34537
  return {
34094
34538
  appPath: shellDir,
@@ -34132,17 +34576,17 @@ async function createAppBuildApi(paths, cwd) {
34132
34576
  }
34133
34577
 
34134
34578
  // packages/cli/src/app-doctor.ts
34135
- import { readFile as readFile14, stat as stat9 } from "node:fs/promises";
34136
- import { join as join18 } from "node:path";
34579
+ import { readFile as readFile17, stat as stat9 } from "node:fs/promises";
34580
+ import { join as join24 } from "node:path";
34137
34581
 
34138
34582
  // packages/cli/src/app-offline-build.ts
34139
34583
  init_zip();
34140
34584
  init_auth();
34141
34585
  import { createHash as createHash3 } from "node:crypto";
34142
- import { access, copyFile as copyFile2, mkdir as mkdir10, mkdtemp as mkdtemp2, readFile as readFile13, rm as rm4, writeFile as writeFile9 } 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";
34143
34587
  import { spawn as spawn3 } from "node:child_process";
34144
34588
  import { tmpdir as tmpdir2 } from "node:os";
34145
- import { dirname as dirname11, join as join17, 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";
34146
34590
  init_client();
34147
34591
  var SHELL_OFFLINE_DIR = "app/offline";
34148
34592
  var SHELL_SITE_OFFLINE_DIR = "app/site/offline";
@@ -34184,15 +34628,15 @@ function collectOfflineEntries(entries) {
34184
34628
  return collected;
34185
34629
  }
34186
34630
  async function writeOfflineTree(shellDir, collected, targetRel) {
34187
- const targetRoot = join17(shellDir, targetRel);
34631
+ const targetRoot = join23(shellDir, targetRel);
34188
34632
  await rm4(targetRoot, { recursive: true, force: true });
34189
- await mkdir10(targetRoot, { recursive: true });
34633
+ await mkdir12(targetRoot, { recursive: true });
34190
34634
  const written = [];
34191
34635
  for (const [rel, bytes] of collected) {
34192
34636
  if (rel.length === 0 || rel.endsWith("/")) continue;
34193
- const dest = join17(targetRoot, ...rel.split("/"));
34194
- await mkdir10(dirname11(dest), { recursive: true });
34195
- await writeFile9(dest, bytes);
34637
+ const dest = join23(targetRoot, ...rel.split("/"));
34638
+ await mkdir12(dirname10(dest), { recursive: true });
34639
+ await writeFile13(dest, bytes);
34196
34640
  written.push({ path: `${targetRel}/${rel}`, size: bytes.length });
34197
34641
  }
34198
34642
  return written;
@@ -34286,14 +34730,14 @@ async function buildOfflineApp(options, deps) {
34286
34730
  );
34287
34731
  }
34288
34732
  if (mobileOffline) {
34289
- const entry = join17(shellDir, "app", "site", "index.html");
34733
+ const entry = join23(shellDir, "app", "site", "index.html");
34290
34734
  if (!await fileExists(entry)) {
34291
34735
  throw new InitError(
34292
34736
  "APP_SITE_MISSING",
34293
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"
34294
34738
  );
34295
34739
  }
34296
- const loaderSource = join17(shellDir, MOBILE_OFFLINE_LOADER.source);
34740
+ const loaderSource = join23(shellDir, MOBILE_OFFLINE_LOADER.source);
34297
34741
  if (!await fileExists(loaderSource)) {
34298
34742
  throw new InitError(
34299
34743
  "OFFLINE_LOADER_MISSING",
@@ -34318,11 +34762,11 @@ ${finished.error ?? "\u670D\u52A1\u7AEF\u672A\u63D0\u4F9B\u539F\u56E0"}
34318
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`
34319
34763
  );
34320
34764
  }
34321
- const workDir = await mkdtemp2(join17(tmpdir2(), "adep-app-offline-build-"));
34765
+ const workDir = await mkdtemp2(join23(tmpdir2(), "adep-app-offline-build-"));
34322
34766
  try {
34323
- const bundlePath = join17(workDir, "bundle.adepack");
34767
+ const bundlePath = join23(workDir, "bundle.adepack");
34324
34768
  await deps.api.downloadBundle(project2.id, finished.id, bundlePath);
34325
- const entries = zipRead(await readFile13(bundlePath));
34769
+ const entries = zipRead(await readFile16(bundlePath));
34326
34770
  const manifest = readManifest(entries, { allowOfflinePortZero: true });
34327
34771
  const collected = collectOfflineEntries(entries);
34328
34772
  const functionEntries = readFunctionsIndex(collected);
@@ -34331,9 +34775,9 @@ ${finished.error ?? "\u670D\u52A1\u7AEF\u672A\u63D0\u4F9B\u539F\u56E0"}
34331
34775
  if (mobileOffline) {
34332
34776
  const permissions = sortPermissions(await deps.api.getPackagingPermissions(project2.id));
34333
34777
  await injectMobileShellAssets({ shellDir, permissions });
34334
- await copyFile2(
34335
- join17(shellDir, MOBILE_OFFLINE_LOADER.source),
34336
- join17(shellDir, MOBILE_OFFLINE_LOADER.dest)
34778
+ await copyFile3(
34779
+ join23(shellDir, MOBILE_OFFLINE_LOADER.source),
34780
+ join23(shellDir, MOBILE_OFFLINE_LOADER.dest)
34337
34781
  );
34338
34782
  }
34339
34783
  const builtAt = now().toISOString();
@@ -34349,13 +34793,13 @@ ${finished.error ?? "\u670D\u52A1\u7AEF\u672A\u63D0\u4F9B\u539F\u56E0"}
34349
34793
  platform: "ios",
34350
34794
  target: "installer",
34351
34795
  toolchain: "xtool",
34352
- outDir: join17(shellDir, "dist")
34796
+ outDir: join23(shellDir, "dist")
34353
34797
  });
34354
- artifacts = await findArtifacts(shellDir, join17(shellDir, "dist"), "ios", "xtool");
34798
+ artifacts = await findArtifacts(shellDir, join23(shellDir, "dist"), "ios", "xtool");
34355
34799
  } else if (androidOffline) {
34356
34800
  await (deps.runCapSync ?? syncCapacitorAssets)({ shellDir, platform: "android" });
34357
- const outDir2 = join17(shellDir, "dist");
34358
- await mkdir10(outDir2, { recursive: true });
34801
+ const outDir2 = join23(shellDir, "dist");
34802
+ await mkdir12(outDir2, { recursive: true });
34359
34803
  await runner({
34360
34804
  shellDir,
34361
34805
  platform: "android",
@@ -34366,8 +34810,8 @@ ${finished.error ?? "\u670D\u52A1\u7AEF\u672A\u63D0\u4F9B\u539F\u56E0"}
34366
34810
  artifacts = await findArtifacts(shellDir, outDir2, "android");
34367
34811
  } else {
34368
34812
  const platform = resolveOfflinePlatform();
34369
- const outDir2 = join17(shellDir, "dist");
34370
- await mkdir10(outDir2, { recursive: true });
34813
+ const outDir2 = join23(shellDir, "dist");
34814
+ await mkdir12(outDir2, { recursive: true });
34371
34815
  await runner({
34372
34816
  shellDir,
34373
34817
  platform,
@@ -34380,7 +34824,7 @@ ${finished.error ?? "\u670D\u52A1\u7AEF\u672A\u63D0\u4F9B\u539F\u56E0"}
34380
34824
  if (artifacts.length === 0) {
34381
34825
  throw new InitError(
34382
34826
  "APP_ARTIFACT_MISSING",
34383
- toolchain === "xtool" ? `\u6253\u5305\u5668\u5DF2\u6267\u884C\u4F46 ${join17(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 ${join17(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 ${join17(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`
34384
34828
  );
34385
34829
  }
34386
34830
  }
@@ -34408,10 +34852,10 @@ ${finished.error ?? "\u670D\u52A1\u7AEF\u672A\u63D0\u4F9B\u539F\u56E0"}
34408
34852
  },
34409
34853
  artifacts
34410
34854
  };
34411
- const outDir = join17(shellDir, "dist");
34412
- await mkdir10(outDir, { recursive: true });
34413
- const reportPath = join17(outDir, "build-report.json");
34414
- await writeFile9(reportPath, `${JSON.stringify(report, null, 2)}
34855
+ const outDir = join23(shellDir, "dist");
34856
+ await mkdir12(outDir, { recursive: true });
34857
+ const reportPath = join23(outDir, "build-report.json");
34858
+ await writeFile13(reportPath, `${JSON.stringify(report, null, 2)}
34415
34859
  `);
34416
34860
  return {
34417
34861
  appPath: shellDir,
@@ -34472,7 +34916,7 @@ async function createAppOfflineBuildApi(paths, cwd) {
34472
34916
  }
34473
34917
  const response = await client.download(downloadUrl, "APP_OFFLINE_BUILD_DOWNLOAD_FAILED");
34474
34918
  const bytes = Buffer.from(await response.arrayBuffer());
34475
- await writeFile9(outputPath, bytes);
34919
+ await writeFile13(outputPath, bytes);
34476
34920
  return { path: outputPath, size: bytes.length };
34477
34921
  },
34478
34922
  // 与在线构建 `AppBuildDeps.getPackagingPermissions` 同一端点同一读法(app-build.ts 同款)。
@@ -34510,7 +34954,7 @@ async function pathExists2(path) {
34510
34954
  }
34511
34955
  async function missingEntries(root, rels) {
34512
34956
  const probed = await Promise.all(
34513
- rels.map(async (rel) => ({ rel, exists: await pathExists2(join18(root, ...rel.split("/"))) }))
34957
+ rels.map(async (rel) => ({ rel, exists: await pathExists2(join24(root, ...rel.split("/"))) }))
34514
34958
  );
34515
34959
  return probed.filter((entry) => !entry.exists).map((entry) => entry.rel);
34516
34960
  }
@@ -34524,10 +34968,10 @@ async function resolveTargets(shellDir, template, platform) {
34524
34968
  if (template === "app-mobile-xtool") return [{ platform: "ios", toolchain: "xtool" }];
34525
34969
  if (template === "app-mobile") {
34526
34970
  const targets = [];
34527
- if (await pathExists2(join18(shellDir, "ios", "App"))) {
34971
+ if (await pathExists2(join24(shellDir, "ios", "App"))) {
34528
34972
  targets.push({ platform: "ios", toolchain: "capacitor" });
34529
34973
  }
34530
- if (await pathExists2(join18(shellDir, "android", "gradlew"))) {
34974
+ if (await pathExists2(join24(shellDir, "android", "gradlew"))) {
34531
34975
  targets.push({ platform: "android", toolchain: "capacitor" });
34532
34976
  }
34533
34977
  return targets;
@@ -34535,10 +34979,10 @@ async function resolveTargets(shellDir, template, platform) {
34535
34979
  return [];
34536
34980
  }
34537
34981
  async function checkConfigDrift(shellDir, config2) {
34538
- const siteConfigPath = join18(shellDir, SHELL_SITE_DIR, MOBILE_SITE_ASSET_FILES.config);
34982
+ const siteConfigPath = join24(shellDir, SHELL_SITE_DIR, MOBILE_SITE_ASSET_FILES.config);
34539
34983
  let text;
34540
34984
  try {
34541
- text = await readFile14(siteConfigPath, "utf8");
34985
+ text = await readFile17(siteConfigPath, "utf8");
34542
34986
  } catch {
34543
34987
  return {
34544
34988
  id: "configDrift",
@@ -34579,8 +35023,8 @@ async function checkConfigDrift(shellDir, config2) {
34579
35023
  };
34580
35024
  }
34581
35025
  async function checkOffline(shellDir) {
34582
- const desktopRoot = join18(shellDir, SHELL_OFFLINE_DIR);
34583
- const siteRoot = join18(shellDir, SHELL_SITE_OFFLINE_DIR);
35026
+ const desktopRoot = join24(shellDir, SHELL_OFFLINE_DIR);
35027
+ const siteRoot = join24(shellDir, SHELL_SITE_OFFLINE_DIR);
34584
35028
  const hasDesktop = await pathExists2(desktopRoot);
34585
35029
  const hasSite = await pathExists2(siteRoot);
34586
35030
  if (!hasDesktop && !hasSite) {
@@ -34613,7 +35057,7 @@ async function checkOffline(shellDir) {
34613
35057
  let functions = [];
34614
35058
  try {
34615
35059
  const index = JSON.parse(
34616
- await readFile14(join18(root, ...OFFLINE_BUNDLE_PATHS.functionsIndex.split("/")), "utf8")
35060
+ await readFile17(join24(root, ...OFFLINE_BUNDLE_PATHS.functionsIndex.split("/")), "utf8")
34617
35061
  );
34618
35062
  functions = index.functions ?? [];
34619
35063
  } catch (error62) {
@@ -34626,7 +35070,7 @@ async function checkOffline(shellDir) {
34626
35070
  };
34627
35071
  }
34628
35072
  const missingSources = (await missingEntries(
34629
- join18(root, "functions"),
35073
+ join24(root, "functions"),
34630
35074
  functions.map((entry) => typeof entry.name === "string" ? entry.name : "").filter((name) => name !== "").map((name) => `${name}.mjs`)
34631
35075
  )).map((rel) => rel.slice(0, -".mjs".length));
34632
35076
  if (missingSources.length > 0) {
@@ -34654,10 +35098,10 @@ async function checkIdentity(shellDir, desktopShaped) {
34654
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"
34655
35099
  };
34656
35100
  }
34657
- const file2 = join18(shellDir, IDENTITY_STATUS_REL);
35101
+ const file2 = join24(shellDir, IDENTITY_STATUS_REL);
34658
35102
  let text;
34659
35103
  try {
34660
- text = await readFile14(file2, "utf8");
35104
+ text = await readFile17(file2, "utf8");
34661
35105
  } catch {
34662
35106
  return {
34663
35107
  id: "identity",
@@ -34792,7 +35236,7 @@ async function runShellDoctor(shellDir, deps = {}) {
34792
35236
  }
34793
35237
  let html;
34794
35238
  try {
34795
- html = await readEntryPage(join18(shellDir, SHELL_SITE_DIR, "index.html"));
35239
+ html = await readEntryPage(join24(shellDir, SHELL_SITE_DIR, "index.html"));
34796
35240
  checks.push({
34797
35241
  id: "siteEntry",
34798
35242
  status: "ok",
@@ -34810,7 +35254,7 @@ async function runShellDoctor(shellDir, deps = {}) {
34810
35254
  }
34811
35255
  const desktopShaped = config2.template === "app-desktop";
34812
35256
  if (desktopShaped) {
34813
- if (await pathExists2(join18(shellDir, "preload.cjs"))) {
35257
+ if (await pathExists2(join24(shellDir, "preload.cjs"))) {
34814
35258
  checks.push({
34815
35259
  id: "bridgeTag",
34816
35260
  status: "ok",
@@ -34855,7 +35299,7 @@ async function runShellDoctor(shellDir, deps = {}) {
34855
35299
  });
34856
35300
  } else {
34857
35301
  const missingAssets = await missingEntries(
34858
- join18(shellDir, SHELL_SITE_DIR),
35302
+ join24(shellDir, SHELL_SITE_DIR),
34859
35303
  Object.values(MOBILE_SITE_ASSET_FILES)
34860
35304
  );
34861
35305
  if (missingAssets.length === 0) {
@@ -34924,8 +35368,8 @@ function formatShellDoctorReport(report) {
34924
35368
  }
34925
35369
 
34926
35370
  // packages/cli/src/app-sync.ts
34927
- import { readFile as readFile15 } from "node:fs/promises";
34928
- import { join as join19 } from "node:path";
35371
+ import { readFile as readFile18 } from "node:fs/promises";
35372
+ import { join as join25 } from "node:path";
34929
35373
 
34930
35374
  // packages/app-runtime/src/device-sqlite.ts
34931
35375
  function createDeviceSqliteDriver(sqlite) {
@@ -35361,7 +35805,7 @@ var APP_SYNC_CODES = {
35361
35805
  /** 当前运行时无 SQLite 内建模块(需要 Bun 或 Node ≥ 22.5)。 */
35362
35806
  runtimeUnsupported: "APP_SYNC_RUNTIME_UNSUPPORTED"
35363
35807
  };
35364
- var LOCAL_DB_REL = join19("data", "offline.sqlite");
35808
+ var LOCAL_DB_REL = join25("data", "offline.sqlite");
35365
35809
  function resolveOwnerKey(explicit) {
35366
35810
  const fromEnv = process.env["ADEP_OWNER_KEY"];
35367
35811
  const value = (explicit ?? fromEnv ?? "").trim();
@@ -35436,9 +35880,9 @@ async function runAppSync(options) {
35436
35880
  );
35437
35881
  }
35438
35882
  const ownerKey = resolveOwnerKey(options.ownerKey);
35439
- const localDb = join19(shellDir, LOCAL_DB_REL);
35883
+ const localDb = join25(shellDir, LOCAL_DB_REL);
35440
35884
  try {
35441
- await readFile15(localDb);
35885
+ await readFile18(localDb);
35442
35886
  } catch (error62) {
35443
35887
  const code = error62.code;
35444
35888
  if (code === "ENOENT" || code === "EISDIR") {
@@ -35499,14 +35943,14 @@ function formatAppSyncReport(report) {
35499
35943
  // packages/cli/src/app-open.ts
35500
35944
  import { spawn as spawn4 } from "node:child_process";
35501
35945
  import { stat as stat10 } from "node:fs/promises";
35502
- import { join as join20 } from "node:path";
35946
+ import { join as join26 } from "node:path";
35503
35947
  var OPEN_UNSUPPORTED_HINT = {
35504
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",
35505
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"
35506
35950
  };
35507
35951
  function resolveDevBinary(shellDir) {
35508
35952
  const name = process.platform === "win32" ? "electron.cmd" : "electron";
35509
- return join20(shellDir, "node_modules", ".bin", name);
35953
+ return join26(shellDir, "node_modules", ".bin", name);
35510
35954
  }
35511
35955
  function defaultSpawnDev(command, args, options) {
35512
35956
  return spawn4(command, args, { cwd: options.cwd, stdio: "inherit" });
@@ -35792,8 +36236,8 @@ function registerApp(program2, ctx) {
35792
36236
  // packages/cli/src/import-cf.ts
35793
36237
  init_adep_config();
35794
36238
  init_regexp();
35795
- import { copyFile as copyFile3, mkdir as mkdir11, readFile as readFile16, readdir as readdir7, stat as stat11, writeFile as writeFile10 } from "node:fs/promises";
35796
- import { basename as basename3, dirname as dirname12, join as join21, 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";
35797
36241
  var TomlSyntaxError = class extends Error {
35798
36242
  constructor(message) {
35799
36243
  super(message);
@@ -36047,13 +36491,13 @@ var SKIP_COPY_NAMES = /* @__PURE__ */ new Set([
36047
36491
  async function copyWorkerDir(sourceDir, targetDir, mainFile) {
36048
36492
  const copied = [];
36049
36493
  const renamedIndex = [];
36050
- const entries = await readdir7(sourceDir, { withFileTypes: true });
36494
+ const entries = await readdir8(sourceDir, { withFileTypes: true });
36051
36495
  for (const entry of entries) {
36052
- const from = join21(sourceDir, entry.name);
36053
- const to = join21(targetDir, entry.name);
36496
+ const from = join27(sourceDir, entry.name);
36497
+ const to = join27(targetDir, entry.name);
36054
36498
  if (SKIP_COPY_NAMES.has(entry.name)) continue;
36055
36499
  if (entry.isDirectory()) {
36056
- await mkdir11(to, { recursive: true });
36500
+ await mkdir13(to, { recursive: true });
36057
36501
  const sub = await copyWorkerDir(from, to, "");
36058
36502
  copied.push(...sub.copied);
36059
36503
  renamedIndex.push(...sub.renamedIndex);
@@ -36061,18 +36505,18 @@ async function copyWorkerDir(sourceDir, targetDir, mainFile) {
36061
36505
  }
36062
36506
  if (from === mainFile) continue;
36063
36507
  if (entry.name === "index.ts") {
36064
- await copyFile3(from, join21(targetDir, "_index.ts"));
36508
+ await copyFile4(from, join27(targetDir, "_index.ts"));
36065
36509
  renamedIndex.push("_index.ts");
36066
36510
  continue;
36067
36511
  }
36068
- await copyFile3(from, to);
36512
+ await copyFile4(from, to);
36069
36513
  copied.push(relative3(targetDir, to));
36070
36514
  }
36071
36515
  return { copied, renamedIndex };
36072
36516
  }
36073
36517
  async function readDevVars(sourceDir) {
36074
36518
  try {
36075
- const text = await readFile16(join21(sourceDir, ".dev.vars"), "utf8");
36519
+ const text = await readFile19(join27(sourceDir, ".dev.vars"), "utf8");
36076
36520
  const vars = {};
36077
36521
  for (const line of text.split(/\r?\n/)) {
36078
36522
  const trimmed = line.trim();
@@ -36090,19 +36534,19 @@ async function readDevVars(sourceDir) {
36090
36534
  async function copyAssetsToWeb(sourceDir, assetsDir, outDir) {
36091
36535
  const files = [];
36092
36536
  const from = resolve11(sourceDir, assetsDir);
36093
- const target = join21(outDir, "web");
36094
- await mkdir11(target, { recursive: true });
36095
- const entries = await readdir7(from, { withFileTypes: true });
36537
+ const target = join27(outDir, "web");
36538
+ await mkdir13(target, { recursive: true });
36539
+ const entries = await readdir8(from, { withFileTypes: true });
36096
36540
  for (const entry of entries) {
36097
- const src = join21(from, entry.name);
36098
- const dst = join21(target, entry.name);
36541
+ const src = join27(from, entry.name);
36542
+ const dst = join27(target, entry.name);
36099
36543
  if (entry.isDirectory()) {
36100
- await mkdir11(dst, { recursive: true });
36544
+ await mkdir13(dst, { recursive: true });
36101
36545
  const sub = await copyAssetsToWeb(src, ".", outDir);
36102
36546
  files.push(...sub);
36103
36547
  continue;
36104
36548
  }
36105
- await copyFile3(src, dst);
36549
+ await copyFile4(src, dst);
36106
36550
  files.push(relative3(outDir, dst));
36107
36551
  }
36108
36552
  return files;
@@ -36351,11 +36795,11 @@ function renderImportPackageJson(name) {
36351
36795
  async function importCfProject(cwd, sourceDir, options = {}) {
36352
36796
  let tomlText;
36353
36797
  try {
36354
- tomlText = await readFile16(join21(sourceDir, "wrangler.toml"), "utf8");
36798
+ tomlText = await readFile19(join27(sourceDir, "wrangler.toml"), "utf8");
36355
36799
  } catch {
36356
36800
  throw new ImportCfError(
36357
36801
  "NO_WRANGLER",
36358
- `\u627E\u4E0D\u5230 ${join21(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`
36359
36803
  );
36360
36804
  }
36361
36805
  let config2;
@@ -36390,10 +36834,10 @@ async function importCfProject(cwd, sourceDir, options = {}) {
36390
36834
  const configText = renderAdepConfig(adepConfig, {
36391
36835
  header: "// \u7531 adep import cf \u751F\u6210\uFF08CF-015\uFF09\uFF1A\u7ED1\u5B9A\u58F0\u660E\u4E0E wrangler.toml \u5BF9\u5E94"
36392
36836
  });
36393
- await mkdir11(outDir, { recursive: true });
36394
- await writeFile10(join21(outDir, "adep.config.ts"), configText, "utf8");
36837
+ await mkdir13(outDir, { recursive: true });
36838
+ await writeFile14(join27(outDir, "adep.config.ts"), configText, "utf8");
36395
36839
  files.push("adep.config.ts");
36396
- await writeFile10(join21(outDir, "package.json"), renderImportPackageJson(workerName), "utf8");
36840
+ await writeFile14(join27(outDir, "package.json"), renderImportPackageJson(workerName), "utf8");
36397
36841
  files.push("package.json");
36398
36842
  let mainCopied = false;
36399
36843
  if (config2.main !== void 0) {
@@ -36407,12 +36851,12 @@ async function importCfProject(cwd, sourceDir, options = {}) {
36407
36851
  if (!mainStat.isFile()) {
36408
36852
  throw new ImportCfError("MAIN_NOT_FILE", `main \u4E0D\u662F\u6587\u4EF6\uFF1A${config2.main}`);
36409
36853
  }
36410
- const fnDir = join21(outDir, "functions", workerName);
36411
- await mkdir11(fnDir, { recursive: true });
36412
- await copyFile3(mainAbs, join21(fnDir, "worker.ts"));
36854
+ const fnDir = join27(outDir, "functions", workerName);
36855
+ await mkdir13(fnDir, { recursive: true });
36856
+ await copyFile4(mainAbs, join27(fnDir, "worker.ts"));
36413
36857
  files.push(`functions/${workerName}/worker.ts`);
36414
36858
  mainCopied = true;
36415
- const mainDir = dirname12(mainAbs);
36859
+ const mainDir = dirname11(mainAbs);
36416
36860
  const { copied, renamedIndex } = await copyWorkerDir(mainDir, fnDir, mainAbs);
36417
36861
  if (renamedIndex.length > 0) {
36418
36862
  warnings.push(
@@ -36423,7 +36867,7 @@ async function importCfProject(cwd, sourceDir, options = {}) {
36423
36867
  if (copied.length > 0) {
36424
36868
  warnings.push(`\u5DF2\u590D\u5236\u540C\u76EE\u5F55\u4F9D\u8D56\u6A21\u5757 ${copied.length} \u4E2A\uFF08\u4FDD\u6301\u76F8\u5BF9 import\uFF09`);
36425
36869
  }
36426
- await writeFile10(join21(fnDir, "index.ts"), renderFunctionEntry("worker", cfBindings), "utf8");
36870
+ await writeFile14(join27(fnDir, "index.ts"), renderFunctionEntry("worker", cfBindings), "utf8");
36427
36871
  files.push(`functions/${workerName}/index.ts`);
36428
36872
  }
36429
36873
  let dosMigrated = 0;
@@ -36438,20 +36882,20 @@ async function importCfProject(cwd, sourceDir, options = {}) {
36438
36882
  );
36439
36883
  }
36440
36884
  if (doBindings.length > 0) {
36441
- const fnDir = join21(outDir, "functions", workerName);
36442
- const workerPath = join21(fnDir, "worker.ts");
36443
- const workerText = await readFile16(workerPath, "utf8");
36885
+ const fnDir = join27(outDir, "functions", workerName);
36886
+ const workerPath = join27(fnDir, "worker.ts");
36887
+ const workerText = await readFile19(workerPath, "utf8");
36444
36888
  const { text: stripped, removed } = stripDurableObjectClasses(
36445
36889
  workerText,
36446
36890
  doBindings.map((b) => b.className)
36447
36891
  );
36448
- await writeFile10(workerPath, stripped, "utf8");
36892
+ await writeFile14(workerPath, stripped, "utf8");
36449
36893
  if (removed.length > 0) {
36450
- await mkdir11(join21(fnDir, "durable-objects"), { recursive: true });
36894
+ await mkdir13(join27(fnDir, "durable-objects"), { recursive: true });
36451
36895
  await Promise.all(
36452
36896
  removed.map(async (r) => {
36453
- await writeFile10(
36454
- join21(fnDir, "durable-objects", `${r.className}.ts`),
36897
+ await writeFile14(
36898
+ join27(fnDir, "durable-objects", `${r.className}.ts`),
36455
36899
  `${r.source}
36456
36900
  `,
36457
36901
  "utf8"
@@ -36461,8 +36905,8 @@ async function importCfProject(cwd, sourceDir, options = {}) {
36461
36905
  );
36462
36906
  }
36463
36907
  if (removed.length > 0) {
36464
- await writeFile10(
36465
- join21(fnDir, "state-objects.ts"),
36908
+ await writeFile14(
36909
+ join27(fnDir, "state-objects.ts"),
36466
36910
  renderStateObjectDeclaration(doBindings, removed),
36467
36911
  "utf8"
36468
36912
  );
@@ -36507,7 +36951,7 @@ async function importCfProject(cwd, sourceDir, options = {}) {
36507
36951
  unsupported,
36508
36952
  warnings
36509
36953
  });
36510
- await writeFile10(join21(outDir, "MIGRATION.md"), migration, "utf8");
36954
+ await writeFile14(join27(outDir, "MIGRATION.md"), migration, "utf8");
36511
36955
  files.push("MIGRATION.md");
36512
36956
  if (!mainCopied) {
36513
36957
  warnings.push("wrangler.toml \u672A\u58F0\u660E main\uFF1A\u672A\u751F\u6210\u51FD\u6570\uFF0C\u4EC5\u751F\u6210\u914D\u7F6E\u4E0E\u62A5\u544A");
@@ -36628,7 +37072,7 @@ init_auth();
36628
37072
  init_client();
36629
37073
  init_deploy();
36630
37074
  import { stat as stat16 } from "node:fs/promises";
36631
- import { join as join28, resolve as resolve16 } from "node:path";
37075
+ import { join as join34, resolve as resolve16 } from "node:path";
36632
37076
  async function resolveProjectId2(client, cwd, slug) {
36633
37077
  const resolvedSlug = await resolveSlug(resolve16(cwd), slug);
36634
37078
  const listed = await client.request("/api/v1/projects", {}, "PROJECT_LIST_FAILED");
@@ -36675,8 +37119,8 @@ async function publishStaticFrontend(paths, options) {
36675
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"
36676
37120
  );
36677
37121
  }
36678
- const webDir = join28(options.cwd, "web");
36679
- const indexStat = await stat16(join28(webDir, "index.html")).catch(() => null);
37122
+ const webDir = join34(options.cwd, "web");
37123
+ const indexStat = await stat16(join34(webDir, "index.html")).catch(() => null);
36680
37124
  if (indexStat === null || !indexStat.isFile()) {
36681
37125
  throw new CliError(
36682
37126
  "FRONTEND_NO_PAGE",
@@ -36729,7 +37173,7 @@ async function runPublish(paths, io, cwd, flags) {
36729
37173
  });
36730
37174
  }
36731
37175
  if (wantFrontend) {
36732
- const webDir = join28(cwd, "web");
37176
+ const webDir = join34(cwd, "web");
36733
37177
  const webStat = await stat16(webDir).catch(() => null);
36734
37178
  if (webStat !== null && webStat.isDirectory()) {
36735
37179
  const { isStaticFrontendDir: isStaticFrontendDir2 } = await Promise.resolve().then(() => (init_frontend(), frontend_exports));
@@ -36797,6 +37241,13 @@ function renderPublish(data) {
36797
37241
  lines.push(`\u2713 frontend built ${status} \xB7 ${fe.siteUrl}`);
36798
37242
  }
36799
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
+ }
36800
37251
  return lines;
36801
37252
  }
36802
37253
  function registerPublish(program2, ctx) {
@@ -36830,8 +37281,8 @@ init_auth();
36830
37281
  // packages/cli/src/deploy-worker.ts
36831
37282
  init_auth();
36832
37283
  init_client();
36833
- import { readdir as readdir11, readFile as readFile23 } from "node:fs/promises";
36834
- import { join as join29, relative as relative8, resolve as resolve17, sep as sep4 } from "node:path";
37284
+ import { readdir as readdir12, readFile as readFile26 } from "node:fs/promises";
37285
+ import { join as join35, relative as relative8, resolve as resolve17, sep as sep4 } from "node:path";
36835
37286
  async function collectWranglerFiles(dir) {
36836
37287
  const root = resolve17(dir);
36837
37288
  const out = {};
@@ -36839,7 +37290,7 @@ async function collectWranglerFiles(dir) {
36839
37290
  const walk = async (sub) => {
36840
37291
  let entries;
36841
37292
  try {
36842
- entries = await readdir11(sub, { withFileTypes: true });
37293
+ entries = await readdir12(sub, { withFileTypes: true });
36843
37294
  } catch (error62) {
36844
37295
  throw new CliError(
36845
37296
  "WORKER_DIR_UNREADABLE",
@@ -36848,11 +37299,11 @@ async function collectWranglerFiles(dir) {
36848
37299
  }
36849
37300
  for (const entry of entries) {
36850
37301
  if (entry.isDirectory() && skip.has(entry.name)) continue;
36851
- const full = join29(sub, entry.name);
37302
+ const full = join35(sub, entry.name);
36852
37303
  if (entry.isDirectory()) {
36853
37304
  await walk(full);
36854
37305
  } else if (entry.isFile()) {
36855
- const buf = await readFile23(full).catch(() => null);
37306
+ const buf = await readFile26(full).catch(() => null);
36856
37307
  if (buf === null) continue;
36857
37308
  if (buf.includes(0)) continue;
36858
37309
  out[relative8(root, full).split(sep4).join("/")] = buf.toString("utf8");
@@ -37164,20 +37615,21 @@ function registerDb(program2, ctx) {
37164
37615
  });
37165
37616
  });
37166
37617
  db.command("migrate").description(
37167
- "\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"
37168
- ).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) => {
37169
37620
  const command = ctx.io("db migrate");
37170
37621
  await command.run(async () => {
37171
37622
  const { environment, source } = await ctx.env();
37172
37623
  const { dbMigrate: dbMigrate2 } = await Promise.resolve().then(() => (init_db2(), db_exports));
37173
37624
  const result = await dbMigrate2(ctx.paths, {
37174
37625
  cwd: ctx.cwd,
37175
- file: file2,
37626
+ files,
37176
37627
  environment,
37177
37628
  ...flags.project === void 0 ? {} : { slug: flags.project }
37178
37629
  });
37179
37630
  if (result.failed !== void 0) {
37180
- 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}`);
37181
37633
  return;
37182
37634
  }
37183
37635
  command.line(
@@ -37655,28 +38107,40 @@ function registerHosting(program2, ctx) {
37655
38107
  });
37656
38108
  });
37657
38109
  hosting.command("deploy").description(
37658
- "[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"
37659
- ).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) => {
37660
- const command = ctx.io("hosting deploy");
37661
- if (!command.json) {
37662
- process.stderr.write(
37663
- "\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"
37664
- );
37665
- }
37666
- await command.run(async () => {
37667
- const { hostingDeploy: hostingDeploy2 } = await Promise.resolve().then(() => (init_hosting(), hosting_exports));
37668
- const result = await hostingDeploy2(ctx.paths, {
37669
- cwd: ctx.cwd,
37670
- dir,
37671
- ...flags.spa === true ? { spa: true } : {},
37672
- ...flags.project === void 0 ? {} : { slug: flags.project }
37673
- });
37674
- command.ok(result, (data) => {
37675
- const r = data;
37676
- 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
+ });
37677
38141
  });
37678
- });
37679
- });
38142
+ }
38143
+ );
37680
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) => {
37681
38145
  const command = ctx.io("hosting pull");
37682
38146
  await command.run(async () => {