@adep/cli 0.0.1 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -61,6 +61,77 @@ var init_credentials = __esm({
61
61
  }
62
62
  });
63
63
 
64
+ // packages/cli/src/offline/errors.ts
65
+ var NetworkRequiredError;
66
+ var init_errors = __esm({
67
+ "packages/cli/src/offline/errors.ts"() {
68
+ "use strict";
69
+ NetworkRequiredError = class extends Error {
70
+ command;
71
+ reason;
72
+ constructor(command, reason) {
73
+ super(`\`${command}\` \u9700\u8981\u8054\u7F51\uFF1A${reason} \xB7 \u79BB\u7EBF\u53EF\u7528\u8303\u56F4\u89C1 \`adep doctor\``);
74
+ this.name = "NetworkRequiredError";
75
+ this.command = command;
76
+ this.reason = reason;
77
+ }
78
+ };
79
+ }
80
+ });
81
+
82
+ // packages/cli/src/offline/net.ts
83
+ var net_exports = {};
84
+ __export(net_exports, {
85
+ isOffline: () => isOffline,
86
+ requireNetwork: () => requireNetwork,
87
+ resetProbeCache: () => resetProbeCache
88
+ });
89
+ async function isOffline() {
90
+ const now = Date.now();
91
+ if (cachedResult !== null && now - cachedResult.timestamp < PROBE_TTL_MS) {
92
+ return cachedResult.offline;
93
+ }
94
+ let offline = true;
95
+ try {
96
+ const controller = new AbortController();
97
+ const timer = setTimeout(() => controller.abort(), PROBE_TIMEOUT_MS);
98
+ try {
99
+ const res = await fetch(PROBE_URL, {
100
+ method: "HEAD",
101
+ signal: controller.signal
102
+ });
103
+ offline = false;
104
+ void res;
105
+ } finally {
106
+ clearTimeout(timer);
107
+ }
108
+ } catch {
109
+ offline = true;
110
+ }
111
+ cachedResult = { offline, timestamp: now };
112
+ return offline;
113
+ }
114
+ function resetProbeCache() {
115
+ cachedResult = null;
116
+ }
117
+ async function requireNetwork(command) {
118
+ const offline = await isOffline();
119
+ if (offline) {
120
+ throw new NetworkRequiredError(command, "\u5F53\u524D\u7F51\u7EDC\u4E0D\u53EF\u8FBE\uFF08\u63A2\u6D4B registry.npmjs.org \u5931\u8D25\uFF09");
121
+ }
122
+ }
123
+ var PROBE_TTL_MS, PROBE_URL, PROBE_TIMEOUT_MS, cachedResult;
124
+ var init_net = __esm({
125
+ "packages/cli/src/offline/net.ts"() {
126
+ "use strict";
127
+ init_errors();
128
+ PROBE_TTL_MS = 3e4;
129
+ PROBE_URL = "https://registry.npmjs.org/";
130
+ PROBE_TIMEOUT_MS = 5e3;
131
+ cachedResult = null;
132
+ }
133
+ });
134
+
64
135
  // packages/cli/src/auth.ts
65
136
  function sessionCookieOf(setCookie) {
66
137
  const line = setCookie.find(
@@ -72,6 +143,7 @@ function sessionCookieOf(setCookie) {
72
143
  return line.split(";")[0];
73
144
  }
74
145
  async function login(paths, input) {
146
+ await requireNetwork("adep login");
75
147
  const server = input.server.replace(/\/+$/, "");
76
148
  let response;
77
149
  try {
@@ -98,6 +170,7 @@ async function login(paths, input) {
98
170
  return { email: input.email };
99
171
  }
100
172
  async function whoami(paths) {
173
+ await requireNetwork("adep whoami");
101
174
  const credentials = await loadCredentials(paths);
102
175
  if (credentials === null) {
103
176
  throw new CliError("NOT_LOGGED_IN", "\u672A\u767B\u5F55\uFF1A\u8BF7\u5148\u6267\u884C adep login");
@@ -133,6 +206,7 @@ var init_auth = __esm({
133
206
  "packages/cli/src/auth.ts"() {
134
207
  "use strict";
135
208
  init_credentials();
209
+ init_net();
136
210
  CliError = class extends Error {
137
211
  constructor(code, message, exitCode = 1) {
138
212
  super(message);
@@ -144,6 +218,20 @@ var init_auth = __esm({
144
218
  }
145
219
  });
146
220
 
221
+ // packages/cli/src/config.ts
222
+ function resolvePaths(env = process.env) {
223
+ const home = env["ADEP_HOME"] ?? `${env["HOME"] ?? ""}/.adep`;
224
+ return { home, credentialsFile: `${home}/credentials` };
225
+ }
226
+ function resolveServer(env = process.env) {
227
+ return (env["ADEP_SERVER"] ?? "https://adep.jajabjbj.top").replace(/\/+$/, "");
228
+ }
229
+ var init_config = __esm({
230
+ "packages/cli/src/config.ts"() {
231
+ "use strict";
232
+ }
233
+ });
234
+
147
235
  // packages/cli/src/widget/build.ts
148
236
  import { createHash } from "node:crypto";
149
237
  import { join as join2, resolve as resolve2 } from "node:path";
@@ -454,50 +542,8 @@ var init_init = __esm({
454
542
  }
455
543
  });
456
544
 
457
- // packages/cli/src/prompt.ts
458
- var prompt_exports = {};
459
- __export(prompt_exports, {
460
- createPrompt: () => createPrompt
461
- });
462
- import { createInterface } from "node:readline/promises";
463
- import { Writable } from "node:stream";
464
- function createPrompt(input = process.stdin) {
465
- const rl = createInterface({ input, output: process.stdout, terminal: true });
466
- let muted = null;
467
- return {
468
- async ask(question) {
469
- const answer = await rl.question(question);
470
- return answer.trim();
471
- },
472
- async askHidden(question) {
473
- muted = createInterface({ input, output: new MutedStream(), terminal: true });
474
- const answer = await muted.question(question);
475
- muted.close();
476
- muted = null;
477
- process.stdout.write("\n");
478
- return answer.trim();
479
- },
480
- close() {
481
- muted?.close();
482
- rl.close();
483
- }
484
- };
485
- }
486
- var MutedStream;
487
- var init_prompt = __esm({
488
- "packages/cli/src/prompt.ts"() {
489
- "use strict";
490
- MutedStream = class extends Writable {
491
- write(_chunk, ...rest) {
492
- void rest;
493
- return true;
494
- }
495
- };
496
- }
497
- });
498
-
499
545
  // packages/runtime/src/shared/capability-keys.ts
500
- var RPC_CAPABILITY_KEY, CHAIN_CAPABILITY_KEY, DB_RPC;
546
+ var RPC_CAPABILITY_KEY, CHAIN_CAPABILITY_KEY, DB_RPC, REALTIME_CAPABILITY_CODES, REALTIME_CAPABILITY_METHODS;
501
547
  var init_capability_keys = __esm({
502
548
  "packages/runtime/src/shared/capability-keys.ts"() {
503
549
  "use strict";
@@ -517,6 +563,20 @@ var init_capability_keys = __esm({
517
563
  /** 执行一条链:`chain, args=[ChainRequest]`。 */
518
564
  chain: "chain"
519
565
  };
566
+ REALTIME_CAPABILITY_CODES = {
567
+ invalidMethod: "REALTIME_INVALID_METHOD",
568
+ unsupportedArg: "REALTIME_UNSUPPORTED_ARG",
569
+ subscriptionNotFound: "REALTIME_SUBSCRIPTION_NOT_FOUND",
570
+ tooManySubscriptions: "REALTIME_TOO_MANY_SUBSCRIPTIONS",
571
+ /** 线上独有:订阅授权策略(RT-002 `SubscriptionPolicy`)拒绝该 channel。 */
572
+ channelDenied: "REALTIME_CHANNEL_DENIED"
573
+ };
574
+ REALTIME_CAPABILITY_METHODS = [
575
+ "publish",
576
+ "subscribe",
577
+ "receive",
578
+ "unsubscribe"
579
+ ];
520
580
  }
521
581
  });
522
582
 
@@ -743,7 +803,7 @@ var init_worker_executor = __esm({
743
803
  const entry = input.entry ?? "index.ts";
744
804
  const deps = this.depsConfig === void 0 ? void 0 : resolveExecutionDeps(this.depsConfig, input.project.id, input.files["package.json"]);
745
805
  const logs = [];
746
- return new Promise((resolve12, reject) => {
806
+ return new Promise((resolve15, reject) => {
747
807
  let worker;
748
808
  try {
749
809
  worker = new Worker(resolveWorkerEntry(), {
@@ -805,7 +865,7 @@ var init_worker_executor = __esm({
805
865
  if (message.type === "result") {
806
866
  clearTimeout(timer);
807
867
  void worker.terminate();
808
- resolve12({ body: message.body, logs });
868
+ resolve15({ body: message.body, logs });
809
869
  return;
810
870
  }
811
871
  if (message.type === "error") {
@@ -1048,7 +1108,6 @@ var init_owned = __esm({
1048
1108
  });
1049
1109
 
1050
1110
  // packages/runtime/src/database/builder/ulid.ts
1051
- import { randomFillSync } from "node:crypto";
1052
1111
  function encodeTime(now) {
1053
1112
  let ts = Math.trunc(now);
1054
1113
  let out = "";
@@ -1084,6 +1143,16 @@ function incrBase32(prev) {
1084
1143
  }
1085
1144
  return chars.join("");
1086
1145
  }
1146
+ function randomFill(bytes) {
1147
+ const source = globalThis.crypto;
1148
+ if (source !== void 0 && typeof source.getRandomValues === "function") {
1149
+ return source.getRandomValues(bytes);
1150
+ }
1151
+ for (let i = 0; i < bytes.length; i += 1) {
1152
+ bytes[i] = Math.floor(Math.random() * 256);
1153
+ }
1154
+ return bytes;
1155
+ }
1087
1156
  function ulid(now = Date.now()) {
1088
1157
  const time = encodeTime(now);
1089
1158
  let random;
@@ -1092,7 +1161,7 @@ function ulid(now = Date.now()) {
1092
1161
  } else {
1093
1162
  lastTime = now;
1094
1163
  const bytes = new Uint8Array(10);
1095
- randomFillSync(bytes);
1164
+ randomFill(bytes);
1096
1165
  random = encodeRandom(bytes);
1097
1166
  }
1098
1167
  lastRandom = random;
@@ -1504,7 +1573,6 @@ var init_builder = __esm({
1504
1573
  });
1505
1574
 
1506
1575
  // packages/runtime/src/database/sdk/cloud.ts
1507
- import { randomUUID } from "node:crypto";
1508
1576
  function errorWithCode(error) {
1509
1577
  const code = typeof error === "object" && error !== null && typeof error.code === "string" ? error.code : void 0;
1510
1578
  if (code !== void 0 && error instanceof Error) {
@@ -1563,7 +1631,7 @@ function createDbCapability(driver, options = {}) {
1563
1631
  case DB_RPC.begin: {
1564
1632
  if (activeTxs.size > 0) throw unsafeOperation("\u4E0D\u5141\u8BB8\u5D4C\u5957\u4E8B\u52A1");
1565
1633
  await driver.run("BEGIN");
1566
- const txId = randomUUID();
1634
+ const txId = crypto.randomUUID();
1567
1635
  activeTxs.set(txId, true);
1568
1636
  return txId;
1569
1637
  }
@@ -2115,11 +2183,177 @@ var init_driver = __esm({
2115
2183
  }
2116
2184
  });
2117
2185
 
2186
+ // packages/runtime/src/storage/hmac-sha256.ts
2187
+ function compress(h, block, w) {
2188
+ for (let i = 0; i < 16; i += 1) {
2189
+ const j = i * 4;
2190
+ w[i] = (block[j] ?? 0) << 24 | (block[j + 1] ?? 0) << 16 | (block[j + 2] ?? 0) << 8 | (block[j + 3] ?? 0);
2191
+ }
2192
+ for (let i = 16; i < 64; i += 1) {
2193
+ const s0 = rotr(w[i - 15], 7) ^ rotr(w[i - 15], 18) ^ w[i - 15] >>> 3;
2194
+ const s1 = rotr(w[i - 2], 17) ^ rotr(w[i - 2], 19) ^ w[i - 2] >>> 10;
2195
+ w[i] = w[i - 16] + s0 + w[i - 7] + s1 | 0;
2196
+ }
2197
+ let [a, b, c, d, e, f, g, hh] = [h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7]];
2198
+ for (let i = 0; i < 64; i += 1) {
2199
+ const S1 = rotr(e, 6) ^ rotr(e, 11) ^ rotr(e, 25);
2200
+ const ch = e & f ^ ~e & g;
2201
+ const t1 = hh + S1 + ch + K[i] + w[i] | 0;
2202
+ const S0 = rotr(a, 2) ^ rotr(a, 13) ^ rotr(a, 22);
2203
+ const maj = a & b ^ a & c ^ b & c;
2204
+ const t2 = S0 + maj | 0;
2205
+ hh = g;
2206
+ g = f;
2207
+ f = e;
2208
+ e = d + t1 | 0;
2209
+ d = c;
2210
+ c = b;
2211
+ b = a;
2212
+ a = t1 + t2 | 0;
2213
+ }
2214
+ h[0] = h[0] + a | 0;
2215
+ h[1] = h[1] + b | 0;
2216
+ h[2] = h[2] + c | 0;
2217
+ h[3] = h[3] + d | 0;
2218
+ h[4] = h[4] + e | 0;
2219
+ h[5] = h[5] + f | 0;
2220
+ h[6] = h[6] + g | 0;
2221
+ h[7] = h[7] + hh | 0;
2222
+ }
2223
+ function sha256(data) {
2224
+ const h = new Uint32Array([
2225
+ 1779033703,
2226
+ 3144134277,
2227
+ 1013904242,
2228
+ 2773480762,
2229
+ 1359893119,
2230
+ 2600822924,
2231
+ 528734635,
2232
+ 1541459225
2233
+ ]);
2234
+ const bitLength = data.length * 8;
2235
+ const paddedLength = Math.ceil((data.length + 9) / 64) * 64;
2236
+ const padded = new Uint8Array(paddedLength);
2237
+ padded.set(data);
2238
+ padded[data.length] = 128;
2239
+ const view = new DataView(padded.buffer);
2240
+ view.setUint32(paddedLength - 4, bitLength >>> 0, false);
2241
+ view.setUint32(paddedLength - 8, Math.floor(bitLength / 4294967296), false);
2242
+ const w = new Uint32Array(64);
2243
+ for (let offset = 0; offset < paddedLength; offset += 64) {
2244
+ compress(h, padded.subarray(offset, offset + 64), w);
2245
+ }
2246
+ const out = new Uint8Array(32);
2247
+ const outView = new DataView(out.buffer);
2248
+ for (let i = 0; i < 8; i += 1) outView.setUint32(i * 4, h[i], false);
2249
+ return out;
2250
+ }
2251
+ function toBytes(input) {
2252
+ if (typeof input !== "string") return input;
2253
+ return new TextEncoder().encode(input);
2254
+ }
2255
+ function hmacSha256(key, message) {
2256
+ const blockSize = 64;
2257
+ let keyBytes = toBytes(key);
2258
+ if (keyBytes.length > blockSize) keyBytes = sha256(keyBytes);
2259
+ const padded = new Uint8Array(blockSize);
2260
+ padded.set(keyBytes);
2261
+ const inner = new Uint8Array(blockSize);
2262
+ const outer = new Uint8Array(blockSize);
2263
+ for (let i = 0; i < blockSize; i += 1) {
2264
+ inner[i] = padded[i] ^ 54;
2265
+ outer[i] = padded[i] ^ 92;
2266
+ }
2267
+ const innerInput = new Uint8Array(blockSize + toBytes(message).length);
2268
+ innerInput.set(inner);
2269
+ innerInput.set(toBytes(message), blockSize);
2270
+ const innerHash = sha256(innerInput);
2271
+ const outerInput = new Uint8Array(blockSize + 32);
2272
+ outerInput.set(outer);
2273
+ outerInput.set(innerHash, blockSize);
2274
+ return sha256(outerInput);
2275
+ }
2276
+ function hmacSha256Hex(key, message) {
2277
+ return [...hmacSha256(key, message)].map((b) => b.toString(16).padStart(2, "0")).join("");
2278
+ }
2279
+ var K, rotr;
2280
+ var init_hmac_sha256 = __esm({
2281
+ "packages/runtime/src/storage/hmac-sha256.ts"() {
2282
+ "use strict";
2283
+ K = new Uint32Array([
2284
+ 1116352408,
2285
+ 1899447441,
2286
+ 3049323471,
2287
+ 3921009573,
2288
+ 961987163,
2289
+ 1508970993,
2290
+ 2453635748,
2291
+ 2870763221,
2292
+ 3624381080,
2293
+ 310598401,
2294
+ 607225278,
2295
+ 1426881987,
2296
+ 1925078388,
2297
+ 2162078206,
2298
+ 2614888103,
2299
+ 3248222580,
2300
+ 3835390401,
2301
+ 4022224774,
2302
+ 264347078,
2303
+ 604807628,
2304
+ 770255983,
2305
+ 1249150122,
2306
+ 1555081692,
2307
+ 1996064986,
2308
+ 2554220882,
2309
+ 2821834349,
2310
+ 2952996808,
2311
+ 3210313671,
2312
+ 3336571891,
2313
+ 3584528711,
2314
+ 113926993,
2315
+ 338241895,
2316
+ 666307205,
2317
+ 773529912,
2318
+ 1294757372,
2319
+ 1396182291,
2320
+ 1695183700,
2321
+ 1986661051,
2322
+ 2177026350,
2323
+ 2456956037,
2324
+ 2730485921,
2325
+ 2820302411,
2326
+ 3259730800,
2327
+ 3345764771,
2328
+ 3516065817,
2329
+ 3600352804,
2330
+ 4094571909,
2331
+ 275423344,
2332
+ 430227734,
2333
+ 506948616,
2334
+ 659060556,
2335
+ 883997877,
2336
+ 958139571,
2337
+ 1322822218,
2338
+ 1537002063,
2339
+ 1747873779,
2340
+ 1955562222,
2341
+ 2024104815,
2342
+ 2227730452,
2343
+ 2361852424,
2344
+ 2428436474,
2345
+ 2756734187,
2346
+ 3204031479,
2347
+ 3329325298
2348
+ ]);
2349
+ rotr = (x, n) => x >>> n | x << 32 - n;
2350
+ }
2351
+ });
2352
+
2118
2353
  // packages/runtime/src/storage/signature.ts
2119
- import { createHmac, timingSafeEqual } from "node:crypto";
2120
2354
  function sign(secret, projectId, path, expires) {
2121
2355
  const payload = `${projectId}|${path}|${expires}`;
2122
- return createHmac("sha256", secret).update(payload).digest("hex");
2356
+ return hmacSha256Hex(secret, payload);
2123
2357
  }
2124
2358
  function signDownloadUrl(config, projectId, path, ttlSeconds = DEFAULT_SIGN_TTL_SECONDS) {
2125
2359
  const expires = Math.floor(Date.now() / 1e3) + ttlSeconds;
@@ -2131,6 +2365,7 @@ var DEFAULT_SIGN_TTL_SECONDS, SIGN_EXPIRES_KEY, SIGN_SIGNATURE_KEY;
2131
2365
  var init_signature = __esm({
2132
2366
  "packages/runtime/src/storage/signature.ts"() {
2133
2367
  "use strict";
2368
+ init_hmac_sha256();
2134
2369
  DEFAULT_SIGN_TTL_SECONDS = 15 * 60;
2135
2370
  SIGN_EXPIRES_KEY = "x-expires";
2136
2371
  SIGN_SIGNATURE_KEY = "x-signature";
@@ -2360,7 +2595,7 @@ function createLocalStorageDriver(options) {
2360
2595
  }
2361
2596
  const root = bucketDir(projectId);
2362
2597
  const metas = [];
2363
- const walk = async (dir, relative2) => {
2598
+ const walk = async (dir, relative3) => {
2364
2599
  let entries;
2365
2600
  try {
2366
2601
  entries = await readdir(dir, { withFileTypes: true });
@@ -2371,7 +2606,7 @@ function createLocalStorageDriver(options) {
2371
2606
  for (const entry of entries) {
2372
2607
  if (entry.name.endsWith(META_SUFFIX)) continue;
2373
2608
  const full = join5(dir, entry.name);
2374
- const rel = relative2 === "" ? entry.name : `${relative2}/${entry.name}`;
2609
+ const rel = relative3 === "" ? entry.name : `${relative3}/${entry.name}`;
2375
2610
  if (entry.isFile()) {
2376
2611
  if (prefix !== void 0 && !rel.startsWith(prefix)) continue;
2377
2612
  tasks.push(
@@ -2440,10 +2675,89 @@ var init_storage = __esm({
2440
2675
  });
2441
2676
 
2442
2677
  // packages/cli/src/sim/realtime.ts
2443
- var SimRealtime;
2678
+ function realtimeError(code, message) {
2679
+ return new Error(`[${code}] ${message}`);
2680
+ }
2681
+ function createSimRealtimeCapability() {
2682
+ const sim = new SimRealtime();
2683
+ const buffers = /* @__PURE__ */ new Map();
2684
+ const disposers = /* @__PURE__ */ new Map();
2685
+ let seq = 0;
2686
+ const handler = async (method, args) => {
2687
+ switch (method) {
2688
+ case "publish": {
2689
+ if (args.length > 2) {
2690
+ throw realtimeError(
2691
+ REALTIME_CODES.unsupportedArg,
2692
+ "\u672C\u5730\u5355\u8FDB\u7A0B\u5185\u5B58\u5E7F\u64AD\u65E0\u8FDE\u63A5\u8EAB\u4EFD\uFF0C\u4E0D\u652F\u6301 publish \u7684 except \u5B9E\u53C2"
2693
+ );
2694
+ }
2695
+ const [channel, data] = args;
2696
+ return sim.publish(channel, data);
2697
+ }
2698
+ case "subscribe": {
2699
+ if (buffers.size >= MAX_SUBSCRIPTIONS) {
2700
+ throw realtimeError(
2701
+ REALTIME_CODES.tooManySubscriptions,
2702
+ `\u672C\u5730\u8BA2\u9605\u6570\u5DF2\u8FBE\u4E0A\u9650 ${String(MAX_SUBSCRIPTIONS)}\uFF0C\u8BF7\u5148 unsubscribe`
2703
+ );
2704
+ }
2705
+ const [channel] = args;
2706
+ seq += 1;
2707
+ const id = `sub-${String(seq)}`;
2708
+ const buffer = [];
2709
+ const off = sim.subscribe(channel, (msg) => {
2710
+ buffer.push(msg);
2711
+ if (buffer.length > MAX_BUFFERED_MESSAGES) buffer.shift();
2712
+ });
2713
+ buffers.set(id, buffer);
2714
+ disposers.set(id, off);
2715
+ return { subscription: id, channel };
2716
+ }
2717
+ case "receive": {
2718
+ const buffer = buffers.get(args[0]);
2719
+ if (buffer === void 0) {
2720
+ throw realtimeError(
2721
+ REALTIME_CODES.subscriptionNotFound,
2722
+ `\u672C\u5730\u8BA2\u9605 "${String(args[0])}" \u4E0D\u5B58\u5728\u6216\u5DF2\u9000\u8BA2`
2723
+ );
2724
+ }
2725
+ return buffer.splice(0, buffer.length);
2726
+ }
2727
+ case "unsubscribe": {
2728
+ const id = args[0];
2729
+ const off = disposers.get(id);
2730
+ if (off === void 0) {
2731
+ throw realtimeError(
2732
+ REALTIME_CODES.subscriptionNotFound,
2733
+ `\u672C\u5730\u8BA2\u9605 "${id}" \u4E0D\u5B58\u5728\u6216\u5DF2\u9000\u8BA2`
2734
+ );
2735
+ }
2736
+ off();
2737
+ disposers.delete(id);
2738
+ buffers.delete(id);
2739
+ return { removed: true };
2740
+ }
2741
+ default:
2742
+ throw realtimeError(
2743
+ REALTIME_CODES.invalidMethod,
2744
+ `\u672A\u77E5\u7684 cloud.realtime \u65B9\u6CD5 "${method}"\uFF08\u53EF\u7528\uFF1A${REALTIME_CAPABILITY_METHODS.join(" / ")}\uFF09`
2745
+ );
2746
+ }
2747
+ };
2748
+ return {
2749
+ bundle: {
2750
+ capabilities: [{ name: "realtime", value: { [RPC_CAPABILITY_KEY]: true } }],
2751
+ rpcHandlers: { realtime: handler }
2752
+ },
2753
+ realtime: sim
2754
+ };
2755
+ }
2756
+ var SimRealtime, MAX_BUFFERED_MESSAGES, MAX_SUBSCRIPTIONS, REALTIME_CODES;
2444
2757
  var init_realtime = __esm({
2445
2758
  "packages/cli/src/sim/realtime.ts"() {
2446
2759
  "use strict";
2760
+ init_capability_keys();
2447
2761
  SimRealtime = class {
2448
2762
  seq = 0;
2449
2763
  subscribers = /* @__PURE__ */ new Map();
@@ -2483,6 +2797,9 @@ var init_realtime = __esm({
2483
2797
  return this.subscribers.size;
2484
2798
  }
2485
2799
  };
2800
+ MAX_BUFFERED_MESSAGES = 64;
2801
+ MAX_SUBSCRIPTIONS = 64;
2802
+ REALTIME_CODES = REALTIME_CAPABILITY_CODES;
2486
2803
  }
2487
2804
  });
2488
2805
 
@@ -2538,12 +2855,12 @@ async function createSimRuntime(options) {
2538
2855
  ...options.baseUrl === void 0 ? {} : { baseUrl: options.baseUrl },
2539
2856
  projectId: options.projectId ?? "local"
2540
2857
  });
2541
- const realtime = new SimRealtime();
2542
- const bundle = mergeBundles([db.bundle, storage.bundle]);
2858
+ const simRealtime = createSimRealtimeCapability();
2859
+ const bundle = mergeBundles([db.bundle, storage.bundle, simRealtime.bundle]);
2543
2860
  await db.engine.load();
2544
2861
  return {
2545
2862
  bundle,
2546
- realtime,
2863
+ realtime: simRealtime.realtime,
2547
2864
  db,
2548
2865
  dispose: async () => {
2549
2866
  await db.driver.close();
@@ -2647,7 +2964,12 @@ var init_boundary = __esm({
2647
2964
  {
2648
2965
  kind: "diff",
2649
2966
  title: "\u65E0\u8DE8\u5B9E\u4F8B\u5E7F\u64AD",
2650
- detail: "realtime \u4E3A\u5355\u8FDB\u7A0B\u5185\u5B58\u5E7F\u64AD\uFF1A\u4E0D\u652F\u6301\u8DE8\u8FDB\u7A0B / \u8DE8\u5B9E\u4F8B\uFF0C\u7EBF\u4E0A\u591A\u5B9E\u4F8B\u8BED\u4E49\u4E0D\u540C\u3002"
2967
+ detail: "cloud.realtime \u5DF2\u6CE8\u5165\uFF0C\u4F46\u4E3A\u5355\u8FDB\u7A0B\u5185\u5B58\u5E7F\u64AD\uFF1A\u4E0D\u652F\u6301\u8DE8\u8FDB\u7A0B / \u8DE8\u5B9E\u4F8B\uFF0C\u7EBF\u4E0A\u591A\u5B9E\u4F8B\u8BED\u4E49\u4E0D\u540C\u3002"
2968
+ },
2969
+ {
2970
+ kind: "capability",
2971
+ title: "publish \u4E0D\u652F\u6301 except",
2972
+ detail: "\u672C\u5730\u4E0D\u5EFA WS \u63E1\u624B\u3001\u65E0\u8FDE\u63A5\u8EAB\u4EFD\uFF0C\u6545 cloud.realtime.publish \u7684 except\uFF08\u4E0D\u53D1\u56DE\u53D1\u9001\u8005\uFF09\u65E0\u4ECE\u5B9E\u73B0\uFF0C\u4F20\u5165\u5373\u62A5\u9519\u3002"
2651
2973
  },
2652
2974
  {
2653
2975
  kind: "capability",
@@ -2928,6 +3250,11 @@ var init_dev = __esm({
2928
3250
  });
2929
3251
 
2930
3252
  // packages/cli/src/client.ts
3253
+ var client_exports = {};
3254
+ __export(client_exports, {
3255
+ createClient: () => createClient,
3256
+ resolveSlug: () => resolveSlug
3257
+ });
2931
3258
  async function envelopeError(response, fallbackCode, parsed) {
2932
3259
  const payload = parsed ?? null;
2933
3260
  return new CliError(
@@ -3050,13 +3377,14 @@ function sha256Hex(content) {
3050
3377
  return createHash3("sha256").update(content).digest("hex");
3051
3378
  }
3052
3379
  async function deploy(paths, options) {
3053
- const log = options.log ?? ((line) => process.stdout.write(`${line}
3380
+ await requireNetwork("adep deploy");
3381
+ const log = options.silent === true ? () => void 0 : options.log ?? ((line) => process.stdout.write(`${line}
3054
3382
  `));
3055
3383
  const client = await createClient(paths);
3056
3384
  const cwd = resolve6(options.cwd);
3057
3385
  const config = await loadConfig(cwd);
3058
3386
  const slug = options.slug ?? config.name;
3059
- const functionsDir = join10(cwd, config.functionsDir);
3387
+ const functionsDir = options.functionsDir === void 0 ? join10(cwd, config.functionsDir) : resolve6(cwd, options.functionsDir);
3060
3388
  const local = await collectEntries(functionsDir);
3061
3389
  if (Object.keys(local).length === 0) {
3062
3390
  throw new CliError("NO_FUNCTIONS", `${functionsDir} \u4E0B\u6CA1\u6709\u51FD\u6570\u6587\u4EF6`);
@@ -3128,120 +3456,926 @@ var init_deploy = __esm({
3128
3456
  init_auth();
3129
3457
  init_client();
3130
3458
  init_dev();
3459
+ init_net();
3131
3460
  }
3132
3461
  });
3133
3462
 
3134
- // packages/cli/src/db.ts
3135
- var db_exports = {};
3136
- __export(db_exports, {
3137
- dbExec: () => dbExec,
3138
- dbRollback: () => dbRollback,
3139
- dbSnapshotCreate: () => dbSnapshotCreate,
3140
- dbSnapshotList: () => dbSnapshotList,
3141
- dbSnapshotRestore: () => dbSnapshotRestore,
3142
- dbStart: () => dbStart,
3143
- dbStatus: () => dbStatus,
3144
- dbStop: () => dbStop
3463
+ // packages/cli/src/prompt.ts
3464
+ var prompt_exports = {};
3465
+ __export(prompt_exports, {
3466
+ createPrompt: () => createPrompt
3145
3467
  });
3146
- import { resolve as resolve7 } from "node:path";
3147
- async function open2(paths, options) {
3148
- const client = await createClient(paths);
3149
- const project2 = await resolveSlug(resolve7(options.cwd), options.slug);
3150
- return { client, project: project2 };
3151
- }
3152
- async function dbStart(paths, options) {
3153
- const { client, project: project2 } = await open2(paths, options);
3154
- return client.request(`/api/v1/projects/${project2}/database`, { method: "POST" });
3155
- }
3156
- async function dbStatus(paths, options) {
3157
- const { client, project: project2 } = await open2(paths, options);
3158
- return client.request(`/api/v1/projects/${project2}/database`);
3159
- }
3160
- async function dbStop(paths, options) {
3161
- const { client, project: project2 } = await open2(paths, options);
3162
- return client.request(`/api/v1/projects/${project2}/database`, {
3163
- method: "DELETE"
3164
- });
3165
- }
3166
- async function dbExec(paths, options) {
3167
- const { client, project: project2 } = await open2(paths, options);
3168
- return client.request(
3169
- `/api/v1/projects/${project2}/database/console/sql`,
3170
- {
3171
- method: "POST",
3172
- body: {
3173
- sql: options.sql,
3174
- ...options.params === void 0 ? {} : { params: options.params },
3175
- ...options.confirmTable === void 0 ? {} : { confirmTable: options.confirmTable }
3176
- }
3468
+ import { createInterface } from "node:readline/promises";
3469
+ import { Writable } from "node:stream";
3470
+ function createPrompt(input = process.stdin) {
3471
+ const rl = createInterface({ input, output: process.stdout, terminal: true });
3472
+ let muted = null;
3473
+ return {
3474
+ async ask(question) {
3475
+ const answer = await rl.question(question);
3476
+ return answer.trim();
3177
3477
  },
3178
- "SQL_EXEC_FAILED"
3179
- );
3180
- }
3181
- async function dbSnapshotList(paths, options) {
3182
- const { client, project: project2 } = await open2(paths, options);
3183
- return client.request(
3184
- `/api/v1/projects/${project2}/database/snapshots`
3185
- );
3186
- }
3187
- async function dbSnapshotCreate(paths, options) {
3188
- const { client, project: project2 } = await open2(paths, options);
3189
- return client.request(`/api/v1/projects/${project2}/database/snapshots`, {
3190
- method: "POST"
3191
- });
3192
- }
3193
- async function dbSnapshotRestore(paths, options) {
3194
- const { client, project: project2 } = await open2(paths, options);
3195
- return client.request(
3196
- `/api/v1/projects/${project2}/database/snapshots/${options.snapshotId}/restore`,
3197
- { method: "POST" }
3198
- );
3199
- }
3200
- async function dbRollback(paths, options) {
3201
- const { client, project: project2 } = await open2(paths, options);
3202
- return client.request(
3203
- `/api/v1/projects/${project2}/database/rollback`,
3204
- { method: "POST", body: { to: options.to } }
3205
- );
3478
+ async askHidden(question) {
3479
+ muted = createInterface({ input, output: new MutedStream(), terminal: true });
3480
+ const answer = await muted.question(question);
3481
+ muted.close();
3482
+ muted = null;
3483
+ process.stdout.write("\n");
3484
+ return answer.trim();
3485
+ },
3486
+ close() {
3487
+ muted?.close();
3488
+ rl.close();
3489
+ }
3490
+ };
3206
3491
  }
3207
- var init_db2 = __esm({
3208
- "packages/cli/src/db.ts"() {
3492
+ var MutedStream;
3493
+ var init_prompt = __esm({
3494
+ "packages/cli/src/prompt.ts"() {
3209
3495
  "use strict";
3210
- init_client();
3496
+ MutedStream = class extends Writable {
3497
+ write(_chunk, ...rest) {
3498
+ void rest;
3499
+ return true;
3500
+ }
3501
+ };
3211
3502
  }
3212
3503
  });
3213
3504
 
3214
- // packages/cli/src/storage.ts
3215
- var storage_exports = {};
3216
- __export(storage_exports, {
3217
- contentTypeOf: () => contentTypeOf,
3218
- storageDownload: () => storageDownload,
3219
- storageList: () => storageList,
3220
- storageRemove: () => storageRemove,
3221
- storageUpload: () => storageUpload
3505
+ // packages/cli/src/serve/banner.ts
3506
+ function isLoopback(host) {
3507
+ return host === "127.0.0.1" || host === "localhost" || host === "::1" || host === "[::1]";
3508
+ }
3509
+ function renderBanner(options) {
3510
+ const { host, port, projectName, functions, hasStatic, staticDir = "public/" } = options;
3511
+ const baseUrl = `http://${host}:${port}`;
3512
+ const loopback = isLoopback(host);
3513
+ const lines = [];
3514
+ lines.push("");
3515
+ lines.push("\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557");
3516
+ lines.push("\u2551 adep serve \u2014 \u5F00\u53D1\u6001\u670D\u52A1\u5668 \u2551");
3517
+ lines.push("\u2551 \u26A0 \u8FD9\u4E0D\u662F\u751F\u4EA7\u670D\u52A1\u5668\uFF0C\u4E0D\u63D0\u4F9B TLS / \u96C6\u7FA4 / \u4F18\u96C5\u91CD\u542F \u2551");
3518
+ lines.push("\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D");
3519
+ lines.push("");
3520
+ lines.push(` \u9879\u76EE: ${projectName}`);
3521
+ lines.push(` \u5730\u5740: ${baseUrl}`);
3522
+ lines.push(` \u7ED1\u5B9A: ${host}${loopback ? "\uFF08\u4EC5\u672C\u673A\u53EF\u8BBF\u95EE\uFF09" : "\uFF08\u26A0 \u5BF9\u5916\u66B4\u9732\uFF09"}`);
3523
+ lines.push("");
3524
+ lines.push(" \u80FD\u529B:");
3525
+ if (functions.length > 0) {
3526
+ lines.push(
3527
+ ` - \u51FD\u6570\u8DEF\u7531: ${baseUrl}/api/{fn}\uFF08${functions.length} \u4E2A\u51FD\u6570: ${functions.join(", ")}\uFF09`
3528
+ );
3529
+ } else {
3530
+ lines.push(" - \u51FD\u6570\u8DEF\u7531: \u65E0\uFF08functions/ \u76EE\u5F55\u4E3A\u7A7A\uFF09");
3531
+ }
3532
+ if (hasStatic) {
3533
+ lines.push(` - \u9759\u6001\u6258\u7BA1: ${baseUrl}/ \u2192 ${staticDir}`);
3534
+ } else {
3535
+ lines.push(` - \u9759\u6001\u6258\u7BA1: \u65E0\uFF08${staticDir} \u76EE\u5F55\u4E0D\u5B58\u5728\uFF09`);
3536
+ }
3537
+ lines.push(" - \u7EC4\u4EF6\u9884\u89C8: Widget / Page \u4EA7\u7269\uFF08\u5982\u5DF2\u6784\u5EFA\uFF09");
3538
+ lines.push(` - \u5065\u5EB7\u68C0\u67E5: ${baseUrl}/healthz`);
3539
+ lines.push("");
3540
+ lines.push(" \u8FB9\u754C\uFF08\u5F00\u53D1\u6001\u9ED8\u8BA4\u503C\uFF0C\u4E0D\u53EF\u5728\u6B64\u6A21\u5F0F\u4E0B\u5F00\u542F\uFF09:");
3541
+ lines.push(" - \u65E0\u9274\u6743\uFF1A\u4EFB\u4F55\u4EBA\u53EF\u8C03\u7528\u6240\u6709\u51FD\u6570");
3542
+ lines.push(" - \u65E0\u9650\u6D41\uFF1A\u65E0 QPS / \u5E76\u53D1\u9650\u5236");
3543
+ lines.push(" - \u65E0\u914D\u989D\uFF1A\u65E0\u8C03\u7528\u6B21\u6570 / \u8D44\u6E90\u7528\u91CF\u9650\u5236");
3544
+ lines.push(" - \u65E0 TLS\uFF1A\u660E\u6587 HTTP\uFF0C\u4E0D\u652F\u6301 HTTPS");
3545
+ lines.push(" - \u65E0\u96C6\u7FA4\uFF1A\u5355\u8FDB\u7A0B\uFF0C\u4E0D\u652F\u6301\u591A\u5B9E\u4F8B");
3546
+ lines.push(" - \u65E0\u4F18\u96C5\u91CD\u542F\uFF1A\u8FDB\u7A0B\u9000\u51FA\u5373\u4E2D\u65AD");
3547
+ lines.push("");
3548
+ if (!loopback) {
3549
+ lines.push(" \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510");
3550
+ lines.push(" \u2502 \u26A0\u26A0\u26A0 \u5BF9\u5916\u66B4\u9732\u8B66\u544A \u2502");
3551
+ lines.push(" \u2502 \u2502");
3552
+ lines.push(` \u2502 \u5F53\u524D\u7ED1\u5B9A ${host.padEnd(43)}\u2502`);
3553
+ lines.push(" \u2502 \u5C40\u57DF\u7F51/\u516C\u7F51\u5185\u4EFB\u4F55\u4EBA\u90FD\u53EF\u8BBF\u95EE\u4F60\u7684\u51FD\u6570\u4E0E\u6570\u636E\u3002 \u2502");
3554
+ lines.push(" \u2502 \u65E0\u9274\u6743\u3001\u65E0\u9650\u6D41\u3001\u65E0\u914D\u989D\u2014\u2014\u8BF7\u52FF\u5728\u4E0D\u53EF\u4FE1\u7F51\u7EDC\u4E2D\u4F7F\u7528\u3002 \u2502");
3555
+ lines.push(" \u2502 \u2502");
3556
+ lines.push(" \u2502 \u9700\u8981\u751F\u4EA7\u90E8\u7F72\uFF1F\u4F7F\u7528 `adep deploy` \u90E8\u7F72\u5230\u5E73\u53F0\u3002 \u2502");
3557
+ lines.push(" \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518");
3558
+ lines.push("");
3559
+ }
3560
+ lines.push(" \u6309 Ctrl+C \u505C\u6B62\u670D\u52A1\u5668\u3002");
3561
+ lines.push("");
3562
+ return lines.join("\n");
3563
+ }
3564
+ var init_banner = __esm({
3565
+ "packages/cli/src/serve/banner.ts"() {
3566
+ "use strict";
3567
+ }
3222
3568
  });
3223
- import { mkdir as mkdir7, readFile as readFile7, stat as stat6, writeFile as writeFile6 } from "node:fs/promises";
3224
- import { basename as basename3, dirname as dirname7, extname, join as join11, resolve as resolve8 } from "node:path";
3225
- async function open3(paths, options) {
3226
- const client = await createClient(paths);
3227
- const project2 = await resolveSlug(resolve8(options.cwd), options.slug);
3228
- return { client, project: project2 };
3229
- }
3230
- function contentTypeOf(path) {
3231
- const map = {
3232
- ".html": "text/html; charset=utf-8",
3233
- ".htm": "text/html; charset=utf-8",
3234
- ".css": "text/css; charset=utf-8",
3235
- ".js": "text/javascript; charset=utf-8",
3236
- ".mjs": "text/javascript; charset=utf-8",
3237
- ".json": "application/json; charset=utf-8",
3238
- ".png": "image/png",
3239
- ".jpg": "image/jpeg",
3240
- ".jpeg": "image/jpeg",
3241
- ".gif": "image/gif",
3242
- ".svg": "image/svg+xml",
3243
- ".webp": "image/webp",
3244
- ".ico": "image/x-icon",
3569
+
3570
+ // packages/cli/src/serve/server.ts
3571
+ var server_exports = {};
3572
+ __export(server_exports, {
3573
+ isLoopback: () => isLoopback,
3574
+ startServeServer: () => startServeServer
3575
+ });
3576
+ import { createServer as createServer2 } from "node:http";
3577
+ import { readdir as readdir4, readFile as readFile7, stat as stat6 } from "node:fs/promises";
3578
+ import { join as join11, relative, resolve as resolve7 } from "node:path";
3579
+ function envNumber(name) {
3580
+ const raw = process.env[name];
3581
+ if (raw === void 0 || raw.trim() === "") return void 0;
3582
+ const value = Number(raw);
3583
+ return Number.isInteger(value) && value >= 0 ? value : void 0;
3584
+ }
3585
+ function envString(name) {
3586
+ const raw = process.env[name];
3587
+ return raw === void 0 || raw.trim() === "" ? void 0 : raw.trim();
3588
+ }
3589
+ async function collectFunctions2(dir) {
3590
+ const files = {};
3591
+ const walk = async (sub, prefix) => {
3592
+ let entries;
3593
+ try {
3594
+ entries = await readdir4(sub, { withFileTypes: true });
3595
+ } catch {
3596
+ return;
3597
+ }
3598
+ for (const entry of entries) {
3599
+ const rel = prefix.length === 0 ? entry.name : `${prefix}/${entry.name}`;
3600
+ const full = join11(sub, entry.name);
3601
+ if (entry.isDirectory()) {
3602
+ await walk(full, rel);
3603
+ } else if (entry.isFile() && entry.name.endsWith(".ts")) {
3604
+ files[rel] = await readFile7(full, "utf8");
3605
+ }
3606
+ }
3607
+ };
3608
+ await walk(dir, "");
3609
+ return files;
3610
+ }
3611
+ function bodyOf2(req) {
3612
+ return new Promise((resolveBody, rejectBody) => {
3613
+ const chunks = [];
3614
+ req.on("data", (chunk) => chunks.push(chunk));
3615
+ req.on("end", () => {
3616
+ const raw = Buffer.concat(chunks).toString("utf8");
3617
+ if (raw.length === 0) {
3618
+ resolveBody(void 0);
3619
+ return;
3620
+ }
3621
+ try {
3622
+ resolveBody(JSON.parse(raw));
3623
+ } catch {
3624
+ resolveBody(raw);
3625
+ }
3626
+ });
3627
+ req.on("error", rejectBody);
3628
+ });
3629
+ }
3630
+ function writeJson2(res, status, payload) {
3631
+ res.writeHead(status, { "content-type": "application/json" });
3632
+ res.end(JSON.stringify(payload));
3633
+ }
3634
+ function contentTypeFor(path) {
3635
+ const ext = path.slice(path.lastIndexOf(".")).toLowerCase();
3636
+ return MIME_TYPES[ext] ?? "application/octet-stream";
3637
+ }
3638
+ async function startServeServer(options) {
3639
+ const cwd = resolve7(options.cwd);
3640
+ const log = options.log ?? ((line) => process.stdout.write(`${line}
3641
+ `));
3642
+ const host = options.host ?? envString("HOST") ?? "127.0.0.1";
3643
+ const port = options.port ?? envNumber("PORT") ?? 8787;
3644
+ const staticDir = resolve7(
3645
+ cwd,
3646
+ options.staticDir ?? envString("ADEP_SERVE_STATIC_DIR") ?? "public"
3647
+ );
3648
+ const config = await loadConfig(cwd);
3649
+ const functionsDir = join11(cwd, config.functionsDir);
3650
+ let hasStatic = false;
3651
+ try {
3652
+ const publicStat = await stat6(staticDir);
3653
+ hasStatic = publicStat.isDirectory();
3654
+ } catch {
3655
+ hasStatic = false;
3656
+ }
3657
+ const files = await collectFunctions2(functionsDir);
3658
+ const functionNames = Object.keys(files).filter((f) => f.endsWith(".ts")).map((f) => f.slice(0, -3));
3659
+ const envText = await readFile7(join11(cwd, ".env.local"), "utf8").catch(() => "");
3660
+ const env = parseEnvFile(envText);
3661
+ const simEnv = await loadSimEnv(cwd).catch(() => ({}));
3662
+ const runtime = await createSimRuntime({
3663
+ cwd,
3664
+ projectId: "local",
3665
+ baseUrl: `http://${host}:${port}`,
3666
+ log
3667
+ });
3668
+ const executor = new WorkerFunctionExecutor();
3669
+ const dbBundle = runtime.bundle;
3670
+ const invokeHandler = createSimInvokeHandler({ executor, files });
3671
+ const buildInput = async (fnName, url, req) => {
3672
+ const query = {};
3673
+ for (const key of new Set(url.searchParams.keys())) {
3674
+ const values = url.searchParams.getAll(key);
3675
+ query[key] = values.length > 1 ? values.join(",") : values[0] ?? "";
3676
+ }
3677
+ const headers = {};
3678
+ for (const [key, value] of Object.entries(req.headers)) {
3679
+ if (typeof value === "string") headers[key] = value;
3680
+ }
3681
+ const body = req.method === "GET" || req.method === "HEAD" ? void 0 : await bodyOf2(req);
3682
+ const hasEnv = Object.keys(env).length > 0 || Object.keys(simEnv).length > 0;
3683
+ const mergedEnv = { ...simEnv, ...env };
3684
+ return {
3685
+ project: { id: "local", slug: config.name },
3686
+ fn: { id: fnName, name: fnName },
3687
+ files,
3688
+ entry: `${fnName}.ts`,
3689
+ request: {
3690
+ method: req.method ?? "GET",
3691
+ path: url.pathname,
3692
+ query,
3693
+ headers,
3694
+ ...body === void 0 ? {} : { body }
3695
+ },
3696
+ capabilities: dbBundle.capabilities,
3697
+ rpcHandlers: {
3698
+ ...dbBundle.rpcHandlers,
3699
+ invoke: invokeHandler
3700
+ },
3701
+ timeoutMs: 1e4,
3702
+ ...hasEnv ? { env: mergedEnv } : {}
3703
+ };
3704
+ };
3705
+ const serveStatic = async (pathname, res) => {
3706
+ if (!hasStatic) return false;
3707
+ const safePath = pathname.replace(/\.\.\//g, "").replace(/^\//, "");
3708
+ const filePath = join11(staticDir, safePath);
3709
+ const resolvedPath = safePath === "" || safePath === "/" ? join11(filePath, "index.html") : filePath;
3710
+ try {
3711
+ const fileStat = await stat6(resolvedPath);
3712
+ if (fileStat.isDirectory()) {
3713
+ const indexPath = join11(resolvedPath, "index.html");
3714
+ try {
3715
+ const indexStat = await stat6(indexPath);
3716
+ if (indexStat.isFile()) {
3717
+ const content2 = await readFile7(indexPath);
3718
+ res.writeHead(200, { "content-type": contentTypeFor(indexPath) });
3719
+ res.end(content2);
3720
+ return true;
3721
+ }
3722
+ } catch {
3723
+ }
3724
+ return false;
3725
+ }
3726
+ const content = await readFile7(resolvedPath);
3727
+ res.writeHead(200, { "content-type": contentTypeFor(resolvedPath) });
3728
+ res.end(content);
3729
+ return true;
3730
+ } catch {
3731
+ return false;
3732
+ }
3733
+ };
3734
+ const handle = async (req, res) => {
3735
+ const url = new URL(req.url ?? "/", `http://${host}:${port}`);
3736
+ const pathname = url.pathname;
3737
+ if (pathname === "/api" || pathname.startsWith("/api/")) {
3738
+ const fnName = pathname === "/api" ? "" : pathname.slice("/api/".length).split("/")[0];
3739
+ if (fnName === void 0 || fnName.length === 0) {
3740
+ writeJson2(res, 400, {
3741
+ error: { code: "FN_NAME_REQUIRED", message: "\u4EE5 /api/{fnName} \u8C03\u7528\u51FD\u6570" }
3742
+ });
3743
+ return;
3744
+ }
3745
+ const entry = `${fnName}.ts`;
3746
+ const source = files[entry];
3747
+ if (source === void 0) {
3748
+ log(`[serve] ${req.method ?? "GET"} ${pathname} -> 404\uFF08\u51FD\u6570\u4E0D\u5B58\u5728\uFF09`);
3749
+ writeJson2(res, 404, { error: { code: "FN_NOT_FOUND", message: `\u51FD\u6570 "${fnName}" \u4E0D\u5B58\u5728` } });
3750
+ return;
3751
+ }
3752
+ const input = await buildInput(fnName, url, req);
3753
+ const startedAt = performance.now();
3754
+ try {
3755
+ const result = await executor.execute(input);
3756
+ const durationMs = Math.round(performance.now() - startedAt);
3757
+ log(`[serve] ${req.method ?? "GET"} ${pathname} -> 200 ${durationMs}ms`);
3758
+ writeJson2(res, 200, result.body === void 0 ? null : result.body);
3759
+ } catch (error) {
3760
+ const durationMs = Math.round(performance.now() - startedAt);
3761
+ if (error instanceof ExecutorError) {
3762
+ log(
3763
+ `[serve] ${req.method ?? "GET"} ${pathname} -> ${error.status} ${durationMs}ms (${error.code})`
3764
+ );
3765
+ writeJson2(res, error.status, { error: { code: error.code, message: error.message } });
3766
+ return;
3767
+ }
3768
+ log(`[serve] ${req.method ?? "GET"} ${pathname} -> 500 ${durationMs}ms`);
3769
+ writeJson2(res, 500, {
3770
+ error: {
3771
+ code: "FN_EXEC_ERROR",
3772
+ message: error instanceof Error ? error.message : "\u51FD\u6570\u6267\u884C\u5931\u8D25"
3773
+ }
3774
+ });
3775
+ }
3776
+ return;
3777
+ }
3778
+ if (pathname === "/healthz") {
3779
+ writeJson2(res, 200, {
3780
+ status: "ok",
3781
+ service: "adep-serve",
3782
+ project: config.name
3783
+ });
3784
+ return;
3785
+ }
3786
+ const served = await serveStatic(pathname, res);
3787
+ if (served) return;
3788
+ if (pathname.startsWith("/_preview/")) {
3789
+ const widgetName = pathname.slice("/_preview/".length).split("/")[0];
3790
+ if (widgetName !== void 0 && widgetName.length > 0) {
3791
+ const widgetDir = join11(cwd, ".adep", "widgets", widgetName);
3792
+ try {
3793
+ const widgetStat = await stat6(widgetDir);
3794
+ if (widgetStat.isDirectory()) {
3795
+ const indexPath = join11(widgetDir, "index.html");
3796
+ try {
3797
+ const content = await readFile7(indexPath, "utf8");
3798
+ res.writeHead(200, { "content-type": "text/html; charset=utf-8" });
3799
+ res.end(content);
3800
+ return;
3801
+ } catch {
3802
+ }
3803
+ }
3804
+ } catch {
3805
+ }
3806
+ }
3807
+ writeJson2(res, 404, { error: { code: "WIDGET_NOT_FOUND", message: "\u7EC4\u4EF6\u4EA7\u7269\u4E0D\u5B58\u5728" } });
3808
+ return;
3809
+ }
3810
+ if (pathname === "/" || pathname === "") {
3811
+ writeJson2(res, 200, {
3812
+ service: "adep-serve",
3813
+ mode: "development",
3814
+ project: config.name,
3815
+ functions: functionNames,
3816
+ static: hasStatic,
3817
+ endpoints: {
3818
+ functions: "/api/{fn}",
3819
+ static: `/ \u2192 ${staticDir}`,
3820
+ preview: "/_preview/{widget}",
3821
+ healthz: "/healthz"
3822
+ },
3823
+ warning: "\u8FD9\u662F\u5F00\u53D1\u6001\u670D\u52A1\u5668\uFF0C\u4E0D\u662F\u751F\u4EA7\u670D\u52A1\u5668"
3824
+ });
3825
+ return;
3826
+ }
3827
+ writeJson2(res, 404, { error: { code: "NOT_FOUND", message: `\u8DEF\u5F84 "${pathname}" \u4E0D\u5B58\u5728` } });
3828
+ };
3829
+ const server = createServer2((req, res) => {
3830
+ void handle(req, res).catch((error) => {
3831
+ log(`[serve] \u672A\u5904\u7406\u9519\u8BEF: ${error instanceof Error ? error.message : String(error)}`);
3832
+ if (!res.headersSent) {
3833
+ writeJson2(res, 500, { error: { code: "INTERNAL_ERROR", message: "\u670D\u52A1\u5668\u5185\u90E8\u9519\u8BEF" } });
3834
+ }
3835
+ });
3836
+ });
3837
+ const actualPort = await new Promise((resolveListen, rejectListen) => {
3838
+ server.once("error", rejectListen);
3839
+ server.listen(port, host, () => {
3840
+ server.off("error", rejectListen);
3841
+ const addr = server.address();
3842
+ if (addr === null || typeof addr === "string") {
3843
+ resolveListen(port);
3844
+ } else {
3845
+ resolveListen(addr.port);
3846
+ }
3847
+ });
3848
+ });
3849
+ const banner = renderBanner({
3850
+ host,
3851
+ port: actualPort,
3852
+ projectName: config.name,
3853
+ functions: functionNames,
3854
+ hasStatic,
3855
+ staticDir: relative(cwd, staticDir).length > 0 ? relative(cwd, staticDir) : staticDir
3856
+ });
3857
+ log(banner);
3858
+ return {
3859
+ port: actualPort,
3860
+ host,
3861
+ baseUrl: `http://${host}:${actualPort}`,
3862
+ close: async () => {
3863
+ await new Promise((resolveClose) => {
3864
+ server.close(() => resolveClose());
3865
+ });
3866
+ }
3867
+ };
3868
+ }
3869
+ var MIME_TYPES;
3870
+ var init_server = __esm({
3871
+ "packages/cli/src/serve/server.ts"() {
3872
+ "use strict";
3873
+ init_executor();
3874
+ init_worker_executor();
3875
+ init_runtime();
3876
+ init_env();
3877
+ init_invoke();
3878
+ init_dev();
3879
+ init_banner();
3880
+ MIME_TYPES = {
3881
+ ".html": "text/html; charset=utf-8",
3882
+ ".htm": "text/html; charset=utf-8",
3883
+ ".css": "text/css; charset=utf-8",
3884
+ ".js": "application/javascript; charset=utf-8",
3885
+ ".mjs": "application/javascript; charset=utf-8",
3886
+ ".json": "application/json; charset=utf-8",
3887
+ ".png": "image/png",
3888
+ ".jpg": "image/jpeg",
3889
+ ".jpeg": "image/jpeg",
3890
+ ".gif": "image/gif",
3891
+ ".svg": "image/svg+xml",
3892
+ ".ico": "image/x-icon",
3893
+ ".woff": "font/woff",
3894
+ ".woff2": "font/woff2",
3895
+ ".ttf": "font/ttf",
3896
+ ".txt": "text/plain; charset=utf-8",
3897
+ ".md": "text/markdown; charset=utf-8",
3898
+ ".pdf": "application/pdf",
3899
+ ".map": "application/json"
3900
+ };
3901
+ }
3902
+ });
3903
+
3904
+ // packages/cli/src/projects.ts
3905
+ var projects_exports = {};
3906
+ __export(projects_exports, {
3907
+ projectsCreate: () => projectsCreate,
3908
+ projectsInfo: () => projectsInfo,
3909
+ projectsList: () => projectsList
3910
+ });
3911
+ function requireSlug(slug, hint) {
3912
+ if (slug === void 0 || slug.trim().length === 0) {
3913
+ throw new CliError("INVALID_SLUG", `\u7F3A\u5C11\u9879\u76EE slug\uFF1A${hint}`);
3914
+ }
3915
+ return slug.trim();
3916
+ }
3917
+ async function projectsCreate(paths, options) {
3918
+ await requireNetworkGuard();
3919
+ const client = await createClient(paths);
3920
+ const slug = requireSlug(options.slug, "adep projects create <slug>");
3921
+ const name = options.name ?? slug;
3922
+ const body = { slug, name };
3923
+ if (options.spaceId !== void 0) body.spaceId = options.spaceId;
3924
+ const created = await client.request(
3925
+ "/api/v1/projects",
3926
+ { body },
3927
+ "PROJECT_CREATE_FAILED"
3928
+ );
3929
+ if (created.url === void 0 || created.url.length === 0) {
3930
+ throw new CliError("PROJECT_CREATE_FAILED", "\u5E73\u53F0\u672A\u8FD4\u56DE\u9879\u76EE\u5730\u5740\uFF0C\u65E0\u6CD5\u8F93\u51FA\u5B50\u57DF URL");
3931
+ }
3932
+ return created;
3933
+ }
3934
+ async function projectsList(paths) {
3935
+ await requireNetworkGuard();
3936
+ const client = await createClient(paths);
3937
+ const result = await client.request(
3938
+ "/api/v1/projects",
3939
+ {},
3940
+ "PROJECT_LIST_FAILED"
3941
+ );
3942
+ return result.projects;
3943
+ }
3944
+ async function projectsInfo(paths, options) {
3945
+ await requireNetworkGuard();
3946
+ const slug = requireSlug(options.slug, "adep projects info <slug>");
3947
+ const projects = await projectsList(paths);
3948
+ const match = projects.find((project2) => project2.slug === slug);
3949
+ if (match === void 0) {
3950
+ throw new CliError("PROJECT_NOT_FOUND", `\u9879\u76EE "${slug}" \u4E0D\u5B58\u5728\u6216\u4F60\u6CA1\u6709\u8BBF\u95EE\u6743\u9650`);
3951
+ }
3952
+ return match;
3953
+ }
3954
+ async function requireNetworkGuard() {
3955
+ const { requireNetwork: requireNetwork2 } = await Promise.resolve().then(() => (init_net(), net_exports));
3956
+ await requireNetwork2("adep projects");
3957
+ }
3958
+ var init_projects = __esm({
3959
+ "packages/cli/src/projects.ts"() {
3960
+ "use strict";
3961
+ init_auth();
3962
+ init_client();
3963
+ }
3964
+ });
3965
+
3966
+ // packages/cli/src/functions.ts
3967
+ var functions_exports = {};
3968
+ __export(functions_exports, {
3969
+ functionsDeploy: () => functionsDeploy,
3970
+ functionsList: () => functionsList,
3971
+ functionsLogs: () => functionsLogs
3972
+ });
3973
+ import { resolve as resolve8 } from "node:path";
3974
+ async function functionsDeploy(paths, options) {
3975
+ const startedAt = Date.now();
3976
+ const result = await deploy(paths, {
3977
+ cwd: options.cwd,
3978
+ ...options.slug === void 0 ? {} : { slug: options.slug },
3979
+ ...options.dir === void 0 ? {} : { functionsDir: resolve8(options.cwd, options.dir) },
3980
+ silent: true
3981
+ });
3982
+ return { ...result, elapsedSeconds: (Date.now() - startedAt) / 1e3 };
3983
+ }
3984
+ async function functionsList(paths, options) {
3985
+ const client = await createClient(paths);
3986
+ const project2 = await resolveProject(client, options);
3987
+ const result = await client.request(
3988
+ `/api/v1/projects/${project2.id}/functions`,
3989
+ {},
3990
+ "FUNCTION_LIST_FAILED"
3991
+ );
3992
+ return {
3993
+ projectId: project2.id,
3994
+ slug: project2.slug,
3995
+ baseUrl: project2.url,
3996
+ functions: result.functions
3997
+ };
3998
+ }
3999
+ async function functionsLogs(paths, options) {
4000
+ if (options.name === void 0 || options.name.trim().length === 0) {
4001
+ throw new CliError("INVALID_ARGUMENT", "\u7F3A\u5C11\u51FD\u6570\u540D\uFF1Aadep functions logs <name>");
4002
+ }
4003
+ const client = await createClient(paths);
4004
+ const project2 = await resolveProject(client, options);
4005
+ const listed = await client.request(
4006
+ `/api/v1/projects/${project2.id}/functions`,
4007
+ {},
4008
+ "FUNCTION_LIST_FAILED"
4009
+ );
4010
+ const target = listed.functions.find((fn) => fn.name === options.name);
4011
+ if (target === void 0) {
4012
+ throw new CliError("FN_NOT_FOUND", `\u51FD\u6570 "${options.name}" \u4E0D\u5B58\u5728\u4E8E\u9879\u76EE "${project2.slug}"`);
4013
+ }
4014
+ const tail = options.tail === void 0 ? "" : `?tail=${encodeURIComponent(String(options.tail))}`;
4015
+ const result = await client.request(
4016
+ `/api/v1/functions/${target.id}/logs${tail}`,
4017
+ {},
4018
+ "FUNCTION_LOGS_FAILED"
4019
+ );
4020
+ return { functionId: target.id, name: target.name, logs: result.logs };
4021
+ }
4022
+ async function resolveProject(client, options) {
4023
+ const slug = await resolveSlug(resolve8(options.cwd), options.slug);
4024
+ const projects = await projectsListFrom(client);
4025
+ const match = projects.find((project2) => project2.slug === slug);
4026
+ if (match === void 0) {
4027
+ throw new CliError(
4028
+ "PROJECT_NOT_FOUND",
4029
+ `\u5E73\u53F0\u9879\u76EE "${slug}" \u4E0D\u5B58\u5728\u6216\u4F60\u6CA1\u6709\u8BBF\u95EE\u6743\u9650\uFF1A\u5148\u6267\u884C adep projects create ${slug}`
4030
+ );
4031
+ }
4032
+ return match;
4033
+ }
4034
+ async function projectsListFrom(client) {
4035
+ const result = await client.request("/api/v1/projects", {}, "PROJECT_LIST_FAILED");
4036
+ return result.projects;
4037
+ }
4038
+ var init_functions = __esm({
4039
+ "packages/cli/src/functions.ts"() {
4040
+ "use strict";
4041
+ init_auth();
4042
+ init_client();
4043
+ init_deploy();
4044
+ }
4045
+ });
4046
+
4047
+ // packages/cli/src/mcp.ts
4048
+ var mcp_exports = {};
4049
+ __export(mcp_exports, {
4050
+ mcpList: () => mcpList,
4051
+ mcpPublish: () => mcpPublish,
4052
+ mcpUnpublish: () => mcpUnpublish
4053
+ });
4054
+ import { resolve as resolve9 } from "node:path";
4055
+ async function mcpPublish(paths, options) {
4056
+ const fn = requireFunctionName(options.fn);
4057
+ const client = await createClient(paths);
4058
+ const project2 = await resolveProject2(client, options);
4059
+ const target = await resolveFunction(client, project2, fn);
4060
+ const body = {};
4061
+ if (options.toolName !== void 0 && options.toolName.trim().length > 0) {
4062
+ body.toolName = options.toolName.trim();
4063
+ }
4064
+ if (options.description !== void 0 && options.description.length > 0) {
4065
+ body.description = options.description;
4066
+ }
4067
+ const tool = await client.request(
4068
+ `/api/v1/functions/${target.id}/mcp-publish`,
4069
+ { method: "POST", ...Object.keys(body).length === 0 ? {} : { body } },
4070
+ "MCP_PUBLISH_FAILED"
4071
+ );
4072
+ return { projectId: project2.id, tool };
4073
+ }
4074
+ async function mcpUnpublish(paths, options) {
4075
+ const fn = requireFunctionName(options.fn);
4076
+ const client = await createClient(paths);
4077
+ const project2 = await resolveProject2(client, options);
4078
+ const target = await resolveFunction(client, project2, fn);
4079
+ const toolName = options.toolName?.trim() || fn;
4080
+ const result = await client.request(
4081
+ `/api/v1/functions/${target.id}/mcp-publish?tool=${encodeURIComponent(toolName)}`,
4082
+ { method: "DELETE" },
4083
+ "MCP_UNPUBLISH_FAILED"
4084
+ );
4085
+ return { projectId: project2.id, toolName, removed: result.unpublished === true };
4086
+ }
4087
+ async function mcpList(paths, options) {
4088
+ const client = await createClient(paths);
4089
+ const project2 = await resolveProject2(client, options);
4090
+ const endpoint = `${project2.url.replace(/\/+$/, "")}/mcp`;
4091
+ let response;
4092
+ try {
4093
+ response = await fetch(endpoint, {
4094
+ method: "POST",
4095
+ headers: { "content-type": "application/json", cookie: client.cookie },
4096
+ body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "tools/list" })
4097
+ });
4098
+ } catch (error) {
4099
+ throw new CliError(
4100
+ "SERVER_UNREACHABLE",
4101
+ `\u65E0\u6CD5\u8FDE\u63A5 MCP \u7AEF\u70B9 ${endpoint}\uFF1A${error instanceof Error ? error.message : String(error)}`
4102
+ );
4103
+ }
4104
+ const parsed = await response.json().catch(() => null);
4105
+ if (!response.ok) {
4106
+ const envelope = parsed ?? null;
4107
+ throw new CliError(
4108
+ envelope?.error?.code ?? "MCP_LIST_FAILED",
4109
+ envelope?.error?.message ?? `MCP \u7AEF\u70B9\u8FD4\u56DE HTTP ${response.status}`
4110
+ );
4111
+ }
4112
+ const rpcError = parsed?.error;
4113
+ if (rpcError !== void 0) {
4114
+ throw new CliError(
4115
+ rpcError.code ?? "MCP_LIST_FAILED",
4116
+ rpcError.message ?? "MCP tools/list \u5931\u8D25"
4117
+ );
4118
+ }
4119
+ return {
4120
+ projectId: project2.id,
4121
+ slug: project2.slug,
4122
+ endpoint,
4123
+ tools: parsed?.result?.tools ?? []
4124
+ };
4125
+ }
4126
+ function requireFunctionName(fn) {
4127
+ if (fn === void 0 || fn.trim().length === 0) {
4128
+ throw new CliError("INVALID_ARGUMENT", "\u7F3A\u5C11\u51FD\u6570\u540D\uFF1Aadep mcp publish --function <fn>");
4129
+ }
4130
+ return fn.trim();
4131
+ }
4132
+ async function resolveProject2(client, options) {
4133
+ const slug = await resolveSlug(resolve9(options.cwd), options.slug);
4134
+ const listed = await client.request("/api/v1/projects", {}, "PROJECT_LIST_FAILED");
4135
+ const match = listed.projects.find((project2) => project2.slug === slug);
4136
+ if (match === void 0) {
4137
+ throw new CliError(
4138
+ "PROJECT_NOT_FOUND",
4139
+ `\u5E73\u53F0\u9879\u76EE "${slug}" \u4E0D\u5B58\u5728\u6216\u4F60\u6CA1\u6709\u8BBF\u95EE\u6743\u9650\uFF1A\u5148\u6267\u884C adep projects create ${slug}`
4140
+ );
4141
+ }
4142
+ return { id: match.id, slug: match.slug, url: match.url };
4143
+ }
4144
+ async function resolveFunction(client, project2, name) {
4145
+ const listed = await client.request(`/api/v1/projects/${project2.id}/functions`, {}, "FUNCTION_LIST_FAILED");
4146
+ const target = listed.functions.find((fn) => fn.name === name);
4147
+ if (target === void 0) {
4148
+ throw new CliError("FN_NOT_FOUND", `\u51FD\u6570 "${name}" \u4E0D\u5B58\u5728\u4E8E\u9879\u76EE "${project2.slug}"`);
4149
+ }
4150
+ return { id: target.id, name: target.name };
4151
+ }
4152
+ var init_mcp = __esm({
4153
+ "packages/cli/src/mcp.ts"() {
4154
+ "use strict";
4155
+ init_auth();
4156
+ init_client();
4157
+ }
4158
+ });
4159
+
4160
+ // packages/cli/src/doctor.ts
4161
+ var doctor_exports = {};
4162
+ __export(doctor_exports, {
4163
+ formatDoctorReport: () => formatDoctorReport,
4164
+ runDoctor: () => runDoctor
4165
+ });
4166
+ import { stat as stat7 } from "node:fs/promises";
4167
+ async function probeServer(server) {
4168
+ const controller = new AbortController();
4169
+ const timer = setTimeout(() => controller.abort(), SERVER_PROBE_TIMEOUT_MS);
4170
+ try {
4171
+ const response = await fetch(`${server}/api/v1/health`, { signal: controller.signal });
4172
+ return { reachable: true, status: response.status };
4173
+ } catch (error) {
4174
+ return {
4175
+ reachable: false,
4176
+ error: error instanceof Error ? error.message : String(error)
4177
+ };
4178
+ } finally {
4179
+ clearTimeout(timer);
4180
+ }
4181
+ }
4182
+ async function credentialMode(file) {
4183
+ try {
4184
+ const info = await stat7(file);
4185
+ return (info.mode & 511).toString(8).padStart(3, "0");
4186
+ } catch {
4187
+ return void 0;
4188
+ }
4189
+ }
4190
+ async function runDoctor(paths) {
4191
+ const credentials = await loadCredentials(paths);
4192
+ const server = credentials?.server ?? resolveServer();
4193
+ const mode = await credentialMode(paths.credentialsFile);
4194
+ const offline = await isOffline();
4195
+ const health = await probeServer(server);
4196
+ const report = {
4197
+ server,
4198
+ credentials: {
4199
+ file: paths.credentialsFile,
4200
+ present: credentials !== null,
4201
+ ...mode === void 0 ? {} : { mode }
4202
+ },
4203
+ network: { offline },
4204
+ serverHealth: health,
4205
+ offlineCommands: [...OFFLINE_COMMANDS],
4206
+ boundaries: SIM_BOUNDARIES.map((b) => ({ kind: b.kind, title: b.title, detail: b.detail }))
4207
+ };
4208
+ if (credentials !== null) report.credentials.email = credentials.email;
4209
+ if (mode !== void 0 && mode !== "600") {
4210
+ report.credentials.warning = `\u6743\u9650 ${mode} \u5BBD\u4E8E 0600\uFF0C\u5EFA\u8BAE chmod 600 ${paths.credentialsFile}`;
4211
+ }
4212
+ return report;
4213
+ }
4214
+ function formatDoctorReport(report) {
4215
+ const lines = ["adep doctor \xB7 \u73AF\u5883\u81EA\u68C0", ""];
4216
+ lines.push("\u51ED\u636E\u4E0E\u8EAB\u4EFD");
4217
+ if (report.credentials.present) {
4218
+ lines.push(` \u2713 \u5DF2\u767B\u5F55 ${report.credentials.email ?? "(\u672A\u77E5\u90AE\u7BB1)"} @ ${report.server}`);
4219
+ lines.push(
4220
+ ` \xB7 \u51ED\u636E\u6587\u4EF6 ${report.credentials.file}\uFF08${report.credentials.mode ?? "\u6743\u9650\u672A\u77E5"}\uFF09`
4221
+ );
4222
+ if (report.credentials.warning !== void 0) lines.push(` ! ${report.credentials.warning}`);
4223
+ } else {
4224
+ lines.push(` \u2717 \u672A\u767B\u5F55\uFF08\u65E0 ${report.credentials.file}\uFF09`);
4225
+ lines.push(" \u63D0\u793A\uFF1A\u5148\u6267\u884C adep login");
4226
+ }
4227
+ lines.push("", "\u7F51\u7EDC\u4E0E\u670D\u52A1\u7AEF");
4228
+ lines.push(
4229
+ report.network.offline ? " \u2717 \u5916\u7F51\u4E0D\u53EF\u8FBE\uFF08\u4F9D\u8D56\u5B89\u88C5 / \u90E8\u7F72\u7B49\u547D\u4EE4\u5C06\u660E\u786E\u5931\u8D25\uFF09" : " \u2713 \u5916\u7F51\u53EF\u8FBE"
4230
+ );
4231
+ if (report.serverHealth.reachable) {
4232
+ lines.push(` \u2713 \u5E73\u53F0\u53EF\u8FBE ${report.server}\uFF08/api/v1/health \u2192 ${report.serverHealth.status}\uFF09`);
4233
+ } else {
4234
+ lines.push(
4235
+ ` \u2717 \u5E73\u53F0\u4E0D\u53EF\u8FBE ${report.server}\uFF1A${report.serverHealth.error ?? "\u65E0\u5E94\u7B54"}`,
4236
+ " \u63D0\u793A\uFF1A\u68C0\u67E5 ADEP_SERVER / \u767B\u5F55\u65F6\u7684 --server\uFF0C\u6216\u5148\u8D77\u672C\u5730 pnpm run dev"
4237
+ );
4238
+ }
4239
+ lines.push("", "\u79BB\u7EBF\u53EF\u7528\u8303\u56F4\uFF08\u65AD\u7F51\u65F6\u4ECD\u53EF\u6267\u884C\uFF09");
4240
+ for (const command of report.offlineCommands) lines.push(` \xB7 ${command}`);
4241
+ lines.push("", "\u672C\u5730\u6A21\u62DF\u8FD0\u884C\u65F6\u7684\u80FD\u529B\u8FB9\u754C\uFF08\u4E0E adep dev \u542F\u52A8\u6A2A\u5E45\u540C\u6E90\uFF09");
4242
+ for (const boundary of report.boundaries) {
4243
+ lines.push(` \xB7 [${boundary.kind}] ${boundary.title}\uFF1A${boundary.detail}`);
4244
+ }
4245
+ return lines;
4246
+ }
4247
+ var SERVER_PROBE_TIMEOUT_MS, OFFLINE_COMMANDS;
4248
+ var init_doctor = __esm({
4249
+ "packages/cli/src/doctor.ts"() {
4250
+ "use strict";
4251
+ init_credentials();
4252
+ init_config();
4253
+ init_boundary();
4254
+ init_net();
4255
+ SERVER_PROBE_TIMEOUT_MS = 5e3;
4256
+ OFFLINE_COMMANDS = [
4257
+ "adep init",
4258
+ "adep dev",
4259
+ "adep serve",
4260
+ "adep widget init",
4261
+ "adep widget dev",
4262
+ "adep db\uFF08\u672C\u5730\u6A21\u62DF\uFF09",
4263
+ "adep doctor"
4264
+ ];
4265
+ }
4266
+ });
4267
+
4268
+ // packages/cli/src/db.ts
4269
+ var db_exports = {};
4270
+ __export(db_exports, {
4271
+ dbExec: () => dbExec,
4272
+ dbRollback: () => dbRollback,
4273
+ dbSnapshotCreate: () => dbSnapshotCreate,
4274
+ dbSnapshotList: () => dbSnapshotList,
4275
+ dbSnapshotRestore: () => dbSnapshotRestore,
4276
+ dbStart: () => dbStart,
4277
+ dbStatus: () => dbStatus,
4278
+ dbStop: () => dbStop
4279
+ });
4280
+ import { resolve as resolve10 } from "node:path";
4281
+ async function open2(paths, options) {
4282
+ const client = await createClient(paths);
4283
+ const project2 = await resolveSlug(resolve10(options.cwd), options.slug);
4284
+ return { client, project: project2 };
4285
+ }
4286
+ async function dbStart(paths, options) {
4287
+ const { client, project: project2 } = await open2(paths, options);
4288
+ return client.request(`/api/v1/projects/${project2}/database`, { method: "POST" });
4289
+ }
4290
+ async function dbStatus(paths, options) {
4291
+ const { client, project: project2 } = await open2(paths, options);
4292
+ return client.request(`/api/v1/projects/${project2}/database`);
4293
+ }
4294
+ async function dbStop(paths, options) {
4295
+ const { client, project: project2 } = await open2(paths, options);
4296
+ return client.request(`/api/v1/projects/${project2}/database`, {
4297
+ method: "DELETE"
4298
+ });
4299
+ }
4300
+ async function dbExec(paths, options) {
4301
+ const { client, project: project2 } = await open2(paths, options);
4302
+ return client.request(
4303
+ `/api/v1/projects/${project2}/database/console/sql`,
4304
+ {
4305
+ method: "POST",
4306
+ body: {
4307
+ sql: options.sql,
4308
+ ...options.params === void 0 ? {} : { params: options.params },
4309
+ ...options.confirmTable === void 0 ? {} : { confirmTable: options.confirmTable }
4310
+ }
4311
+ },
4312
+ "SQL_EXEC_FAILED"
4313
+ );
4314
+ }
4315
+ async function dbSnapshotList(paths, options) {
4316
+ const { client, project: project2 } = await open2(paths, options);
4317
+ return client.request(
4318
+ `/api/v1/projects/${project2}/database/snapshots`
4319
+ );
4320
+ }
4321
+ async function dbSnapshotCreate(paths, options) {
4322
+ const { client, project: project2 } = await open2(paths, options);
4323
+ return client.request(`/api/v1/projects/${project2}/database/snapshots`, {
4324
+ method: "POST"
4325
+ });
4326
+ }
4327
+ async function dbSnapshotRestore(paths, options) {
4328
+ const { client, project: project2 } = await open2(paths, options);
4329
+ return client.request(
4330
+ `/api/v1/projects/${project2}/database/snapshots/${options.snapshotId}/restore`,
4331
+ { method: "POST" }
4332
+ );
4333
+ }
4334
+ async function dbRollback(paths, options) {
4335
+ const { client, project: project2 } = await open2(paths, options);
4336
+ return client.request(
4337
+ `/api/v1/projects/${project2}/database/rollback`,
4338
+ { method: "POST", body: { to: options.to } }
4339
+ );
4340
+ }
4341
+ var init_db2 = __esm({
4342
+ "packages/cli/src/db.ts"() {
4343
+ "use strict";
4344
+ init_client();
4345
+ }
4346
+ });
4347
+
4348
+ // packages/cli/src/storage.ts
4349
+ var storage_exports = {};
4350
+ __export(storage_exports, {
4351
+ contentTypeOf: () => contentTypeOf,
4352
+ storageDownload: () => storageDownload,
4353
+ storageList: () => storageList,
4354
+ storageRemove: () => storageRemove,
4355
+ storageUpload: () => storageUpload
4356
+ });
4357
+ import { mkdir as mkdir7, readFile as readFile8, stat as stat8, writeFile as writeFile6 } from "node:fs/promises";
4358
+ import { basename as basename3, dirname as dirname7, extname, join as join12, resolve as resolve11 } from "node:path";
4359
+ async function open3(paths, options) {
4360
+ const client = await createClient(paths);
4361
+ const project2 = await resolveSlug(resolve11(options.cwd), options.slug);
4362
+ return { client, project: project2 };
4363
+ }
4364
+ function contentTypeOf(path) {
4365
+ const map = {
4366
+ ".html": "text/html; charset=utf-8",
4367
+ ".htm": "text/html; charset=utf-8",
4368
+ ".css": "text/css; charset=utf-8",
4369
+ ".js": "text/javascript; charset=utf-8",
4370
+ ".mjs": "text/javascript; charset=utf-8",
4371
+ ".json": "application/json; charset=utf-8",
4372
+ ".png": "image/png",
4373
+ ".jpg": "image/jpeg",
4374
+ ".jpeg": "image/jpeg",
4375
+ ".gif": "image/gif",
4376
+ ".svg": "image/svg+xml",
4377
+ ".webp": "image/webp",
4378
+ ".ico": "image/x-icon",
3245
4379
  ".txt": "text/plain; charset=utf-8",
3246
4380
  ".md": "text/markdown; charset=utf-8",
3247
4381
  ".xml": "application/xml",
@@ -3257,13 +4391,13 @@ function contentTypeOf(path) {
3257
4391
  }
3258
4392
  async function storageUpload(paths, options) {
3259
4393
  const { client, project: project2 } = await open3(paths, options);
3260
- const local = resolve8(options.file);
3261
- const info = await stat6(local).catch(() => null);
4394
+ const local = resolve11(options.file);
4395
+ const info = await stat8(local).catch(() => null);
3262
4396
  if (info === null || !info.isFile()) {
3263
4397
  throw new CliError("FILE_NOT_FOUND", `\u672C\u5730\u6587\u4EF6\u4E0D\u5B58\u5728\uFF1A${local}`);
3264
4398
  }
3265
4399
  const visibility = options.visibility ?? "private";
3266
- const bytes = await readFile7(local);
4400
+ const bytes = await readFile8(local);
3267
4401
  const form = new FormData();
3268
4402
  form.set("path", options.path);
3269
4403
  form.set("visibility", visibility);
@@ -3304,7 +4438,7 @@ async function storageDownload(paths, options) {
3304
4438
  const url = await resolveDownloadUrl(client, project2, options.path);
3305
4439
  const response = await client.download(url, "STORAGE_DOWNLOAD_FAILED");
3306
4440
  const bytes = Buffer.from(await response.arrayBuffer());
3307
- const output = resolve8(options.output ?? join11(resolve8(options.cwd), basename3(options.path)));
4441
+ const output = resolve11(options.output ?? join12(resolve11(options.cwd), basename3(options.path)));
3308
4442
  await mkdir7(dirname7(output), { recursive: true });
3309
4443
  await writeFile6(output, bytes);
3310
4444
  return { path: options.path, output, size: bytes.length };
@@ -3332,11 +4466,11 @@ __export(hosting_exports, {
3332
4466
  hostingInfo: () => hostingInfo,
3333
4467
  hostingPull: () => hostingPull
3334
4468
  });
3335
- import { readdir as readdir4, readFile as readFile8, stat as stat7 } from "node:fs/promises";
3336
- import { dirname as dirname8, join as join12, relative, resolve as resolve9, sep } from "node:path";
4469
+ import { readdir as readdir5, readFile as readFile9, stat as stat9 } from "node:fs/promises";
4470
+ import { dirname as dirname8, join as join13, relative as relative2, resolve as resolve12, sep } from "node:path";
3337
4471
  async function open4(paths, options) {
3338
4472
  const client = await createClient(paths);
3339
- const project2 = await resolveSlug(resolve9(options.cwd), options.slug);
4473
+ const project2 = await resolveSlug(resolve12(options.cwd), options.slug);
3340
4474
  return { client, project: project2 };
3341
4475
  }
3342
4476
  async function hostingInfo(paths, options) {
@@ -3349,104 +4483,782 @@ async function hostingInfo(paths, options) {
3349
4483
  };
3350
4484
  }
3351
4485
  async function collectSiteFiles(dir) {
3352
- const root = resolve9(dir);
4486
+ const root = resolve12(dir);
3353
4487
  const files = /* @__PURE__ */ new Map();
3354
4488
  const walk = async (sub) => {
3355
4489
  let entries;
3356
4490
  try {
3357
- entries = await readdir4(sub, { withFileTypes: true });
4491
+ entries = await readdir5(sub, { withFileTypes: true });
3358
4492
  } catch {
3359
4493
  return;
3360
4494
  }
3361
4495
  for (const entry of entries) {
3362
- const full = join12(sub, entry.name);
4496
+ const full = join13(sub, entry.name);
3363
4497
  if (entry.isDirectory()) {
3364
4498
  await walk(full);
3365
4499
  } else if (entry.isFile()) {
3366
- const rel = relative(root, full).split(sep).join("/");
4500
+ const rel = relative2(root, full).split(sep).join("/");
3367
4501
  files.set(rel, full);
3368
4502
  }
3369
4503
  }
3370
4504
  };
3371
- await walk(root);
3372
- return files;
4505
+ await walk(root);
4506
+ return files;
4507
+ }
4508
+ async function hostingDeploy(paths, options) {
4509
+ const { client, project: project2 } = await open4(paths, options);
4510
+ const log = options.log ?? ((line) => process.stdout.write(`${line}
4511
+ `));
4512
+ const files = await collectSiteFiles(options.dir);
4513
+ if (files.size === 0) {
4514
+ throw new CliError("NO_SITE_FILES", `\u7AD9\u70B9\u76EE\u5F55\u4E3A\u7A7A\uFF1A${resolve12(options.dir)}`);
4515
+ }
4516
+ const uploaded = [];
4517
+ for (const [rel, full] of files) {
4518
+ log(`[adep] \u4E0A\u4F20 site/${rel}`);
4519
+ const info2 = await stat9(full);
4520
+ const bytes = await readFile9(full);
4521
+ const form = new FormData();
4522
+ form.set("path", `site/${rel}`);
4523
+ form.set("visibility", "public");
4524
+ form.set(
4525
+ "file",
4526
+ new Blob([bytes], { type: contentTypeOf(rel) }),
4527
+ rel.split("/").pop()
4528
+ );
4529
+ await client.upload(`/api/v1/projects/${project2}/files`, form, "HOSTING_UPLOAD_FAILED");
4530
+ uploaded.push({ path: `site/${rel}`, size: info2.size });
4531
+ }
4532
+ const config = await client.request(
4533
+ `/api/v1/projects/${project2}/hosting`,
4534
+ {
4535
+ method: "PUT",
4536
+ body: options.spa === void 0 ? { enabled: true } : { enabled: true, spaMode: options.spa }
4537
+ }
4538
+ );
4539
+ const info = await hostingInfo(paths, options);
4540
+ return { config: config.config, siteUrl: info.siteUrl, uploaded };
4541
+ }
4542
+ async function hostingPull(paths, options) {
4543
+ const { client } = await open4(paths, options);
4544
+ const log = options.log ?? ((line) => process.stdout.write(`${line}
4545
+ `));
4546
+ const info = await hostingInfo(paths, options);
4547
+ const outputDir = resolve12(options.output ?? resolve12(options.cwd));
4548
+ const { mkdir: mkdir9, writeFile: writeFile9 } = await import("node:fs/promises");
4549
+ const files = [];
4550
+ for (const entry of info.files) {
4551
+ if (entry.visibility !== "public" || entry.path === HOSTING_CONFIG_PATH) continue;
4552
+ const url = entry.url;
4553
+ if (url === void 0 || url.length === 0) continue;
4554
+ log(`[adep] \u4E0B\u8F7D ${entry.path}`);
4555
+ const response = await client.download(url, "HOSTING_DOWNLOAD_FAILED");
4556
+ const bytes = Buffer.from(await response.arrayBuffer());
4557
+ const rel = entry.path.replace(/^site\//, "");
4558
+ const target = join13(outputDir, ...rel.split("/"));
4559
+ await mkdir9(dirname8(target), { recursive: true });
4560
+ await writeFile9(target, bytes);
4561
+ files.push({ path: entry.path, size: bytes.length });
4562
+ }
4563
+ return { siteUrl: info.siteUrl, outputDir, files };
4564
+ }
4565
+ async function hostingConfig(paths, options) {
4566
+ const { client, project: project2 } = await open4(paths, options);
4567
+ const body = {};
4568
+ if (options.enabled !== void 0) body["enabled"] = options.enabled;
4569
+ if (options.spa !== void 0) body["spaMode"] = options.spa;
4570
+ const result = await client.request(
4571
+ `/api/v1/projects/${project2}/hosting`,
4572
+ { method: "PUT", body }
4573
+ );
4574
+ return result.config;
4575
+ }
4576
+ var HOSTING_CONFIG_PATH;
4577
+ var init_hosting = __esm({
4578
+ "packages/cli/src/hosting.ts"() {
4579
+ "use strict";
4580
+ init_client();
4581
+ init_auth();
4582
+ init_storage2();
4583
+ HOSTING_CONFIG_PATH = "site/.hosting.json";
4584
+ }
4585
+ });
4586
+
4587
+ // packages/cli/src/export/client.ts
4588
+ var client_exports2 = {};
4589
+ __export(client_exports2, {
4590
+ createExportApiClient: () => createExportApiClient
4591
+ });
4592
+ import { writeFile as writeFile7 } from "node:fs/promises";
4593
+ function toExportJob(view) {
4594
+ return {
4595
+ id: view.id,
4596
+ status: view.status,
4597
+ progress: view.progress,
4598
+ createdAt: view.createdAt,
4599
+ ...view.stage === void 0 ? {} : { stage: view.stage },
4600
+ ...view.error === void 0 ? {} : { error: view.error },
4601
+ ...view.downloadUrl === void 0 ? {} : { downloadUrl: view.downloadUrl },
4602
+ ...view.bundleSize === void 0 ? {} : { bundleSize: view.bundleSize },
4603
+ ...view.completedAt === void 0 ? {} : { completedAt: view.completedAt }
4604
+ };
4605
+ }
4606
+ async function createExportApiClient(paths) {
4607
+ const client = await createClient(paths);
4608
+ return {
4609
+ async triggerExport(projectId, options) {
4610
+ const view = await client.request(
4611
+ `/api/v1/projects/${encodeURIComponent(projectId)}/export`,
4612
+ { method: "POST", body: { withData: options.withData, withSource: options.withSource } },
4613
+ "EXPORT_TRIGGER_FAILED"
4614
+ );
4615
+ return toExportJob(view);
4616
+ },
4617
+ async getJobStatus(jobId) {
4618
+ const view = await client.request(
4619
+ `/api/v1/exports/${encodeURIComponent(jobId)}`,
4620
+ {},
4621
+ "EXPORT_STATUS_FAILED"
4622
+ );
4623
+ return toExportJob(view);
4624
+ },
4625
+ async downloadBundle(jobId, outputPath) {
4626
+ const download = await client.request(
4627
+ `/api/v1/exports/${encodeURIComponent(jobId)}/download`,
4628
+ {},
4629
+ "EXPORT_DOWNLOAD_FAILED"
4630
+ );
4631
+ if (download.downloadUrl.length === 0) {
4632
+ throw new CliError("EXPORT_BUNDLE_UNAVAILABLE", "\u5BFC\u51FA\u4EA7\u7269\u4E0B\u8F7D URL \u4E3A\u7A7A\uFF0C\u4EA7\u7269\u53EF\u80FD\u5C1A\u4E0D\u53EF\u7528");
4633
+ }
4634
+ const response = await client.download(download.downloadUrl, "EXPORT_DOWNLOAD_FAILED");
4635
+ const bytes = Buffer.from(await response.arrayBuffer());
4636
+ await writeFile7(outputPath, bytes);
4637
+ return { path: outputPath, size: bytes.length };
4638
+ }
4639
+ };
4640
+ }
4641
+ var init_client2 = __esm({
4642
+ "packages/cli/src/export/client.ts"() {
4643
+ "use strict";
4644
+ init_auth();
4645
+ init_client();
4646
+ }
4647
+ });
4648
+
4649
+ // shared/deploy-bundle/zip.ts
4650
+ function zipRead(buf) {
4651
+ const r = new Reader(buf);
4652
+ const eocd = findEocd(buf);
4653
+ if (eocd < 0) throw new ZipFormatError("\u627E\u4E0D\u5230 EOCD \u7B7E\u540D");
4654
+ const total = r.u16(eocd + 10);
4655
+ const centralOffset = r.u32(eocd + 16);
4656
+ const decoder = new TextDecoder();
4657
+ const out = /* @__PURE__ */ new Map();
4658
+ let cursor = centralOffset;
4659
+ for (let i = 0; i < total; i++) {
4660
+ if (cursor + 46 > buf.length) throw new ZipFormatError("\u4E2D\u592E\u76EE\u5F55\u8BB0\u5F55\u8D8A\u754C");
4661
+ if (r.u32(cursor) !== SIG_CENTRAL) throw new ZipFormatError("\u4E2D\u592E\u76EE\u5F55\u7B7E\u540D\u4E0D\u5339\u914D");
4662
+ const method = r.u16(cursor + 10);
4663
+ if (method !== 0) throw new ZipFormatError("\u4EC5\u652F\u6301 store \u578B\u6761\u76EE\u8BFB\u53D6");
4664
+ const compSize = r.u32(cursor + 20);
4665
+ const nameLen = r.u16(cursor + 28);
4666
+ const extraLen = r.u16(cursor + 30);
4667
+ const commentLen = r.u16(cursor + 32);
4668
+ const localHeaderOffset = r.u32(cursor + 42);
4669
+ if (localHeaderOffset + 30 > buf.length) throw new ZipFormatError("\u672C\u5730\u5934\u504F\u79FB\u8D8A\u754C");
4670
+ const name = decoder.decode(r.slice(cursor + 46, nameLen));
4671
+ const localNameLen = r.u16(localHeaderOffset + 26);
4672
+ const localExtraLen = r.u16(localHeaderOffset + 28);
4673
+ const dataStart = localHeaderOffset + 30 + localNameLen + localExtraLen;
4674
+ if (dataStart + compSize > buf.length) throw new ZipFormatError("\u6761\u76EE\u6570\u636E\u8D8A\u754C");
4675
+ if (!out.has(name)) out.set(name, r.slice(dataStart, compSize));
4676
+ cursor += 46 + nameLen + extraLen + commentLen;
4677
+ }
4678
+ return out;
4679
+ }
4680
+ function findEocd(buf) {
4681
+ const view = new DataView(buf.buffer, buf.byteOffset, buf.byteLength);
4682
+ const min = Math.max(0, buf.length - 65557);
4683
+ for (let i = buf.length - 22; i >= min; i--) {
4684
+ if (view.getUint32(i, true) === SIG_EOCD) return i;
4685
+ }
4686
+ return -1;
4687
+ }
4688
+ var SIG_CENTRAL, SIG_EOCD, CRC_TABLE, Reader, ZipFormatError;
4689
+ var init_zip = __esm({
4690
+ "shared/deploy-bundle/zip.ts"() {
4691
+ "use strict";
4692
+ SIG_CENTRAL = 33639248;
4693
+ SIG_EOCD = 101010256;
4694
+ CRC_TABLE = (() => {
4695
+ const table = new Uint32Array(256);
4696
+ for (let i = 0; i < 256; i++) {
4697
+ let c = i;
4698
+ for (let k = 0; k < 8; k++) c = c & 1 ? 3988292384 ^ c >>> 1 : c >>> 1;
4699
+ table[i] = c >>> 0;
4700
+ }
4701
+ return table;
4702
+ })();
4703
+ Reader = class {
4704
+ constructor(buf) {
4705
+ this.buf = buf;
4706
+ this.view = new DataView(buf.buffer, buf.byteOffset, buf.byteLength);
4707
+ }
4708
+ view;
4709
+ u16(offset) {
4710
+ return this.view.getUint16(offset, true);
4711
+ }
4712
+ u32(offset) {
4713
+ return this.view.getUint32(offset, true);
4714
+ }
4715
+ slice(start, length) {
4716
+ return this.buf.subarray(start, start + length);
4717
+ }
4718
+ };
4719
+ ZipFormatError = class extends Error {
4720
+ constructor(message) {
4721
+ super(`[appexport] \u975E\u6CD5 zip\uFF1A${message}`);
4722
+ this.name = "ZipFormatError";
4723
+ }
4724
+ };
4725
+ }
4726
+ });
4727
+
4728
+ // packages/cli/src/export/fs.ts
4729
+ var fs_exports = {};
4730
+ __export(fs_exports, {
4731
+ createExportFileSystem: () => createExportFileSystem
4732
+ });
4733
+ import { mkdir as mkdir8, readFile as readFile10, rm as rm3, stat as stat10, writeFile as writeFile8 } from "node:fs/promises";
4734
+ import { dirname as dirname9, join as join14 } from "node:path";
4735
+ function createExportFileSystem() {
4736
+ return {
4737
+ readFile: (path) => readFile10(path),
4738
+ writeFile: (path, content) => writeFile8(path, content),
4739
+ // 同时用于清理解压临时目录(${zip}.tmp 是个目录)——递归强制删除,缺失不报错。
4740
+ deleteFile: async (path) => {
4741
+ await rm3(path, { recursive: true, force: true });
4742
+ },
4743
+ fileExists: async (path) => {
4744
+ try {
4745
+ await stat10(path);
4746
+ return true;
4747
+ } catch {
4748
+ return false;
4749
+ }
4750
+ },
4751
+ mkdir: async (path) => {
4752
+ await mkdir8(path, { recursive: true });
4753
+ },
4754
+ unzip: async (zipPath, targetDir) => {
4755
+ const entries = zipRead(await readFile10(zipPath));
4756
+ for (const [name, data] of entries) {
4757
+ const dest = join14(targetDir, name);
4758
+ await mkdir8(dirname9(dest), { recursive: true });
4759
+ await writeFile8(dest, data);
4760
+ }
4761
+ }
4762
+ };
4763
+ }
4764
+ var init_fs = __esm({
4765
+ "packages/cli/src/export/fs.ts"() {
4766
+ "use strict";
4767
+ init_zip();
4768
+ }
4769
+ });
4770
+
4771
+ // shared/deploy-bundle/manifest.ts
4772
+ var CURRENT_SCHEMA_VERSION, BundleContentKind, ALLOWED_CONTENT_KINDS;
4773
+ var init_manifest2 = __esm({
4774
+ "shared/deploy-bundle/manifest.ts"() {
4775
+ "use strict";
4776
+ CURRENT_SCHEMA_VERSION = 1;
4777
+ BundleContentKind = {
4778
+ /** 云函数代码与配置。 */
4779
+ Functions: "functions",
4780
+ /** 数据库 schema 与种子数据。 */
4781
+ Database: "database",
4782
+ /** 前端静态资源。 */
4783
+ Web: "web",
4784
+ /** 运行时配置(Dockerfile / docker-compose.yml)。 */
4785
+ Runtime: "runtime",
4786
+ /** 启动 / 备份 / 恢复脚本。 */
4787
+ Scripts: "scripts",
4788
+ /** 文档(README / 部署手册)。 */
4789
+ Docs: "docs"
4790
+ };
4791
+ ALLOWED_CONTENT_KINDS = Object.values(BundleContentKind);
4792
+ }
4793
+ });
4794
+
4795
+ // shared/deploy-bundle/validate.ts
4796
+ function validateBundleManifest(manifest) {
4797
+ const errors = [];
4798
+ const warnings = [];
4799
+ if (typeof manifest !== "object" || manifest === null) {
4800
+ return {
4801
+ valid: false,
4802
+ errors: [{ code: "INVALID_TYPE", message: "Manifest \u5FC5\u987B\u662F\u5BF9\u8C61" }],
4803
+ warnings: []
4804
+ };
4805
+ }
4806
+ const m = manifest;
4807
+ const schemaVersion = m.schemaVersion;
4808
+ if (typeof schemaVersion !== "number" || !Number.isInteger(schemaVersion)) {
4809
+ errors.push({
4810
+ code: "INVALID_SCHEMA_VERSION",
4811
+ message: "schemaVersion \u5FC5\u987B\u662F\u6574\u6570",
4812
+ field: "schemaVersion"
4813
+ });
4814
+ } else if (schemaVersion > CURRENT_SCHEMA_VERSION) {
4815
+ errors.push({
4816
+ code: "SCHEMA_VERSION_TOO_HIGH",
4817
+ message: `schemaVersion ${schemaVersion} \u9AD8\u4E8E\u5F53\u524D\u652F\u6301\u7248\u672C ${CURRENT_SCHEMA_VERSION}\uFF0C\u9700\u5347\u7EA7\u5BFC\u51FA\u7AEF`,
4818
+ field: "schemaVersion"
4819
+ });
4820
+ } else if (schemaVersion < CURRENT_SCHEMA_VERSION) {
4821
+ warnings.push({
4822
+ code: "SCHEMA_VERSION_LOW",
4823
+ message: `schemaVersion ${schemaVersion} \u4F4E\u4E8E\u5F53\u524D\u7248\u672C ${CURRENT_SCHEMA_VERSION}\uFF0C\u5EFA\u8BAE\u91CD\u65B0\u5BFC\u51FA`,
4824
+ field: "schemaVersion"
4825
+ });
4826
+ }
4827
+ if (typeof m.platformVersion !== "string" || m.platformVersion.trim() === "") {
4828
+ errors.push({
4829
+ code: "MISSING_PLATFORM_VERSION",
4830
+ message: "platformVersion \u5FC5\u987B\u975E\u7A7A",
4831
+ field: "platformVersion"
4832
+ });
4833
+ }
4834
+ if (typeof m.project !== "object" || m.project === null) {
4835
+ errors.push({
4836
+ code: "MISSING_PROJECT",
4837
+ message: "project \u5FC5\u987B\u662F\u5BF9\u8C61",
4838
+ field: "project"
4839
+ });
4840
+ } else {
4841
+ const project2 = m.project;
4842
+ if (typeof project2.id !== "string" || project2.id.trim() === "") {
4843
+ errors.push({
4844
+ code: "MISSING_PROJECT_ID",
4845
+ message: "project.id \u5FC5\u987B\u975E\u7A7A",
4846
+ field: "project.id"
4847
+ });
4848
+ }
4849
+ if (typeof project2.name !== "string" || project2.name.trim() === "") {
4850
+ errors.push({
4851
+ code: "MISSING_PROJECT_NAME",
4852
+ message: "project.name \u5FC5\u987B\u975E\u7A7A",
4853
+ field: "project.name"
4854
+ });
4855
+ }
4856
+ if (typeof project2.slug !== "string" || project2.slug.trim() === "") {
4857
+ errors.push({
4858
+ code: "MISSING_PROJECT_SLUG",
4859
+ message: "project.slug \u5FC5\u987B\u975E\u7A7A",
4860
+ field: "project.slug"
4861
+ });
4862
+ }
4863
+ if (typeof project2.version !== "number" || !Number.isInteger(project2.version) || project2.version < 1) {
4864
+ errors.push({
4865
+ code: "INVALID_PROJECT_VERSION",
4866
+ message: "project.version \u5FC5\u987B\u662F\u6B63\u6574\u6570",
4867
+ field: "project.version"
4868
+ });
4869
+ }
4870
+ }
4871
+ if (!Array.isArray(m.contents)) {
4872
+ errors.push({
4873
+ code: "MISSING_CONTENTS",
4874
+ message: "contents \u5FC5\u987B\u662F\u6570\u7EC4",
4875
+ field: "contents"
4876
+ });
4877
+ } else if (m.contents.length === 0) {
4878
+ errors.push({
4879
+ code: "EMPTY_CONTENTS",
4880
+ message: "contents \u4E0D\u80FD\u4E3A\u7A7A",
4881
+ field: "contents"
4882
+ });
4883
+ } else {
4884
+ m.contents.forEach((content, index) => {
4885
+ validateContent(content, index, errors, warnings);
4886
+ });
4887
+ }
4888
+ if (typeof m.runtime !== "object" || m.runtime === null) {
4889
+ errors.push({
4890
+ code: "MISSING_RUNTIME",
4891
+ message: "runtime \u5FC5\u987B\u662F\u5BF9\u8C61",
4892
+ field: "runtime"
4893
+ });
4894
+ } else {
4895
+ const runtime = m.runtime;
4896
+ if (typeof runtime.engine !== "string" || runtime.engine.trim() === "") {
4897
+ errors.push({
4898
+ code: "MISSING_ENGINE",
4899
+ message: "runtime.engine \u5FC5\u987B\u975E\u7A7A",
4900
+ field: "runtime.engine"
4901
+ });
4902
+ }
4903
+ if (typeof runtime.engineVersion !== "string" || runtime.engineVersion.trim() === "") {
4904
+ errors.push({
4905
+ code: "MISSING_ENGINE_VERSION",
4906
+ message: "runtime.engineVersion \u5FC5\u987B\u975E\u7A7A",
4907
+ field: "runtime.engineVersion"
4908
+ });
4909
+ }
4910
+ if (typeof runtime.port !== "number" || !Number.isInteger(runtime.port) || runtime.port < 1 || runtime.port > 65535) {
4911
+ errors.push({
4912
+ code: "INVALID_PORT",
4913
+ message: "runtime.port \u5FC5\u987B\u662F 1-65535 \u7684\u6574\u6570",
4914
+ field: "runtime.port"
4915
+ });
4916
+ }
4917
+ if (typeof runtime.startCommand !== "string" || runtime.startCommand.trim() === "") {
4918
+ errors.push({
4919
+ code: "MISSING_START_COMMAND",
4920
+ message: "runtime.startCommand \u5FC5\u987B\u975E\u7A7A",
4921
+ field: "runtime.startCommand"
4922
+ });
4923
+ }
4924
+ }
4925
+ if (typeof m.exportedAt !== "string" || m.exportedAt.trim() === "") {
4926
+ errors.push({
4927
+ code: "MISSING_EXPORTED_AT",
4928
+ message: "exportedAt \u5FC5\u987B\u975E\u7A7A",
4929
+ field: "exportedAt"
4930
+ });
4931
+ } else {
4932
+ const date = new Date(m.exportedAt);
4933
+ if (Number.isNaN(date.getTime())) {
4934
+ errors.push({
4935
+ code: "INVALID_EXPORTED_AT",
4936
+ message: "exportedAt \u5FC5\u987B\u662F\u6709\u6548\u7684 ISO 8601 \u65F6\u95F4",
4937
+ field: "exportedAt"
4938
+ });
4939
+ }
4940
+ }
4941
+ return {
4942
+ valid: errors.length === 0,
4943
+ errors,
4944
+ warnings
4945
+ };
3373
4946
  }
3374
- async function hostingDeploy(paths, options) {
3375
- const { client, project: project2 } = await open4(paths, options);
3376
- const log = options.log ?? ((line) => process.stdout.write(`${line}
3377
- `));
3378
- const files = await collectSiteFiles(options.dir);
3379
- if (files.size === 0) {
3380
- throw new CliError("NO_SITE_FILES", `\u7AD9\u70B9\u76EE\u5F55\u4E3A\u7A7A\uFF1A${resolve9(options.dir)}`);
4947
+ function validateContent(content, index, errors, _warnings) {
4948
+ if (typeof content !== "object" || content === null) {
4949
+ errors.push({
4950
+ code: "INVALID_CONTENT",
4951
+ message: `contents[${index}] \u5FC5\u987B\u662F\u5BF9\u8C61`,
4952
+ field: `contents[${index}]`
4953
+ });
4954
+ return;
3381
4955
  }
3382
- const uploaded = [];
3383
- for (const [rel, full] of files) {
3384
- log(`[adep] \u4E0A\u4F20 site/${rel}`);
3385
- const info2 = await stat7(full);
3386
- const bytes = await readFile8(full);
3387
- const form = new FormData();
3388
- form.set("path", `site/${rel}`);
3389
- form.set("visibility", "public");
3390
- form.set(
3391
- "file",
3392
- new Blob([bytes], { type: contentTypeOf(rel) }),
3393
- rel.split("/").pop()
3394
- );
3395
- await client.upload(`/api/v1/projects/${project2}/files`, form, "HOSTING_UPLOAD_FAILED");
3396
- uploaded.push({ path: `site/${rel}`, size: info2.size });
4956
+ const c = content;
4957
+ if (typeof c.path !== "string" || c.path.trim() === "") {
4958
+ errors.push({
4959
+ code: "MISSING_CONTENT_PATH",
4960
+ message: `contents[${index}].path \u5FC5\u987B\u975E\u7A7A`,
4961
+ field: `contents[${index}].path`
4962
+ });
3397
4963
  }
3398
- const config = await client.request(
3399
- `/api/v1/projects/${project2}/hosting`,
3400
- {
3401
- method: "PUT",
3402
- body: options.spa === void 0 ? { enabled: true } : { enabled: true, spaMode: options.spa }
3403
- }
3404
- );
3405
- const info = await hostingInfo(paths, options);
3406
- return { config: config.config, siteUrl: info.siteUrl, uploaded };
3407
- }
3408
- async function hostingPull(paths, options) {
3409
- const { client } = await open4(paths, options);
3410
- const log = options.log ?? ((line) => process.stdout.write(`${line}
3411
- `));
3412
- const info = await hostingInfo(paths, options);
3413
- const outputDir = resolve9(options.output ?? resolve9(options.cwd));
3414
- const { mkdir: mkdir8, writeFile: writeFile7 } = await import("node:fs/promises");
3415
- const files = [];
3416
- for (const entry of info.files) {
3417
- if (entry.visibility !== "public" || entry.path === HOSTING_CONFIG_PATH) continue;
3418
- const url = entry.url;
3419
- if (url === void 0 || url.length === 0) continue;
3420
- log(`[adep] \u4E0B\u8F7D ${entry.path}`);
3421
- const response = await client.download(url, "HOSTING_DOWNLOAD_FAILED");
3422
- const bytes = Buffer.from(await response.arrayBuffer());
3423
- const rel = entry.path.replace(/^site\//, "");
3424
- const target = join12(outputDir, ...rel.split("/"));
3425
- await mkdir8(dirname8(target), { recursive: true });
3426
- await writeFile7(target, bytes);
3427
- files.push({ path: entry.path, size: bytes.length });
4964
+ if (typeof c.sha256 !== "string" || c.sha256.trim() === "") {
4965
+ errors.push({
4966
+ code: "MISSING_CONTENT_SHA256",
4967
+ message: `contents[${index}].sha256 \u5FC5\u987B\u975E\u7A7A`,
4968
+ field: `contents[${index}].sha256`
4969
+ });
4970
+ } else if (!/^[a-fA-F0-9]{64}$/.test(c.sha256)) {
4971
+ errors.push({
4972
+ code: "INVALID_SHA256_FORMAT",
4973
+ message: `contents[${index}].sha256 \u5FC5\u987B\u662F 64 \u5B57\u7B26\u5341\u516D\u8FDB\u5236`,
4974
+ field: `contents[${index}].sha256`
4975
+ });
4976
+ }
4977
+ if (typeof c.kind !== "string" || c.kind.trim() === "") {
4978
+ errors.push({
4979
+ code: "MISSING_CONTENT_KIND",
4980
+ message: `contents[${index}].kind \u5FC5\u987B\u975E\u7A7A`,
4981
+ field: `contents[${index}].kind`
4982
+ });
4983
+ } else if (!ALLOWED_CONTENT_KINDS.includes(c.kind)) {
4984
+ errors.push({
4985
+ code: "INVALID_CONTENT_KIND",
4986
+ message: `contents[${index}].kind "${c.kind}" \u4E0D\u5728\u5141\u8BB8\u5217\u8868\u5185\uFF0C\u5141\u8BB8\u503C\uFF1A${ALLOWED_CONTENT_KINDS.join(", ")}`,
4987
+ field: `contents[${index}].kind`
4988
+ });
3428
4989
  }
3429
- return { siteUrl: info.siteUrl, outputDir, files };
3430
4990
  }
3431
- async function hostingConfig(paths, options) {
3432
- const { client, project: project2 } = await open4(paths, options);
3433
- const body = {};
3434
- if (options.enabled !== void 0) body["enabled"] = options.enabled;
3435
- if (options.spa !== void 0) body["spaMode"] = options.spa;
3436
- const result = await client.request(
3437
- `/api/v1/projects/${project2}/hosting`,
3438
- { method: "PUT", body }
3439
- );
3440
- return result.config;
4991
+ function verifyContents(contents, actualContents, hashFunction) {
4992
+ const errors = [];
4993
+ const warnings = [];
4994
+ for (const content of contents) {
4995
+ const actual = actualContents.get(content.path);
4996
+ if (actual === void 0) {
4997
+ errors.push({
4998
+ code: "CONTENT_NOT_FOUND",
4999
+ message: `\u5185\u5BB9\u7269 ${content.path} \u5728\u5B9E\u9645\u5305\u4E2D\u4E0D\u5B58\u5728`,
5000
+ field: `contents[${content.path}]`
5001
+ });
5002
+ continue;
5003
+ }
5004
+ const actualHash = hashFunction(actual);
5005
+ if (actualHash.toLowerCase() !== content.sha256.toLowerCase()) {
5006
+ errors.push({
5007
+ code: "CHECKSUM_MISMATCH",
5008
+ message: `\u5185\u5BB9\u7269 ${content.path} \u7684\u6821\u9A8C\u548C\u4E0D\u5339\u914D\uFF1A\u671F\u671B ${content.sha256}\uFF0C\u5B9E\u9645 ${actualHash}`,
5009
+ field: `contents[${content.path}].sha256`
5010
+ });
5011
+ }
5012
+ }
5013
+ for (const path of actualContents.keys()) {
5014
+ if (!contents.some((c) => c.path === path)) {
5015
+ warnings.push({
5016
+ code: "UNDECLARED_CONTENT",
5017
+ message: `\u5B9E\u9645\u5305\u4E2D\u5B58\u5728 Manifest \u672A\u58F0\u660E\u7684\u5185\u5BB9\uFF1A${path}`,
5018
+ field: `contents[${path}]`
5019
+ });
5020
+ }
5021
+ }
5022
+ return {
5023
+ valid: errors.length === 0,
5024
+ errors,
5025
+ warnings
5026
+ };
3441
5027
  }
3442
- var HOSTING_CONFIG_PATH;
3443
- var init_hosting = __esm({
3444
- "packages/cli/src/hosting.ts"() {
5028
+ var init_validate = __esm({
5029
+ "shared/deploy-bundle/validate.ts"() {
3445
5030
  "use strict";
3446
- init_client();
3447
- init_auth();
3448
- init_storage2();
3449
- HOSTING_CONFIG_PATH = "site/.hosting.json";
5031
+ init_manifest2();
5032
+ }
5033
+ });
5034
+
5035
+ // packages/cli/src/export/command.ts
5036
+ var command_exports = {};
5037
+ __export(command_exports, {
5038
+ ExportCommand: () => ExportCommand
5039
+ });
5040
+ import { createHash as createHash4 } from "node:crypto";
5041
+ var ExportCommand;
5042
+ var init_command = __esm({
5043
+ "packages/cli/src/export/command.ts"() {
5044
+ "use strict";
5045
+ init_validate();
5046
+ ExportCommand = class {
5047
+ constructor(apiClient, fs, pollInterval = 2e3, maxPollAttempts = 300) {
5048
+ this.apiClient = apiClient;
5049
+ this.fs = fs;
5050
+ this.pollInterval = pollInterval;
5051
+ this.maxPollAttempts = maxPollAttempts;
5052
+ }
5053
+ /**
5054
+ * 执行导出命令。
5055
+ *
5056
+ * @param options 命令选项
5057
+ * @returns 导出结果
5058
+ */
5059
+ async execute(options) {
5060
+ const projectId = options.project ?? "default";
5061
+ const outputDir = options.out ?? "./exports";
5062
+ const jsonOutput = options.json ?? false;
5063
+ try {
5064
+ if (!jsonOutput) {
5065
+ console.log(`\u89E6\u53D1\u5BFC\u51FA\uFF1A\u9879\u76EE ${projectId}`);
5066
+ }
5067
+ const job = await this.apiClient.triggerExport(projectId, {
5068
+ withData: options.withData,
5069
+ withSource: options.withSource
5070
+ });
5071
+ if (!jsonOutput) {
5072
+ console.log(`\u5BFC\u51FA\u4EFB\u52A1\u5DF2\u521B\u5EFA\uFF1A${job.id}`);
5073
+ }
5074
+ const completedJob = await this.pollJobStatus(job.id, jsonOutput);
5075
+ if (completedJob.status === "failed") {
5076
+ return {
5077
+ success: false,
5078
+ jobId: job.id,
5079
+ status: "failed",
5080
+ error: completedJob.error ?? "\u5BFC\u51FA\u5931\u8D25"
5081
+ };
5082
+ }
5083
+ if (!jsonOutput) {
5084
+ console.log("\u4E0B\u8F7D\u5BFC\u51FA\u4EA7\u7269...");
5085
+ }
5086
+ const outputPath = `${outputDir}/${projectId}-export-${Date.now()}.zip`;
5087
+ await this.fs.mkdir(outputDir);
5088
+ const downloadResult = await this.apiClient.downloadBundle(job.id, outputPath);
5089
+ if (!jsonOutput) {
5090
+ console.log(`\u4EA7\u7269\u5DF2\u4E0B\u8F7D\uFF1A${downloadResult.path}\uFF08${this.formatSize(downloadResult.size)}\uFF09`);
5091
+ }
5092
+ if (!jsonOutput) {
5093
+ console.log("\u6267\u884C manifest \u81EA\u68C0...");
5094
+ }
5095
+ const manifest = await this.verifyManifest(downloadResult.path);
5096
+ if (!jsonOutput) {
5097
+ this.printContentList(manifest);
5098
+ }
5099
+ return {
5100
+ success: true,
5101
+ jobId: job.id,
5102
+ status: "completed",
5103
+ downloadPath: downloadResult.path,
5104
+ manifest: {
5105
+ projectName: manifest.project.name,
5106
+ platformVersion: manifest.platformVersion,
5107
+ exportedAt: manifest.exportedAt,
5108
+ contents: this.countContents(manifest.contents)
5109
+ }
5110
+ };
5111
+ } catch (error) {
5112
+ const message = error instanceof Error ? error.message : "unknown_error";
5113
+ if (message.includes("ECONNREFUSED") || message.includes("ENOTFOUND") || message.includes("network")) {
5114
+ return {
5115
+ success: false,
5116
+ error: `\u5E73\u53F0\u7AEF\u70B9\u4E0D\u53EF\u8FBE\uFF1A${message}\u3002\u8BF7\u68C0\u67E5\u7F51\u7EDC\u8FDE\u63A5\u548C\u5E73\u53F0\u5730\u5740\u914D\u7F6E\uFF0C\u7136\u540E\u91CD\u8BD5\u3002`
5117
+ };
5118
+ }
5119
+ return {
5120
+ success: false,
5121
+ error: message
5122
+ };
5123
+ }
5124
+ }
5125
+ /**
5126
+ * 轮询任务状态。
5127
+ *
5128
+ * @param jobId 任务 ID
5129
+ * @param jsonOutput 是否 JSON 输出
5130
+ * @returns 完成的任务
5131
+ */
5132
+ async pollJobStatus(jobId, jsonOutput) {
5133
+ let attempts = 0;
5134
+ let lastProgress = -1;
5135
+ while (attempts < this.maxPollAttempts) {
5136
+ const job = await this.apiClient.getJobStatus(jobId);
5137
+ if (!jsonOutput && job.progress !== lastProgress) {
5138
+ const stage = job.stage ? `\uFF08${job.stage}\uFF09` : "";
5139
+ console.log(`\u8FDB\u5EA6\uFF1A${job.progress}%${stage}`);
5140
+ lastProgress = job.progress;
5141
+ }
5142
+ if (job.status === "completed" || job.status === "failed") {
5143
+ return job;
5144
+ }
5145
+ attempts++;
5146
+ await this.sleep(this.pollInterval);
5147
+ }
5148
+ throw new Error(`\u5BFC\u51FA\u4EFB\u52A1\u8D85\u65F6\uFF1A\u8F6E\u8BE2 ${this.maxPollAttempts} \u6B21\u540E\u4ECD\u672A\u5B8C\u6210`);
5149
+ }
5150
+ /**
5151
+ * 验证 Manifest:解压 → 契约校验 → 逐项 sha256 校验 → 清理临时目录。
5152
+ *
5153
+ * 逐项校验与导出端同法:内容物以 latin1 承载(逐字节双射,二进制条目不被解码改写),
5154
+ * 比对时对原字节做真实 sha256;任一不匹配即判定包损坏并抛错,不静默放行。
5155
+ * 无论成功失败,`${zip}.tmp` 临时目录都在 finally 里删除,不留残余。
5156
+ *
5157
+ * @param zipPath ZIP 文件路径
5158
+ * @returns Manifest
5159
+ */
5160
+ async verifyManifest(zipPath) {
5161
+ const tempDir = `${zipPath}.tmp`;
5162
+ try {
5163
+ await this.fs.mkdir(tempDir);
5164
+ await this.fs.unzip(zipPath, tempDir);
5165
+ const manifestPath = `${tempDir}/manifest.json`;
5166
+ if (!await this.fs.fileExists(manifestPath)) {
5167
+ throw new Error("manifest.json \u4E0D\u5B58\u5728\uFF0C\u5305\u53EF\u80FD\u5DF2\u635F\u574F");
5168
+ }
5169
+ const manifestContent = await this.fs.readFile(manifestPath);
5170
+ const manifest = JSON.parse(manifestContent.toString("utf-8"));
5171
+ const validationResult = validateBundleManifest(manifest);
5172
+ if (!validationResult.valid) {
5173
+ const errors = validationResult.errors.map((e) => `${e.field ?? ""}: ${e.message}`).join("\n");
5174
+ throw new Error(`manifest \u6821\u9A8C\u5931\u8D25\uFF1A
5175
+ ${errors}`);
5176
+ }
5177
+ const actual = /* @__PURE__ */ new Map();
5178
+ for (const content of manifest.contents) {
5179
+ const filePath = `${tempDir}/${content.path}`;
5180
+ if (await this.fs.fileExists(filePath)) {
5181
+ const bytes = await this.fs.readFile(filePath);
5182
+ actual.set(content.path, bytes.toString("latin1"));
5183
+ }
5184
+ }
5185
+ const contentResult = verifyContents(
5186
+ manifest.contents,
5187
+ actual,
5188
+ (text) => createHash4("sha256").update(Buffer.from(text, "latin1")).digest("hex")
5189
+ );
5190
+ if (!contentResult.valid) {
5191
+ const detail = contentResult.errors.map((e) => e.message).join("\n");
5192
+ throw new Error(`\u5185\u5BB9\u7269\u6821\u9A8C\u548C\u4E0D\u5339\u914D\uFF1A
5193
+ ${detail}`);
5194
+ }
5195
+ return manifest;
5196
+ } finally {
5197
+ await this.fs.deleteFile(tempDir);
5198
+ }
5199
+ }
5200
+ /**
5201
+ * 统计内容物数量。
5202
+ *
5203
+ * @param contents 内容物列表
5204
+ * @returns 统计结果
5205
+ */
5206
+ countContents(contents) {
5207
+ return {
5208
+ functions: contents.filter((c) => c.kind === "functions").length,
5209
+ database: contents.filter((c) => c.kind === "database").length,
5210
+ web: contents.filter((c) => c.kind === "web").length,
5211
+ runtime: contents.filter((c) => c.kind === "runtime").length,
5212
+ scripts: contents.filter((c) => c.kind === "scripts").length,
5213
+ docs: contents.filter((c) => c.kind === "docs").length,
5214
+ total: contents.length
5215
+ };
5216
+ }
5217
+ /**
5218
+ * 打印内容清单。
5219
+ *
5220
+ * @param manifest Manifest
5221
+ */
5222
+ printContentList(manifest) {
5223
+ const counts = this.countContents(manifest.contents);
5224
+ console.log("");
5225
+ console.log("==========================================");
5226
+ console.log("\u5BFC\u51FA\u5185\u5BB9\u6E05\u5355");
5227
+ console.log("==========================================");
5228
+ console.log(`\u9879\u76EE\uFF1A${manifest.project.name}`);
5229
+ console.log(`\u5E73\u53F0\u7248\u672C\uFF1A${manifest.platformVersion}`);
5230
+ console.log(`\u5BFC\u51FA\u65F6\u95F4\uFF1A${manifest.exportedAt}`);
5231
+ console.log("");
5232
+ console.log(`\u51FD\u6570\u6587\u4EF6\uFF1A${counts.functions}`);
5233
+ console.log(`\u6570\u636E\u5E93\u6587\u4EF6\uFF1A${counts.database}`);
5234
+ console.log(`\u524D\u7AEF\u6587\u4EF6\uFF1A${counts.web}`);
5235
+ console.log(`\u8FD0\u884C\u65F6\u6587\u4EF6\uFF1A${counts.runtime}`);
5236
+ console.log(`\u811A\u672C\u6587\u4EF6\uFF1A${counts.scripts}`);
5237
+ console.log(`\u6587\u6863\u6587\u4EF6\uFF1A${counts.docs}`);
5238
+ console.log(`\u603B\u6587\u4EF6\u6570\uFF1A${counts.total}`);
5239
+ console.log("==========================================");
5240
+ }
5241
+ /**
5242
+ * 格式化文件大小。
5243
+ *
5244
+ * @param bytes 字节数
5245
+ * @returns 格式化后的大小
5246
+ */
5247
+ formatSize(bytes) {
5248
+ if (bytes < 1024) return `${bytes} B`;
5249
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
5250
+ if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
5251
+ return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)} GB`;
5252
+ }
5253
+ /**
5254
+ * 睡眠指定毫秒数。
5255
+ *
5256
+ * @param ms 毫秒数
5257
+ */
5258
+ sleep(ms) {
5259
+ return new Promise((resolve15) => setTimeout(resolve15, ms));
5260
+ }
5261
+ };
3450
5262
  }
3451
5263
  });
3452
5264
 
@@ -3456,23 +5268,23 @@ __export(dev_exports2, {
3456
5268
  loadWidgetProject: () => loadWidgetProject,
3457
5269
  startWidgetDev: () => startWidgetDev
3458
5270
  });
3459
- import { createServer as createServer2 } from "node:http";
5271
+ import { createServer as createServer3 } from "node:http";
3460
5272
  import { watch as watch2 } from "node:fs";
3461
- import { readFile as readFile9, stat as stat8 } from "node:fs/promises";
3462
- import { join as join13, resolve as resolve10 } from "node:path";
5273
+ import { readFile as readFile11, stat as stat11 } from "node:fs/promises";
5274
+ import { join as join15, resolve as resolve13 } from "node:path";
3463
5275
  async function loadWidgetProject(cwd) {
3464
5276
  const fallback = {
3465
5277
  name: "widget",
3466
5278
  framework: "vue3"
3467
5279
  };
3468
- const manifestPath = join13(resolve10(cwd), "manifest.json");
5280
+ const manifestPath = join15(resolve13(cwd), "manifest.json");
3469
5281
  try {
3470
- await stat8(manifestPath);
5282
+ await stat11(manifestPath);
3471
5283
  } catch {
3472
5284
  return fallback;
3473
5285
  }
3474
5286
  try {
3475
- const raw = await readFile9(manifestPath, "utf8");
5287
+ const raw = await readFile11(manifestPath, "utf8");
3476
5288
  const parsed = JSON.parse(raw);
3477
5289
  return {
3478
5290
  name: typeof parsed["name"] === "string" ? parsed["name"] : fallback.name,
@@ -3547,7 +5359,7 @@ function sandboxHtml(name, framework) {
3547
5359
  `;
3548
5360
  }
3549
5361
  async function startWidgetDev(options) {
3550
- const cwd = resolve10(options.cwd);
5362
+ const cwd = resolve13(options.cwd);
3551
5363
  const log = options.log ?? ((line) => process.stdout.write(`${line}
3552
5364
  `));
3553
5365
  const project2 = await loadWidgetProject(cwd);
@@ -3598,14 +5410,14 @@ data: ${version}
3598
5410
  }
3599
5411
  const readTheme = async () => {
3600
5412
  try {
3601
- return await readFile9(join13(cwd, "src", "theme.css"), "utf8");
5413
+ return await readFile11(join15(cwd, "src", "theme.css"), "utf8");
3602
5414
  } catch {
3603
5415
  return null;
3604
5416
  }
3605
5417
  };
3606
5418
  const readProps = async () => {
3607
5419
  try {
3608
- return await readFile9(join13(cwd, "src", "mock-props.json"), "utf8");
5420
+ return await readFile11(join15(cwd, "src", "mock-props.json"), "utf8");
3609
5421
  } catch {
3610
5422
  return null;
3611
5423
  }
@@ -3657,7 +5469,7 @@ data: ${version}
3657
5469
  }
3658
5470
  res.writeHead(404).end("not found");
3659
5471
  };
3660
- const server = createServer2((req, res) => {
5472
+ const server = createServer3((req, res) => {
3661
5473
  void handle(req, res);
3662
5474
  });
3663
5475
  await new Promise((resolveListen, rejectListen) => {
@@ -3694,18 +5506,18 @@ var publish_exports = {};
3694
5506
  __export(publish_exports, {
3695
5507
  publishWidget: () => publishWidget
3696
5508
  });
3697
- import { readFile as readFile10 } from "node:fs/promises";
3698
- import { basename as basename4, join as join14, resolve as resolve11 } from "node:path";
5509
+ import { readFile as readFile12 } from "node:fs/promises";
5510
+ import { basename as basename4, join as join16, resolve as resolve14 } from "node:path";
3699
5511
  async function publishWidget(paths, options) {
3700
5512
  const log = options.log ?? ((line) => process.stdout.write(`${line}
3701
5513
  `));
3702
5514
  const client = await createClient(paths);
3703
- const root = resolve11(options.cwd);
5515
+ const root = resolve14(options.cwd);
3704
5516
  const project2 = await loadWidgetProject(root);
3705
5517
  const framework = options.framework ?? project2.framework;
3706
5518
  let version = "0.1.0";
3707
5519
  try {
3708
- const pkg = JSON.parse(await readFile10(join14(root, "package.json"), "utf8"));
5520
+ const pkg = JSON.parse(await readFile12(join16(root, "package.json"), "utf8"));
3709
5521
  if (typeof pkg["version"] === "string" && pkg["version"].length > 0) version = pkg["version"];
3710
5522
  } catch {
3711
5523
  version = "0.1.0";
@@ -3742,18 +5554,10 @@ var init_publish = __esm({
3742
5554
 
3743
5555
  // packages/cli/src/cli.ts
3744
5556
  init_auth();
5557
+ init_config();
3745
5558
  import { Command } from "commander";
3746
5559
  import { createRequire } from "node:module";
3747
5560
 
3748
- // packages/cli/src/config.ts
3749
- function resolvePaths(env = process.env) {
3750
- const home = env["ADEP_HOME"] ?? `${env["HOME"] ?? ""}/.adep`;
3751
- return { home, credentialsFile: `${home}/credentials` };
3752
- }
3753
- function resolveServer(env = process.env) {
3754
- return (env["ADEP_SERVER"] ?? "https://adep.jajabjbj.top").replace(/\/+$/, "");
3755
- }
3756
-
3757
5561
  // packages/cli/src/init.ts
3758
5562
  import { mkdir as mkdir2, stat as stat2, writeFile } from "node:fs/promises";
3759
5563
  import { dirname as dirname2, join, resolve } from "node:path";
@@ -3764,13 +5568,11 @@ var InitError = class extends Error {
3764
5568
  this.name = "InitError";
3765
5569
  }
3766
5570
  };
3767
- var ADEP_CONFIG = (name, template) => `import { defineConfig } from 'adep/config'
3768
-
3769
- // adep \u9879\u76EE\u914D\u7F6E\uFF1ACLI\uFF08dev / deploy\uFF09\u4E0E\u5E73\u53F0\u6309\u6B64\u8BC6\u522B\u9879\u76EE\u3002
3770
- export default defineConfig({
5571
+ var ADEP_CONFIG = (name, template) => `// adep \u9879\u76EE\u914D\u7F6E\uFF1ACLI\uFF08dev / deploy\uFF09\u6309 default export \u8BFB\u53D6\uFF08name / functionsDir\uFF09\u3002
5572
+ export default {
3771
5573
  name: '${name}',
3772
5574
  template: '${template}',
3773
- })
5575
+ }
3774
5576
  `;
3775
5577
  var README = (name, template) => `# ${name}
3776
5578
 
@@ -3779,13 +5581,13 @@ AgentDeploy \u9879\u76EE\uFF08\u6A21\u677F\uFF1A${template}\uFF09\u3002
3779
5581
  - \`adep dev\`\uFF1A\u672C\u5730\u8C03\u8BD5\uFF08CLI-002 \u4EA4\u4ED8\uFF09
3780
5582
  - \`adep deploy\`\uFF1A\u53D1\u5E03\uFF08CLI-003 \u4EA4\u4ED8\uFF09
3781
5583
  `;
3782
- var HELLO_FUNCTION = `import { defineFunction } from 'adep/function'
3783
-
3784
- // \u793A\u4F8B\u51FD\u6570\uFF1Aadep deploy \u540E\u7ECF https://<project-slug>.<platform-domain>/hello \u89E6\u53D1\u3002
3785
- export default defineFunction(async (ctx) => {
5584
+ var HELLO_FUNCTION = `// \u793A\u4F8B\u51FD\u6570\uFF1Aadep deploy \u540E\u7ECF https://<project-slug>.<platform-domain>/hello \u89E6\u53D1\u3002
5585
+ // \u7528\u6237\u51FD\u6570\u5373 functions/ \u4E0B\u7684\u72EC\u7ACB\u6587\u4EF6\uFF0C\u9ED8\u8BA4\u5BFC\u51FA (ctx) => Response \u5F62\u72B6\u7684\u5904\u7406\u5668
5586
+ //\uFF08ctx \u5951\u7EA6\u89C1\u5E73\u53F0\u7684 FunctionContext\uFF1Amethod / path / query / headers / body / cloud.*\uFF09\u3002
5587
+ export default async (ctx) => {
3786
5588
  const name = (ctx.query['name'] as string | undefined) ?? 'world'
3787
5589
  return { message: \`hello \${name}\` }
3788
- })
5590
+ }
3789
5591
  `;
3790
5592
  var FUNCTION_INDEX = `// \u51FD\u6570\u6A21\u5757\u5165\u53E3\uFF1A\u9879\u76EE\u91CC\u7684\u6BCF\u4E2A\u51FD\u6570\u662F functions/ \u4E0B\u7684\u72EC\u7ACB\u6587\u4EF6\uFF0C
3791
5593
  // \u9ED8\u8BA4\u5BFC\u51FA (ctx) => Response \u5F62\u72B6\u7684\u5904\u7406\u5668\uFF08\u5951\u7EA6\u89C1 @adep/types \u7684 FunctionContext\uFF09\u3002
@@ -3864,6 +5666,9 @@ init_build();
3864
5666
  init_init();
3865
5667
  var requireJson = createRequire(import.meta.url);
3866
5668
  var APP_VERSION = requireJson("../package.json").version;
5669
+ function needsRelogin(error) {
5670
+ return error.code === "NOT_LOGGED_IN" || error.code === "AUTH_UNAUTHORIZED";
5671
+ }
3867
5672
  function emitError(output, command, json, error) {
3868
5673
  if (error instanceof CliError || error instanceof InitError || error instanceof WidgetError || error instanceof WidgetInitError) {
3869
5674
  if (json) {
@@ -3875,8 +5680,9 @@ function emitError(output, command, json, error) {
3875
5680
  })
3876
5681
  );
3877
5682
  } else {
3878
- output(`\u9519\u8BEF\uFF1A${error.message}`);
3879
- if (error instanceof CliError && error.code === "NOT_LOGGED_IN") {
5683
+ const withCode = error.message.includes(error.code) || error.code.length === 0 ? error.message : `${error.message}\uFF08${error.code}\uFF09`;
5684
+ output(`\u9519\u8BEF\uFF1A${withCode}`);
5685
+ if (error instanceof CliError && needsRelogin(error)) {
3880
5686
  output("\u63D0\u793A\uFF1A\u5148\u6267\u884C adep login");
3881
5687
  }
3882
5688
  }
@@ -3917,6 +5723,45 @@ function parseBool(raw) {
3917
5723
  if (raw === "false") return false;
3918
5724
  throw new CliError("INVALID_BOOLEAN", `\u5E03\u5C14\u53C2\u6570\u987B\u4E3A true \u6216 false\uFF0C\u6536\u5230 "${raw}"`);
3919
5725
  }
5726
+ function formatSeconds(seconds) {
5727
+ return `${Math.max(0.1, Math.round(seconds * 10) / 10)}s`;
5728
+ }
5729
+ async function runDeploy(paths, output, json, cwd, slug, dir) {
5730
+ const { deploy: deploy2 } = await Promise.resolve().then(() => (init_deploy(), deploy_exports));
5731
+ const startedAt = Date.now();
5732
+ const result = await deploy2(paths, {
5733
+ cwd,
5734
+ ...slug === void 0 ? {} : { slug },
5735
+ ...dir === void 0 ? {} : { functionsDir: dir },
5736
+ // --json 下逐函数进度会破坏「stdout 恰好一个 JSON 对象」的信封约定(PRD §2.5.3)。
5737
+ silent: json,
5738
+ // 人读模式的进度也走注入的 output:deploy 内部缺省会直写 process.stdout,
5739
+ // 那会让带 sink 的调用方漏收这部分行。
5740
+ log: (line) => output(line)
5741
+ });
5742
+ const elapsedSeconds = (Date.now() - startedAt) / 1e3;
5743
+ const deployedCount = result.functions.filter((fn) => fn.action !== "none").length;
5744
+ if (json) {
5745
+ output(
5746
+ JSON.stringify({
5747
+ ok: true,
5748
+ command: "deploy",
5749
+ data: { ...result, elapsedSeconds, deployedCount }
5750
+ })
5751
+ );
5752
+ return;
5753
+ }
5754
+ for (const fn of result.functions) {
5755
+ output(`${fn.name} v${fn.version} ${fn.url}`);
5756
+ }
5757
+ if (result.noChanges) {
5758
+ output(
5759
+ `\u2713 no changes \xB7 ${result.functions.length} functions up to date in ${formatSeconds(elapsedSeconds)}`
5760
+ );
5761
+ return;
5762
+ }
5763
+ output(`\u2713 ${deployedCount} functions deployed in ${formatSeconds(elapsedSeconds)}`);
5764
+ }
3920
5765
  function buildProgram(options = {}) {
3921
5766
  const output = options.output ?? ((line) => process.stdout.write(`${line}
3922
5767
  `));
@@ -4022,25 +5867,212 @@ function buildProgram(options = {}) {
4022
5867
  emitError(output, "dev", jsonMode(), error);
4023
5868
  }
4024
5869
  });
5870
+ program2.command("serve").description(
5871
+ "\u5F00\u53D1\u6001\u670D\u52A1\u5668\uFF1A\u51FD\u6570 /api/{fn} + /healthz + \u9759\u6001\u6258\u7BA1 + \u7EC4\u4EF6\u9884\u89C8\uFF08\u9ED8\u8BA4\u4EC5\u56DE\u73AF\uFF0C\u4E0D\u662F\u751F\u4EA7\u670D\u52A1\u5668\uFF09"
5872
+ ).option("-p, --port <port>", "\u76D1\u542C\u7AEF\u53E3\uFF08\u7F3A\u7701\u53D6 PORT \u73AF\u5883\u53D8\u91CF\uFF0C\u518D\u7F3A\u7701 8787\uFF09").option(
5873
+ "-H, --host <host>",
5874
+ "\u76D1\u542C\u5730\u5740\uFF08\u7F3A\u7701\u53D6 HOST \u73AF\u5883\u53D8\u91CF\uFF0C\u518D\u7F3A\u7701 127.0.0.1\uFF1B\u7ED1\u5B9A\u975E\u56DE\u73AF\u65F6\u7ED9\u51FA\u5BF9\u5916\u66B4\u9732\u8B66\u544A\uFF09"
5875
+ ).option(
5876
+ "--static <dir>",
5877
+ "\u9759\u6001\u6258\u7BA1\u76EE\u5F55\uFF08\u7F3A\u7701\u53D6 ADEP_SERVE_STATIC_DIR\uFF0C\u518D\u7F3A\u7701 public/\uFF1B\u81EA\u6258\u7BA1\u90E8\u7F72\u5305\u6307\u5411\u5305\u5185 web/\uFF09"
5878
+ ).action(async (flags) => {
5879
+ try {
5880
+ const { startServeServer: startServeServer2 } = await Promise.resolve().then(() => (init_server(), server_exports));
5881
+ await startServeServer2({
5882
+ cwd,
5883
+ ...flags.port === void 0 ? {} : { port: Number(flags.port) },
5884
+ ...flags.host === void 0 ? {} : { host: flags.host },
5885
+ ...flags.static === void 0 ? {} : { staticDir: flags.static }
5886
+ });
5887
+ await new Promise(() => void 0);
5888
+ } catch (error) {
5889
+ emitError(output, "serve", jsonMode(), error);
5890
+ }
5891
+ });
4025
5892
  program2.command("deploy").description("\u589E\u91CF\u90E8\u7F72\uFF1A\u5BF9\u6BD4\u8FDC\u7AEF\u54C8\u5E0C \u2192 \u4EC5\u4E0A\u4F20\u53D8\u66F4 \u2192 \u53D1\u5E03 \u2192 \u8F93\u51FA\u8BBF\u95EE\u57DF\u540D").option("-p, --project <slug>", "\u76EE\u6807\u5E73\u53F0\u9879\u76EE slug\uFF08\u7F3A\u7701\u53D6 adep.config.ts \u7684 name\uFF09").action(async (flags) => {
4026
5893
  try {
4027
- const { deploy: deploy2 } = await Promise.resolve().then(() => (init_deploy(), deploy_exports));
4028
- const result = await deploy2(paths, {
5894
+ await runDeploy(paths, output, jsonMode(), cwd, flags.project);
5895
+ } catch (error) {
5896
+ emitError(output, "deploy", jsonMode(), error);
5897
+ }
5898
+ });
5899
+ const projects = program2.command("projects").description("\u9879\u76EE\uFF1A\u521B\u5EFA / \u5217\u51FA / \u67E5\u770B\uFF08\u5B50\u57DF\u5730\u5740\u7531\u5E73\u53F0\u56DE\u663E\uFF0C\u4E0D\u5728 CLI \u4FA7\u62FC\uFF09");
5900
+ projects.command("create").description("\u521B\u5EFA\u9879\u76EE\u5E76\u8F93\u51FA\u5B50\u57DF\u5730\u5740").argument("<slug>", "\u9879\u76EE slug\uFF08\u5168\u5C40\u552F\u4E00\uFF0C\u5373\u5B50\u57DF\u540D\uFF09").option("-n, --name <name>", "\u9879\u76EE\u5C55\u793A\u540D\uFF08\u7F3A\u7701\u53D6 slug\uFF09").option("--space <spaceId>", "\u5F52\u5C5E\u7A7A\u95F4\uFF08\u7F3A\u7701\u4E2A\u4EBA\u7A7A\u95F4\uFF09").action(async (slug, flags) => {
5901
+ try {
5902
+ const { projectsCreate: projectsCreate2 } = await Promise.resolve().then(() => (init_projects(), projects_exports));
5903
+ const created = await projectsCreate2(paths, {
5904
+ slug,
5905
+ ...flags.name === void 0 ? {} : { name: flags.name },
5906
+ ...flags.space === void 0 ? {} : { spaceId: flags.space }
5907
+ });
5908
+ if (jsonMode()) {
5909
+ output(JSON.stringify({ ok: true, command: "projects create", data: created }));
5910
+ } else {
5911
+ output(`\u2713 Project created \xB7 ${created.url}`);
5912
+ }
5913
+ } catch (error) {
5914
+ emitError(output, "projects create", jsonMode(), error);
5915
+ }
5916
+ });
5917
+ projects.command("list").description("\u5217\u51FA\u5F53\u524D\u7528\u6237\u53EF\u8BBF\u95EE\u7684\u9879\u76EE").action(async () => {
5918
+ try {
5919
+ const { projectsList: projectsList2 } = await Promise.resolve().then(() => (init_projects(), projects_exports));
5920
+ const list = await projectsList2(paths);
5921
+ if (jsonMode()) {
5922
+ output(JSON.stringify({ ok: true, command: "projects list", data: { projects: list } }));
5923
+ } else {
5924
+ if (list.length === 0) output("\uFF08\u8FD8\u6CA1\u6709\u9879\u76EE\uFF1Aadep projects create <slug>\uFF09");
5925
+ for (const project2 of list) output(`${project2.slug} ${project2.name} ${project2.url}`);
5926
+ }
5927
+ } catch (error) {
5928
+ emitError(output, "projects list", jsonMode(), error);
5929
+ }
5930
+ });
5931
+ projects.command("info").description("\u67E5\u770B\u5355\u4E2A\u9879\u76EE\u7684 id / slug / \u5B50\u57DF\u5730\u5740").argument("<slug>", "\u9879\u76EE slug").action(async (slug) => {
5932
+ try {
5933
+ const { projectsInfo: projectsInfo2 } = await Promise.resolve().then(() => (init_projects(), projects_exports));
5934
+ const project2 = await projectsInfo2(paths, { slug });
5935
+ if (jsonMode()) {
5936
+ output(JSON.stringify({ ok: true, command: "projects info", data: project2 }));
5937
+ } else {
5938
+ output(`${project2.id} ${project2.slug} ${project2.name} ${project2.url}`);
5939
+ }
5940
+ } catch (error) {
5941
+ emitError(output, "projects info", jsonMode(), error);
5942
+ }
5943
+ });
5944
+ const functions = program2.command("functions").description("\u4E91\u51FD\u6570\uFF1A\u90E8\u7F72\uFF08\u53EF\u6307\u5B9A\u76EE\u5F55\uFF09/ \u5217\u51FA / \u67E5\u65E5\u5FD7");
5945
+ functions.command("deploy").description(
5946
+ "\u90E8\u7F72\u51FD\u6570\u76EE\u5F55\uFF08`adep deploy` \u7684\u547D\u4EE4\u65CF\u5165\u53E3\uFF1Bdir \u8986\u76D6 adep.config.ts \u7684 functionsDir\uFF09"
5947
+ ).argument("[dir]", "\u51FD\u6570\u76EE\u5F55\uFF08\u76F8\u5BF9\u9879\u76EE\u6839\u6216\u7EDD\u5BF9\u8DEF\u5F84\uFF0C\u7F3A\u7701\u53D6\u914D\u7F6E\u91CC\u7684 functionsDir\uFF09").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) => {
5948
+ try {
5949
+ await runDeploy(paths, output, jsonMode(), cwd, flags.project, dir);
5950
+ } catch (error) {
5951
+ emitError(output, "functions deploy", jsonMode(), error);
5952
+ }
5953
+ });
5954
+ functions.command("list").description("\u5217\u51FA\u9879\u76EE\u4E0B\u7684\u4E91\u51FD\u6570\uFF08\u542B\u516C\u7F51\u8BBF\u95EE\u524D\u7F00\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) => {
5955
+ try {
5956
+ const { functionsList: functionsList2 } = await Promise.resolve().then(() => (init_functions(), functions_exports));
5957
+ const result = await functionsList2(paths, {
4029
5958
  cwd,
4030
5959
  ...flags.project === void 0 ? {} : { slug: flags.project }
4031
5960
  });
4032
5961
  if (jsonMode()) {
4033
- output(JSON.stringify({ ok: true, command: "deploy", data: result }));
5962
+ output(JSON.stringify({ ok: true, command: "functions list", data: result }));
4034
5963
  } else {
4035
- if (result.noChanges) {
4036
- output("no changes\uFF1A\u5168\u90E8\u51FD\u6570\u4E0E\u5DF2\u53D1\u5E03\u7248\u672C\u4E00\u81F4\uFF0C\u672A\u4EA7\u751F\u65B0\u7248\u672C");
4037
- }
5964
+ if (result.functions.length === 0) output("\uFF08\u8BE5\u9879\u76EE\u4E0B\u8FD8\u6CA1\u6709\u51FD\u6570\uFF09");
4038
5965
  for (const fn of result.functions) {
4039
- output(`${fn.name} v${fn.version} ${fn.url}`);
5966
+ output(`${fn.name} ${result.baseUrl}/${fn.name}`);
4040
5967
  }
4041
5968
  }
4042
5969
  } catch (error) {
4043
- emitError(output, "deploy", jsonMode(), error);
5970
+ emitError(output, "functions list", jsonMode(), error);
5971
+ }
5972
+ });
5973
+ functions.command("logs").description("\u67E5\u8BE2\u51FD\u6570\u6700\u8FD1\u6267\u884C\u65E5\u5FD7\uFF08\u7F13\u51B2\u5728\u5E73\u53F0\u8FDB\u7A0B\u5185\uFF0C\u672A\u6267\u884C\u8FC7\u7684\u51FD\u6570\u4E3A\u7A7A\uFF09").argument("<name>", "\u51FD\u6570\u540D").option("--tail <count>", "\u53D6\u6700\u8FD1\u591A\u5C11\u6761\uFF08\u7F3A\u7701 100\uFF0C\u670D\u52A1\u7AEF\u6709\u4E0A\u9650\uFF09").option("-p, --project <slug>", "\u76EE\u6807\u5E73\u53F0\u9879\u76EE slug\uFF08\u7F3A\u7701\u53D6 adep.config.ts \u7684 name\uFF09").action(async (name, flags) => {
5974
+ try {
5975
+ const { functionsLogs: functionsLogs2 } = await Promise.resolve().then(() => (init_functions(), functions_exports));
5976
+ const tail = flags.tail === void 0 ? void 0 : Number(flags.tail);
5977
+ if (tail !== void 0 && (!Number.isFinite(tail) || tail <= 0)) {
5978
+ throw new CliError("INVALID_TAIL", `--tail \u987B\u4E3A\u6B63\u6574\u6570\uFF0C\u6536\u5230 "${flags.tail}"`);
5979
+ }
5980
+ const result = await functionsLogs2(paths, {
5981
+ cwd,
5982
+ name,
5983
+ ...tail === void 0 ? {} : { tail },
5984
+ ...flags.project === void 0 ? {} : { slug: flags.project }
5985
+ });
5986
+ if (jsonMode()) {
5987
+ output(JSON.stringify({ ok: true, command: "functions logs", data: result }));
5988
+ } else {
5989
+ if (result.logs.length === 0) {
5990
+ output(`\uFF08\u51FD\u6570 ${name} \u6682\u65E0\u6267\u884C\u65E5\u5FD7\uFF1A\u5148\u7528 adep deploy \u53D1\u5E03\u5E76\u7ECF\u7F51\u5173\u6216\u8C03\u8BD5\u9762\u677F\u6267\u884C\u4E00\u6B21\uFF09`);
5991
+ }
5992
+ for (const log of result.logs) output(`${log.at} [${log.level}] ${log.message}`);
5993
+ }
5994
+ } catch (error) {
5995
+ emitError(output, "functions logs", jsonMode(), error);
5996
+ }
5997
+ });
5998
+ const mcp = program2.command("mcp").description("MCP Tool\uFF1A\u628A\u4E91\u51FD\u6570\u53D1\u5E03\u4E3A\u5DE5\u5177 / \u53D6\u6D88\u53D1\u5E03 / \u5217\u51FA");
5999
+ mcp.command("publish").description("\u53D1\u5E03\u4E91\u51FD\u6570\u4E3A\u9879\u76EE MCP Tool\uFF08Tool \u540D\u7F3A\u7701\u53D6\u51FD\u6570\u540D\uFF0C--name \u53EF\u8986\u76D6\uFF09").requiredOption("--function <fn>", "\u8981\u53D1\u5E03\u7684\u51FD\u6570\u540D").option("--name <tool>", "\u6CE8\u518C\u7684 Tool \u540D\uFF08\u7F3A\u7701\u53D6\u51FD\u6570\u540D\uFF09").option(
6000
+ "--description <text>",
6001
+ "\u8986\u76D6\u9762\u5411 Agent \u7684\u5DE5\u5177\u63CF\u8FF0\uFF08\u7F3A\u7701\u7528\u6E90\u7801 @description / \u63A8\u5BFC\u63CF\u8FF0\uFF09"
6002
+ ).option("-p, --project <slug>", "\u76EE\u6807\u5E73\u53F0\u9879\u76EE slug\uFF08\u7F3A\u7701\u53D6 adep.config.ts \u7684 name\uFF09").action(
6003
+ async (flags) => {
6004
+ try {
6005
+ const { mcpPublish: mcpPublish2 } = await Promise.resolve().then(() => (init_mcp(), mcp_exports));
6006
+ const result = await mcpPublish2(paths, {
6007
+ cwd,
6008
+ fn: flags.function,
6009
+ ...flags.name === void 0 ? {} : { toolName: flags.name },
6010
+ ...flags.description === void 0 ? {} : { description: flags.description },
6011
+ ...flags.project === void 0 ? {} : { slug: flags.project }
6012
+ });
6013
+ if (jsonMode()) {
6014
+ output(JSON.stringify({ ok: true, command: "mcp publish", data: result }));
6015
+ } else {
6016
+ output(`\u2713 MCP tool published \xB7 ${result.tool.name}`);
6017
+ }
6018
+ } catch (error) {
6019
+ emitError(output, "mcp publish", jsonMode(), error);
6020
+ }
6021
+ }
6022
+ );
6023
+ mcp.command("unpublish").description("\u53D6\u6D88\u53D1\u5E03\u4E91\u51FD\u6570\u5BF9\u5E94\u7684 MCP Tool\uFF08\u7ACB\u5373\u4ECE\u9879\u76EE tools/list \u79FB\u9664\uFF09").requiredOption("--function <fn>", "\u51FD\u6570\u540D").option("--name <tool>", "\u5DF2\u6CE8\u518C\u7684 Tool \u540D\uFF08\u7F3A\u7701\u53D6\u51FD\u6570\u540D\uFF1B\u53D1\u5E03\u65F6\u7528\u4E86\u522B\u540D\u624D\u9700\u7ED9\u51FA\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) => {
6024
+ try {
6025
+ const { mcpUnpublish: mcpUnpublish2 } = await Promise.resolve().then(() => (init_mcp(), mcp_exports));
6026
+ const result = await mcpUnpublish2(paths, {
6027
+ cwd,
6028
+ fn: flags.function,
6029
+ ...flags.name === void 0 ? {} : { toolName: flags.name },
6030
+ ...flags.project === void 0 ? {} : { slug: flags.project }
6031
+ });
6032
+ if (jsonMode()) {
6033
+ output(JSON.stringify({ ok: true, command: "mcp unpublish", data: result }));
6034
+ } else if (result.removed) {
6035
+ output(`\u2713 MCP tool unpublished \xB7 ${result.toolName}`);
6036
+ } else {
6037
+ output(`\uFF08\u9879\u76EE\u672A\u53D1\u5E03\u540D\u4E3A ${result.toolName} \u7684 MCP tool\uFF0C\u65E0\u9700\u53D6\u6D88\uFF09`);
6038
+ }
6039
+ } catch (error) {
6040
+ emitError(output, "mcp unpublish", jsonMode(), error);
6041
+ }
6042
+ });
6043
+ mcp.command("list").description("\u5217\u51FA\u9879\u76EE\u5DF2\u53D1\u5E03\u7684 MCP Tool \u4E0E\u7AEF\u70B9\u5730\u5740\uFF08\u8BFB\u9879\u76EE /mcp \u7684 tools/list\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) => {
6044
+ try {
6045
+ const { mcpList: mcpList2 } = await Promise.resolve().then(() => (init_mcp(), mcp_exports));
6046
+ const result = await mcpList2(paths, {
6047
+ cwd,
6048
+ ...flags.project === void 0 ? {} : { slug: flags.project }
6049
+ });
6050
+ if (jsonMode()) {
6051
+ output(JSON.stringify({ ok: true, command: "mcp list", data: result }));
6052
+ } else {
6053
+ output(`\u7AEF\u70B9\uFF1A${result.endpoint}`);
6054
+ if (result.tools.length === 0) {
6055
+ output("\uFF08\u8FD8\u6CA1\u6709\u5DF2\u53D1\u5E03\u7684 MCP tool\uFF1Aadep mcp publish --function <fn>\uFF09");
6056
+ }
6057
+ for (const tool of result.tools) {
6058
+ output(`${tool.name} ${tool.description ?? ""}`);
6059
+ }
6060
+ }
6061
+ } catch (error) {
6062
+ emitError(output, "mcp list", jsonMode(), error);
6063
+ }
6064
+ });
6065
+ program2.command("doctor").description("\u73AF\u5883\u81EA\u68C0\uFF1A\u51ED\u636E\u72B6\u6001 / \u5E73\u53F0\u53EF\u8FBE\u6027 / \u79BB\u7EBF\u53EF\u7528\u8303\u56F4\uFF08\u8865\u9F50\u65AD\u7F51\u6587\u6848\u5F15\u7528\u7684\u60AC\u7A7A\u547D\u4EE4\uFF09").action(async () => {
6066
+ try {
6067
+ const { runDoctor: runDoctor2, formatDoctorReport: formatDoctorReport2 } = await Promise.resolve().then(() => (init_doctor(), doctor_exports));
6068
+ const report = await runDoctor2(paths);
6069
+ if (jsonMode()) {
6070
+ output(JSON.stringify({ ok: true, command: "doctor", data: report }));
6071
+ } else {
6072
+ for (const line of formatDoctorReport2(report)) output(line);
6073
+ }
6074
+ } catch (error) {
6075
+ emitError(output, "doctor", jsonMode(), error);
4044
6076
  }
4045
6077
  });
4046
6078
  const db = program2.command("db").description("\u9879\u76EE\u6570\u636E\u5E93\u7EF4\u62A4\uFF1A\u542F\u52A8 / \u72B6\u6001 / \u505C\u6B62 / SQL / \u5FEB\u7167 / \u56DE\u6EDA").option("-p, --project <slug>", "\u76EE\u6807\u5E73\u53F0\u9879\u76EE slug\uFF08\u7F3A\u7701\u53D6 adep.config.ts \u7684 name\uFF09");
@@ -4361,6 +6393,45 @@ function buildProgram(options = {}) {
4361
6393
  emitError(output, "hosting config", jsonMode(), error);
4362
6394
  }
4363
6395
  });
6396
+ program2.command("export").description("\u5BFC\u51FA\u81EA\u6258\u7BA1\u90E8\u7F72\u5305\uFF1A\u89E6\u53D1\u957F\u4EFB\u52A1 \u2192 \u8F6E\u8BE2\u8FDB\u5EA6 \u2192 \u4E0B\u8F7D zip \u2192 manifest \u9010\u9879\u81EA\u68C0").option("-p, --project <slug>", "\u76EE\u6807\u5E73\u53F0\u9879\u76EE slug\uFF08\u7F3A\u7701\u53D6 adep.config.ts \u7684 name\uFF09").option("--with-data", "\u5305\u542B\u6570\u636E\u5E93\u884C\u6570\u636E\uFF08\u7F3A\u7701\u4EC5 schema\uFF09").option("--with-source", "\u5305\u542B\u51FD\u6570\u6E90\u7801\uFF08\u7F3A\u7701\u5E73\u53F0\u5DF2\u542B\uFF0C\u663E\u5F0F\u7F6E\u6B64\u4E0D\u6539\u53D8\u9ED8\u8BA4\uFF09").option("--out <dir>", "\u8F93\u51FA\u76EE\u5F55\uFF08\u7F3A\u7701 ./exports\uFF09").action(
6397
+ async (flags) => {
6398
+ try {
6399
+ const { createExportApiClient: createExportApiClient2 } = await Promise.resolve().then(() => (init_client2(), client_exports2));
6400
+ const { createExportFileSystem: createExportFileSystem2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
6401
+ const { ExportCommand: ExportCommand2 } = await Promise.resolve().then(() => (init_command(), command_exports));
6402
+ const { resolveSlug: resolveSlug2 } = await Promise.resolve().then(() => (init_client(), client_exports));
6403
+ const project2 = await resolveSlug2(cwd, flags.project);
6404
+ const apiClient = await createExportApiClient2(paths);
6405
+ const command = new ExportCommand2(apiClient, createExportFileSystem2());
6406
+ const result = await command.execute({
6407
+ project: project2,
6408
+ ...flags.withData === true ? { withData: true } : {},
6409
+ ...flags.withSource === true ? { withSource: true } : {},
6410
+ ...flags.out === void 0 ? {} : { out: flags.out },
6411
+ json: jsonMode()
6412
+ });
6413
+ if (jsonMode()) {
6414
+ if (result.success) {
6415
+ output(JSON.stringify({ ok: true, command: "export", data: result }));
6416
+ } else {
6417
+ output(
6418
+ JSON.stringify({
6419
+ ok: false,
6420
+ command: "export",
6421
+ error: { code: "EXPORT_FAILED", message: result.error ?? "\u5BFC\u51FA\u5931\u8D25" }
6422
+ })
6423
+ );
6424
+ process.exitCode = 1;
6425
+ }
6426
+ } else if (!result.success) {
6427
+ output(`\u9519\u8BEF\uFF1A${result.error ?? "\u5BFC\u51FA\u5931\u8D25"}`);
6428
+ process.exitCode = 1;
6429
+ }
6430
+ } catch (error) {
6431
+ emitError(output, "export", jsonMode(), error);
6432
+ }
6433
+ }
6434
+ );
4364
6435
  const widget = program2.command("widget").description("\u5FAE\u524D\u7AEF\u7EC4\u4EF6\uFF08widget\uFF09\uFF1A\u811A\u624B\u67B6 / \u672C\u5730\u6C99\u7BB1 / \u53D1\u5E03");
4365
6436
  widget.command("init").description("\u521D\u59CB\u5316 widget \u5DE5\u7A0B\uFF08\u6A21\u677F\uFF1Avue3-ts / react-ts\uFF09").argument("<name>", "widget \u540D\u79F0\uFF08\u5C0F\u5199\u5B57\u6BCD\u5F00\u5934\uFF0C\u4EC5\u5C0F\u5199\u5B57\u6BCD/\u6570\u5B57/\u8FDE\u5B57\u7B26\uFF09").option("-t, --template <template>", "\u6A21\u677F\uFF1Avue3-ts | react-ts", "vue3-ts").action(async (name, flags) => {
4366
6437
  try {