@tbox.cn/app-cli 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +289 -67
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -383,8 +383,8 @@ async function createApp(opts) {
383
383
  }
384
384
 
385
385
  // src/commands/add.ts
386
- import { existsSync as existsSync19, readFileSync as readFileSync8, readdirSync as readdirSync2 } from "fs";
387
- import path23 from "path";
386
+ import { existsSync as existsSync20, readFileSync as readFileSync9, readdirSync as readdirSync2 } from "fs";
387
+ import path24 from "path";
388
388
 
389
389
  // src/expand.ts
390
390
  import { mkdir as mkdir2, rm, writeFile as writeFile3 } from "fs/promises";
@@ -405,15 +405,32 @@ function rewritePlatformRefs(deps) {
405
405
  if (isWorkspacePkg(name)) deps[name] = "catalog:";
406
406
  }
407
407
  }
408
+ function deriveModuleId(pkgName) {
409
+ return pkgName.replace(/^@tbox\.cn\/app-/, "").replace(/^@[^/]+\//, "");
410
+ }
411
+ function escapeRegExp(s) {
412
+ return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
413
+ }
414
+ function rewriteLoadModuleSkillsCall(content, fromName, toName) {
415
+ return content.replaceAll(
416
+ new RegExp(`loadModuleSkills\\(\\s*['"]${escapeRegExp(fromName)}['"]`, "g"),
417
+ `loadModuleSkills('${toName}'`
418
+ );
419
+ }
408
420
  function rewriteExportsToSrc(pkg) {
409
421
  const exports = pkg.exports;
410
422
  if (!exports || typeof exports !== "object") return;
411
423
  const next = {};
412
424
  for (const [sub, val] of Object.entries(exports)) {
425
+ if (sub === "./package.json") {
426
+ next[sub] = val;
427
+ continue;
428
+ }
413
429
  if (typeof val !== "object" || val === null) continue;
414
430
  const base = sub === "." ? "./src/index.ts" : `./src/${sub.replace(/^\.\//, "")}/index.ts`;
415
431
  next[sub] = { types: base, import: base };
416
432
  }
433
+ if (next["./package.json"] === void 0) next["./package.json"] = "./package.json";
417
434
  pkg.exports = next;
418
435
  }
419
436
  async function expandCodegen(appDir, sourceDir, entry) {
@@ -421,16 +438,21 @@ async function expandCodegen(appDir, sourceDir, entry) {
421
438
  const targetDir = path5.join(appDir, "packages", entry.id);
422
439
  await rm(targetDir, { recursive: true, force: true });
423
440
  await mkdir2(targetDir, { recursive: true });
441
+ const rawPkg = JSON.parse(await src.readFile("package.json"));
442
+ const fromName = rawPkg.name ?? "";
443
+ const toName = `@app/${entry.id}`;
424
444
  for (const rel of await src.listFiles()) {
425
445
  if (rel === "package.json") continue;
426
- const content = await src.readFile(rel);
446
+ let content = await src.readFile(rel);
447
+ if (fromName && fromName !== toName && rel.endsWith(".ts")) {
448
+ content = rewriteLoadModuleSkillsCall(content, fromName, toName);
449
+ }
427
450
  const out = path5.join(targetDir, rel);
428
451
  await mkdir2(path5.dirname(out), { recursive: true });
429
452
  await writeFile3(out, content);
430
453
  }
431
- const rawPkg = await src.readFile("package.json");
432
- const pkg = JSON.parse(rawPkg);
433
- pkg.name = `@app/${entry.id}`;
454
+ const pkg = rawPkg;
455
+ pkg.name = toName;
434
456
  pkg.private = true;
435
457
  if (pkg.dependencies && typeof pkg.dependencies === "object") {
436
458
  rewritePlatformRefs(pkg.dependencies);
@@ -522,7 +544,9 @@ async function createLocalSkeleton(appDir, shortName) {
522
544
  exports: {
523
545
  ".": { types: "./src/index.ts", import: "./src/index.ts" },
524
546
  "./server": { types: "./src/server/index.ts", import: "./src/server/index.ts" },
525
- "./client": { types: "./src/client/index.ts", import: "./src/client/index.ts" }
547
+ "./client": { types: "./src/client/index.ts", import: "./src/client/index.ts" },
548
+ // 009 模块文件化前置:loadModuleSkills 包名解析需 exports 放行元数据子路径
549
+ "./package.json": "./package.json"
526
550
  },
527
551
  // 本地模块自带工具链:typecheck/test 可在生成应用内直接跑(pnpm verify 全 @app/* 范围)
528
552
  scripts: { typecheck: "tsc --noEmit", test: "vitest run --passWithNoTests" },
@@ -932,6 +956,19 @@ function probeModuleObjectExport(dir, sub, symbol) {
932
956
  return false;
933
957
  }
934
958
  }
959
+ function readServerSource(dir) {
960
+ const file = path7.join(dir, "src", "server", "index.ts");
961
+ if (!existsSync5(file)) return "";
962
+ try {
963
+ return readFileSync4(file, "utf8");
964
+ } catch {
965
+ return "";
966
+ }
967
+ }
968
+ function extractComponentId(source) {
969
+ const match = source.match(/declaration\s*:\s*\{[\s\S]*?componentId\s*:\s*['"]([^'"]+)['"]/);
970
+ return match?.[1];
971
+ }
935
972
  async function listLocalModules(appDir) {
936
973
  const packagesDir = path7.join(appDir, "packages");
937
974
  const result = [];
@@ -968,25 +1005,31 @@ async function collectDeclared(appDir) {
968
1005
  const descriptor = readComponentFile(local) ?? readDescriptorFromNodeModules(appDir, entry.package);
969
1006
  const probeDir = existsSync5(path7.join(local, "src")) ? local : path7.join(appDir, "node_modules", ...entry.package.split("/"));
970
1007
  const c = descriptor?.contributes;
1008
+ const hasServerEntry = descriptor !== null && probeModuleObjectExport(probeDir, "server", "serverModule");
971
1009
  declared.push({
972
1010
  id: entry.id,
973
1011
  pkg: entry.mode === "sdk" ? entry.package : `@app/${entry.id}`,
974
1012
  mode: entry.mode,
975
- hasServerEntry: descriptor !== null && probeModuleObjectExport(probeDir, "server", "serverModule"),
1013
+ hasServerEntry,
976
1014
  hasClientEntry: descriptor !== null && probeModuleObjectExport(probeDir, "client", "clientModule"),
977
- hasCards: (c?.cards?.length ?? 0) > 0
1015
+ hasCards: (c?.cards?.length ?? 0) > 0,
1016
+ // 011 评审 M3:declaration.componentId(deployment 对账真源;老模块无 declaration → undefined)
1017
+ ...hasServerEntry ? { componentId: extractComponentId(readServerSource(probeDir)) } : {}
978
1018
  });
979
1019
  }
980
1020
  for (const mod of await listLocalModules(appDir)) {
981
1021
  if (seen.has(mod.id)) continue;
982
1022
  const c = mod.descriptor.contributes;
1023
+ const hasServerEntry = probeModuleObjectExport(mod.dir, "server", "serverModule");
983
1024
  declared.push({
984
1025
  id: mod.id,
985
1026
  pkg: `@app/${mod.id}`,
986
1027
  mode: "local",
987
- hasServerEntry: probeModuleObjectExport(mod.dir, "server", "serverModule"),
1028
+ hasServerEntry,
988
1029
  hasClientEntry: probeModuleObjectExport(mod.dir, "client", "clientModule"),
989
- hasCards: (c.cards?.length ?? 0) > 0
1030
+ hasCards: (c.cards?.length ?? 0) > 0,
1031
+ // 011 评审 M3:declaration.componentId(同 npmModules 路径)
1032
+ ...hasServerEntry ? { componentId: extractComponentId(readServerSource(mod.dir)) } : {}
990
1033
  });
991
1034
  }
992
1035
  return declared;
@@ -2093,6 +2136,181 @@ function legacyPlatformFilesRule(ctx) {
2093
2136
  return issues;
2094
2137
  }
2095
2138
 
2139
+ // src/doctor/rules/mall-deployment.ts
2140
+ import { existsSync as existsSync19, readFileSync as readFileSync8 } from "fs";
2141
+ import { readdir as readdir11 } from "fs/promises";
2142
+ import { createRequire as createRequire2 } from "module";
2143
+ import path23 from "path";
2144
+ function resolveModuleRoot(ctx, pkg) {
2145
+ try {
2146
+ const req = createRequire2(path23.join(ctx.appDir, "package.json"));
2147
+ const resolved = req.resolve(`${pkg}/package.json`);
2148
+ return path23.dirname(resolved);
2149
+ } catch {
2150
+ return void 0;
2151
+ }
2152
+ }
2153
+ function readServerSource2(moduleRoot) {
2154
+ const candidates = [
2155
+ path23.join(moduleRoot, "src/server/index.ts"),
2156
+ path23.join(moduleRoot, "src/server/index.tsx")
2157
+ ];
2158
+ for (const c of candidates) {
2159
+ if (existsSync19(c)) return readFileSync8(c, "utf8");
2160
+ }
2161
+ return "";
2162
+ }
2163
+ function extractFeatures(source) {
2164
+ const match = source.match(/features\s*:\s*\[([^\]]*)\]/);
2165
+ if (!match) return [];
2166
+ return [...match[1].matchAll(/['"]([^'"]+)['"]/g)].map((m) => m[1]);
2167
+ }
2168
+ function extractIntentPatterns(source) {
2169
+ const patterns = [];
2170
+ for (const block of source.matchAll(/patterns\s*:\s*\[([^\]]*)\]/g)) {
2171
+ for (const m of block[1].matchAll(/['"]([^'"]+)['"]/g)) {
2172
+ patterns.push(m[1]);
2173
+ }
2174
+ }
2175
+ return patterns;
2176
+ }
2177
+ function extractFeatureRefs(source) {
2178
+ return [...source.matchAll(/isFeatureEnabled\s*\(\s*['"]([^'"]+)['"]\s*\)/g)].map((m) => m[1]);
2179
+ }
2180
+ async function deploymentConsistencyRule(ctx) {
2181
+ const issues = [];
2182
+ const deploymentDir = path23.join(ctx.appDir, "config/deployments");
2183
+ if (!existsSync19(deploymentDir)) return issues;
2184
+ const entries = await readdir11(deploymentDir);
2185
+ const jsonFiles = entries.filter((e) => e.endsWith(".json"));
2186
+ if (jsonFiles.length === 0) return issues;
2187
+ for (const file of jsonFiles) {
2188
+ let parsed;
2189
+ try {
2190
+ parsed = JSON.parse(readFileSync8(path23.join(deploymentDir, file), "utf8"));
2191
+ } catch {
2192
+ issues.push({ rule: "deployment-consistency", level: "error", message: `deployment \u914D\u7F6E\u975E\u6CD5 JSON\uFF1Aconfig/deployments/${file}` });
2193
+ continue;
2194
+ }
2195
+ const components = parsed.deployment?.components ?? [];
2196
+ const declaredPkgs = new Map(ctx.declared.map((d) => [d.componentId ?? d.id, d]));
2197
+ for (const component of components) {
2198
+ const componentId = component.componentId;
2199
+ if (!componentId) {
2200
+ issues.push({
2201
+ rule: "deployment-consistency",
2202
+ level: "error",
2203
+ message: `config/deployments/${file}\uFF1Acomponents \u9879\u7F3A componentId`
2204
+ });
2205
+ continue;
2206
+ }
2207
+ const declared = declaredPkgs.get(componentId);
2208
+ if (!declared) {
2209
+ issues.push({
2210
+ rule: "deployment-consistency",
2211
+ level: component.optional ? "warning" : "error",
2212
+ message: `config/deployments/${file}\uFF1AcomponentId "${componentId}" \u672A\u5B89\u88C5\u5BF9\u5E94\u6A21\u5757` + (component.optional ? "\uFF08optional \u7EC4\u4EF6\uFF0C\u964D\u7EA7 warning\uFF09" : "\uFF08\u5B89\u88C5\u5BF9\u5E94\u6A21\u5757\u6216\u6807\u8BB0 optional\uFF09")
2213
+ });
2214
+ continue;
2215
+ }
2216
+ const moduleRoot = resolveModuleRoot(ctx, declared.pkg);
2217
+ if (moduleRoot && component.enabledFeatures?.length) {
2218
+ const source = readServerSource2(moduleRoot);
2219
+ const declaredFeatures = extractFeatures(source);
2220
+ if (declaredFeatures.length > 0) {
2221
+ for (const feature of component.enabledFeatures) {
2222
+ if (!declaredFeatures.includes(feature)) {
2223
+ issues.push({
2224
+ rule: "deployment-consistency",
2225
+ level: "error",
2226
+ message: `config/deployments/${file}\uFF1Afeature "${feature}" \u4E0D\u5728 ${componentId} \u7684 declaration.features \u5185\uFF08\u5DF2\u58F0\u660E\uFF1A${declaredFeatures.join(", ") || "(\u65E0)"}\uFF09`
2227
+ });
2228
+ }
2229
+ }
2230
+ }
2231
+ }
2232
+ }
2233
+ }
2234
+ return issues;
2235
+ }
2236
+ async function intentOverlapRule(ctx) {
2237
+ const issues = [];
2238
+ const byPattern = /* @__PURE__ */ new Map();
2239
+ for (const declared of ctx.declared) {
2240
+ if (!declared.hasServerEntry) continue;
2241
+ const root = resolveModuleRoot(ctx, declared.pkg);
2242
+ if (!root) continue;
2243
+ const patterns = extractIntentPatterns(readServerSource2(root));
2244
+ for (const p of patterns) {
2245
+ const list = byPattern.get(p) ?? [];
2246
+ list.push(declared.id);
2247
+ byPattern.set(p, list);
2248
+ }
2249
+ }
2250
+ for (const [pattern, modules] of byPattern) {
2251
+ if (modules.length > 1) {
2252
+ issues.push({
2253
+ rule: "intent-overlap",
2254
+ level: "warning",
2255
+ message: `\u610F\u56FE\u8BCD "${pattern}" \u5728\u591A\u4E2A\u6A21\u5757\u58F0\u660E\uFF08${modules.join(", ")}\uFF09\u2014\u2014\u5148\u6CE8\u518C\u5148\u547D\u4E2D`
2256
+ });
2257
+ }
2258
+ }
2259
+ return issues;
2260
+ }
2261
+ async function skillNameConflictRule(ctx) {
2262
+ const issues = [];
2263
+ const byName = /* @__PURE__ */ new Map();
2264
+ for (const declared of ctx.declared) {
2265
+ if (!declared.hasServerEntry) continue;
2266
+ const root = resolveModuleRoot(ctx, declared.pkg);
2267
+ if (!root) continue;
2268
+ const skillsDir = path23.join(root, "skills");
2269
+ if (!existsSync19(skillsDir)) continue;
2270
+ try {
2271
+ const names = (await readdir11(skillsDir, { withFileTypes: true })).filter((e) => e.isDirectory()).map((e) => e.name);
2272
+ for (const name of names) {
2273
+ const list = byName.get(name) ?? [];
2274
+ list.push(declared.id);
2275
+ byName.set(name, list);
2276
+ }
2277
+ } catch {
2278
+ }
2279
+ }
2280
+ for (const [name, modules] of byName) {
2281
+ if (modules.length > 1) {
2282
+ issues.push({
2283
+ rule: "skill-name-conflict",
2284
+ level: "warning",
2285
+ message: `skill "${name}" \u5728\u591A\u4E2A\u6A21\u5757\u58F0\u660E\uFF08${modules.join(", ")}\uFF09\u2014\u2014\u540E\u6CE8\u518C\u8986\u76D6`
2286
+ });
2287
+ }
2288
+ }
2289
+ return issues;
2290
+ }
2291
+ async function featureDeclarationRule(ctx) {
2292
+ const issues = [];
2293
+ for (const declared of ctx.declared) {
2294
+ if (!declared.hasServerEntry) continue;
2295
+ const root = resolveModuleRoot(ctx, declared.pkg);
2296
+ if (!root) continue;
2297
+ const source = readServerSource2(root);
2298
+ if (!source) continue;
2299
+ const declaredFeatures = extractFeatures(source);
2300
+ const refs = extractFeatureRefs(source);
2301
+ for (const ref of refs) {
2302
+ if (declaredFeatures.length > 0 && !declaredFeatures.includes(ref)) {
2303
+ issues.push({
2304
+ rule: "feature-declaration",
2305
+ level: "error",
2306
+ message: `\u6A21\u5757 ${declared.id}\uFF1AisFeatureEnabled("${ref}") \u4E0D\u5728 declaration.features \u5185\uFF08\u5DF2\u58F0\u660E\uFF1A${declaredFeatures.join(", ") || "(\u65E0)"}\uFF09`
2307
+ });
2308
+ }
2309
+ }
2310
+ }
2311
+ return issues;
2312
+ }
2313
+
2096
2314
  // src/doctor/index.ts
2097
2315
  var DOCTOR_RULES = [
2098
2316
  { name: "workspace-dag", run: workspaceDagRule },
@@ -2108,7 +2326,11 @@ var DOCTOR_RULES = [
2108
2326
  { name: "naked-write-route", run: nakedWriteRouteRule },
2109
2327
  { name: "descriptor-schema", run: descriptorSchemaRule },
2110
2328
  { name: "workspace-ref-resolved", run: workspaceRefResolvedRule },
2111
- { name: "legacy-platform-files", run: legacyPlatformFilesRule }
2329
+ { name: "legacy-platform-files", run: legacyPlatformFilesRule },
2330
+ { name: "deployment-consistency", run: deploymentConsistencyRule },
2331
+ { name: "intent-overlap", run: intentOverlapRule },
2332
+ { name: "skill-name-conflict", run: skillNameConflictRule },
2333
+ { name: "feature-declaration", run: featureDeclarationRule }
2112
2334
  ];
2113
2335
  async function runDoctor(ctx, opts) {
2114
2336
  const issues = [];
@@ -2244,10 +2466,10 @@ async function resolveDependencies(appDir, rootIds, declared, extraRoots = []) {
2244
2466
 
2245
2467
  // src/commands/add.ts
2246
2468
  function readSourceDescriptor(sourceDir) {
2247
- const file = path23.join(sourceDir, "tbox.component.json");
2248
- if (!existsSync19(file)) return null;
2469
+ const file = path24.join(sourceDir, "tbox.component.json");
2470
+ if (!existsSync20(file)) return null;
2249
2471
  try {
2250
- const parsed = parseComponentDescriptor(JSON.parse(readFileSync8(file, "utf8")));
2472
+ const parsed = parseComponentDescriptor(JSON.parse(readFileSync9(file, "utf8")));
2251
2473
  return parsed.ok ? parsed.value : null;
2252
2474
  } catch {
2253
2475
  return null;
@@ -2255,20 +2477,20 @@ function readSourceDescriptor(sourceDir) {
2255
2477
  }
2256
2478
  function resolveDepSource(sourcePath, depId) {
2257
2479
  if (!sourcePath) return null;
2258
- const dir = path23.dirname(sourcePath);
2259
- const siblingDir = path23.join(dir, depId);
2260
- if (existsSync19(path23.join(siblingDir, "package.json"))) return siblingDir;
2480
+ const dir = path24.dirname(sourcePath);
2481
+ const siblingDir = path24.join(dir, depId);
2482
+ if (existsSync20(path24.join(siblingDir, "package.json"))) return siblingDir;
2261
2483
  try {
2262
2484
  const tgz = readdirSync2(dir).find(
2263
2485
  (f) => f.endsWith(".tgz") && f.includes(`-${depId}-`)
2264
2486
  );
2265
- if (tgz) return path23.join(dir, tgz);
2487
+ if (tgz) return path24.join(dir, tgz);
2266
2488
  } catch {
2267
2489
  }
2268
2490
  return null;
2269
2491
  }
2270
2492
  function isInstalled(appDir, id) {
2271
- if (existsSync19(path23.join(appDir, "packages", id))) return true;
2493
+ if (existsSync20(path24.join(appDir, "packages", id))) return true;
2272
2494
  const manifest = readAppManifest(appDir);
2273
2495
  return manifest?.npmModules.some((m) => m.id === id && m.mode === "sdk") ?? false;
2274
2496
  }
@@ -2296,7 +2518,7 @@ async function addModuleWithDepsCore(opts, visited, asDependency, tarballs) {
2296
2518
  assertValidModuleId(id, `--mode local ${opts.pkg}`);
2297
2519
  } else {
2298
2520
  if (!opts.source) throw new Error(`--mode ${opts.mode} \u9700\u8981 --source <\u76EE\u5F55\u6216 tgz \u6216 registry \u5305>`);
2299
- const isRegSource = isReg && !existsSync19(path23.resolve(opts.source));
2521
+ const isRegSource = isReg && !existsSync20(path24.resolve(opts.source));
2300
2522
  if (!isRegSource && !opts.source.endsWith(".tgz") && !LocalDirSource.isUsable(opts.source)) {
2301
2523
  throw new Error(`\u6A21\u5757\u6E90\u65E0\u6548\uFF08\u7F3A package.json\uFF09: ${opts.source}`);
2302
2524
  }
@@ -2305,7 +2527,7 @@ async function addModuleWithDepsCore(opts, visited, asDependency, tarballs) {
2305
2527
  tarballs.push(opened.source);
2306
2528
  }
2307
2529
  const pkgOnly = opts.pkg.replace(/@[^/]+$/, "");
2308
- id = pkgOnly.replace(/^@tbox\.cn\/app-/, "").replace(/^@[^/]+\//, "");
2530
+ id = deriveModuleId(pkgOnly);
2309
2531
  assertValidModuleId(id, `--mode ${opts.mode} ${opts.pkg}`);
2310
2532
  sourceDescriptor = readSourceDescriptor(opened.sourceDir);
2311
2533
  }
@@ -2314,7 +2536,7 @@ async function addModuleWithDepsCore(opts, visited, asDependency, tarballs) {
2314
2536
  return;
2315
2537
  }
2316
2538
  if (!asDependency && isInstalled(appDir, id)) {
2317
- const where = existsSync19(path23.join(appDir, "packages", id)) ? `packages/${id}` : "manifest \u5DF2\u767B\u8BB0\uFF08sdk \u5305\uFF0C\u65E0\u672C\u5730\u76EE\u5F55\uFF09";
2539
+ const where = existsSync20(path24.join(appDir, "packages", id)) ? `packages/${id}` : "manifest \u5DF2\u767B\u8BB0\uFF08sdk \u5305\uFF0C\u65E0\u672C\u5730\u76EE\u5F55\uFF09";
2318
2540
  throw new Error(`\u6A21\u5757 ${id} \u5DF2\u5B58\u5728\uFF08${where}\uFF09\u3002\u82E5\u8981\u91CD\u65B0\u5C55\u5F00\u8BF7\u5148 remove \u6216\u624B\u52A8\u5904\u7406\uFF1B\u88C5\u914D\u552F\u4E00\u8986\u76D6\u5165\u53E3\u4E3A sync --force`);
2319
2541
  }
2320
2542
  if (visited.has(id)) return;
@@ -2345,7 +2567,7 @@ async function addModuleWithDepsCore(opts, visited, asDependency, tarballs) {
2345
2567
  if (depOpened.source instanceof TarballSource || depOpened.source instanceof RegistrySource) {
2346
2568
  tarballs.push(depOpened.source);
2347
2569
  }
2348
- const depIsBusiness = existsSync19(path23.join(depOpened.sourceDir, "tbox.component.json"));
2570
+ const depIsBusiness = existsSync20(path24.join(depOpened.sourceDir, "tbox.component.json"));
2349
2571
  await addModuleWithDeps(
2350
2572
  { pkg: depPkg, mode: depIsBusiness ? "codegen" : "sdk", source: depSource, registry: opts.registry },
2351
2573
  visited,
@@ -2558,9 +2780,9 @@ async function doctorCommand(opts = {}) {
2558
2780
  }
2559
2781
 
2560
2782
  // src/commands/update.ts
2561
- import { existsSync as existsSync20 } from "fs";
2562
- import { readdir as readdir11, readFile as readFile6, unlink, writeFile as writeFile7 } from "fs/promises";
2563
- import path24 from "path";
2783
+ import { existsSync as existsSync21 } from "fs";
2784
+ import { readdir as readdir12, readFile as readFile6, unlink, writeFile as writeFile7 } from "fs/promises";
2785
+ import path25 from "path";
2564
2786
 
2565
2787
  // src/merge3.ts
2566
2788
  import { diffArrays } from "diff";
@@ -2643,21 +2865,21 @@ function merge3(base, ours, theirs) {
2643
2865
  // src/commands/update.ts
2644
2866
  var EXCLUDED = /* @__PURE__ */ new Set(["node_modules", "dist", ".git", ".tbox"]);
2645
2867
  function openSourceDir(source) {
2646
- if (source.endsWith(".tgz") && existsSync20(source)) {
2868
+ if (source.endsWith(".tgz") && existsSync21(source)) {
2647
2869
  const tarball = new TarballSource(source);
2648
2870
  return { dir: tarball.getDir(), tarball };
2649
2871
  }
2650
- return { dir: path24.resolve(source), tarball: null };
2872
+ return { dir: path25.resolve(source), tarball: null };
2651
2873
  }
2652
2874
  async function readPackageFiles(dir) {
2653
2875
  const map = /* @__PURE__ */ new Map();
2654
2876
  async function walk(rel) {
2655
- const full = path24.join(dir, rel);
2656
- const entries = await readdir11(full, { withFileTypes: true });
2877
+ const full = path25.join(dir, rel);
2878
+ const entries = await readdir12(full, { withFileTypes: true });
2657
2879
  for (const entry of entries) {
2658
2880
  if (EXCLUDED.has(entry.name)) continue;
2659
2881
  const child = rel ? `${rel}/${entry.name}` : entry.name;
2660
- const childFull = path24.join(full, entry.name);
2882
+ const childFull = path25.join(full, entry.name);
2661
2883
  if (entry.isDirectory()) {
2662
2884
  await walk(child);
2663
2885
  } else {
@@ -2687,8 +2909,8 @@ async function updateModule(opts) {
2687
2909
  console.log(`\u2705 \u5DF2\u5347\u7EA7 ${entry.package}\uFF08sdk \u6A21\u5F0F\uFF09`);
2688
2910
  return;
2689
2911
  }
2690
- const pkgDir = path24.join(appDir, "packages", opts.module);
2691
- if (!existsSync20(pkgDir)) throw new Error(`\u7F3A\u5C11 packages/${opts.module}`);
2912
+ const pkgDir = path25.join(appDir, "packages", opts.module);
2913
+ if (!existsSync21(pkgDir)) throw new Error(`\u7F3A\u5C11 packages/${opts.module}`);
2692
2914
  const ours = await readPackageFiles(pkgDir);
2693
2915
  const tarballs = [];
2694
2916
  try {
@@ -2735,8 +2957,8 @@ async function updateModule(opts) {
2735
2957
  return;
2736
2958
  }
2737
2959
  for (const [key, content] of mergedFiles) {
2738
- const out = path24.join(pkgDir, key);
2739
- if (content === "" && existsSync20(out)) {
2960
+ const out = path25.join(pkgDir, key);
2961
+ if (content === "" && existsSync21(out)) {
2740
2962
  await unlink(out);
2741
2963
  console.log(` \u{1F5D1} \u5DF2\u5220\u9664 ${key}\uFF08\u5347\u7EA7\u6E90\u5220\u9664\u8BE5\u6587\u4EF6\uFF09`);
2742
2964
  continue;
@@ -2765,27 +2987,27 @@ async function updateModule(opts) {
2765
2987
  }
2766
2988
 
2767
2989
  // src/commands/publish.ts
2768
- import { existsSync as existsSync22, readFileSync as readFileSync10, mkdtempSync as mkdtempSync2, rmSync as rmSync2 } from "fs";
2990
+ import { existsSync as existsSync23, readFileSync as readFileSync11, mkdtempSync as mkdtempSync2, rmSync as rmSync2 } from "fs";
2769
2991
  import { tmpdir as tmpdir2 } from "os";
2770
- import path26 from "path";
2992
+ import path27 from "path";
2771
2993
 
2772
2994
  // src/commands/pack.ts
2773
- import { existsSync as existsSync21, readFileSync as readFileSync9, readdirSync as readdirSync3 } from "fs";
2995
+ import { existsSync as existsSync22, readFileSync as readFileSync10, readdirSync as readdirSync3 } from "fs";
2774
2996
  import { execFileSync as execFileSync3 } from "child_process";
2775
- import path25 from "path";
2997
+ import path26 from "path";
2776
2998
  function tarballFileName(name, version) {
2777
2999
  const plain = name.replace(/^@/, "").replace("/", "-");
2778
3000
  return `${plain}-${version}.tgz`;
2779
3001
  }
2780
3002
  function validatePublishableModule(moduleDir) {
2781
- if (!existsSync21(moduleDir) || !existsSync21(path25.join(moduleDir, "package.json"))) {
3003
+ if (!existsSync22(moduleDir) || !existsSync22(path26.join(moduleDir, "package.json"))) {
2782
3004
  throw new Error(`\u6A21\u5757\u76EE\u5F55\u65E0\u6548\uFF08\u7F3A package.json\uFF09: ${moduleDir}`);
2783
3005
  }
2784
3006
  let pkg;
2785
3007
  try {
2786
- pkg = JSON.parse(readFileSync9(path25.join(moduleDir, "package.json"), "utf8"));
3008
+ pkg = JSON.parse(readFileSync10(path26.join(moduleDir, "package.json"), "utf8"));
2787
3009
  } catch {
2788
- throw new Error(`package.json \u89E3\u6790\u5931\u8D25: ${path25.join(moduleDir, "package.json")}`);
3010
+ throw new Error(`package.json \u89E3\u6790\u5931\u8D25: ${path26.join(moduleDir, "package.json")}`);
2789
3011
  }
2790
3012
  const name = typeof pkg.name === "string" ? pkg.name : "";
2791
3013
  if (!/^@tbox\.cn\//.test(name)) {
@@ -2799,20 +3021,20 @@ function validatePublishableModule(moduleDir) {
2799
3021
  }
2800
3022
  function packModule(moduleDir, outDir) {
2801
3023
  const { name, version } = validatePublishableModule(moduleDir);
2802
- const absOut = path25.resolve(outDir);
3024
+ const absOut = path26.resolve(outDir);
2803
3025
  execFileSync3("pnpm", ["pack", "--pack-destination", absOut], { stdio: "inherit", cwd: moduleDir });
2804
- return path25.join(absOut, tarballFileName(name, version));
3026
+ return path26.join(absOut, tarballFileName(name, version));
2805
3027
  }
2806
3028
  function detectKind(pkgDir, name) {
2807
- if (existsSync21(path25.join(pkgDir, "pnpm-workspace.template.yaml"))) return "template";
2808
- if (existsSync21(path25.join(pkgDir, "tbox.component.json"))) return "module";
3029
+ if (existsSync22(path26.join(pkgDir, "pnpm-workspace.template.yaml"))) return "template";
3030
+ if (existsSync22(path26.join(pkgDir, "tbox.component.json"))) return "module";
2809
3031
  if (/^@[^/]+\/app-contracts/.test(name)) return "contract";
2810
3032
  return "generic";
2811
3033
  }
2812
3034
  function listAllFiles(dir) {
2813
3035
  const out = [];
2814
3036
  function walk(rel) {
2815
- const full = path25.join(dir, rel);
3037
+ const full = path26.join(dir, rel);
2816
3038
  for (const entry of readdirSync3(full, { withFileTypes: true })) {
2817
3039
  if (entry.name === "node_modules" || entry.name === ".git") continue;
2818
3040
  const child = rel ? `${rel}/${entry.name}` : entry.name;
@@ -2841,10 +3063,10 @@ function collectExportTargets(exports) {
2841
3063
  }
2842
3064
  function verifyPkgDir(pkgDir, kind) {
2843
3065
  const issues = [];
2844
- const pkgFile = path25.join(pkgDir, "package.json");
3066
+ const pkgFile = path26.join(pkgDir, "package.json");
2845
3067
  let pkg;
2846
3068
  try {
2847
- pkg = JSON.parse(readFileSync9(pkgFile, "utf8"));
3069
+ pkg = JSON.parse(readFileSync10(pkgFile, "utf8"));
2848
3070
  } catch {
2849
3071
  issues.push({ rule: "pack-manifest", level: "error", message: "\u4EA7\u7269\u7F3A\u5C11\u53EF\u89E3\u6790\u7684 package.json" });
2850
3072
  return issues;
@@ -2872,7 +3094,7 @@ function verifyPkgDir(pkgDir, kind) {
2872
3094
  level: "error",
2873
3095
  message: `exports \u6307\u5411\u5F00\u53D1\u6001\u6E90\u7801 "${t}"\uFF08\u53D1\u5E03\u6001\u5E94\u6307\u5411 dist/\uFF09`
2874
3096
  });
2875
- } else if (t.startsWith("./") && !existsSync21(path25.join(pkgDir, t))) {
3097
+ } else if (t.startsWith("./") && !existsSync22(path26.join(pkgDir, t))) {
2876
3098
  issues.push({
2877
3099
  rule: "pack-exports",
2878
3100
  level: "error",
@@ -2905,7 +3127,7 @@ function verifyPkgDir(pkgDir, kind) {
2905
3127
  }
2906
3128
  if (kindOf === "module") {
2907
3129
  for (const required of ["src", "dist", "tbox.component.json"]) {
2908
- if (!files.includes(required) && !existsSync21(path25.join(pkgDir, required))) {
3130
+ if (!files.includes(required) && !existsSync22(path26.join(pkgDir, required))) {
2909
3131
  issues.push({ rule: "pack-files", level: "error", message: `\u4E1A\u52A1\u6A21\u5757\u4EA7\u7269\u7F3A\u5C11 ${required}` });
2910
3132
  }
2911
3133
  }
@@ -2919,12 +3141,12 @@ function verifyPkgDir(pkgDir, kind) {
2919
3141
  "tsconfig.base.json",
2920
3142
  "scripts/verify-generated.mjs"
2921
3143
  ]) {
2922
- if (!existsSync21(path25.join(pkgDir, required))) {
3144
+ if (!existsSync22(path26.join(pkgDir, required))) {
2923
3145
  issues.push({ rule: "pack-files", level: "error", message: `\u6A21\u677F\u4EA7\u7269\u7F3A\u5C11 ${required}` });
2924
3146
  }
2925
3147
  }
2926
3148
  for (const leaked2 of ["pnpm-workspace.yaml", "pnpm-lock.yaml"]) {
2927
- if (existsSync21(path25.join(pkgDir, leaked2))) {
3149
+ if (existsSync22(path26.join(pkgDir, leaked2))) {
2928
3150
  issues.push({
2929
3151
  rule: "pack-files",
2930
3152
  level: "error",
@@ -2967,11 +3189,11 @@ async function verifyTarball(tgzPath) {
2967
3189
  const issues = verifyPkgDir(pkgDir, kind);
2968
3190
  if (pkg.name && pkg.version) {
2969
3191
  const expect = tarballFileName(pkg.name, pkg.version);
2970
- if (path25.basename(tgzPath) !== expect) {
3192
+ if (path26.basename(tgzPath) !== expect) {
2971
3193
  issues.push({
2972
3194
  rule: "pack-filename",
2973
3195
  level: "error",
2974
- message: `tgz \u6587\u4EF6\u540D ${path25.basename(tgzPath)} \u4E0E\u5305 ${pkg.name}@${pkg.version} \u671F\u671B ${expect} \u4E0D\u4E00\u81F4`
3196
+ message: `tgz \u6587\u4EF6\u540D ${path26.basename(tgzPath)} \u4E0E\u5305 ${pkg.name}@${pkg.version} \u671F\u671B ${expect} \u4E0D\u4E00\u81F4`
2975
3197
  });
2976
3198
  }
2977
3199
  }
@@ -2986,9 +3208,9 @@ function printIssues(issues) {
2986
3208
  }
2987
3209
  }
2988
3210
  async function packCommand(opts) {
2989
- const moduleDir = path25.resolve(process.cwd(), opts.module);
3211
+ const moduleDir = path26.resolve(process.cwd(), opts.module);
2990
3212
  const tgzPath = packModule(moduleDir, opts.out);
2991
- console.log(`\u2705 \u5DF2\u6253\u5305 ${path25.basename(tgzPath)} \u2192 ${path25.resolve(opts.out)}`);
3213
+ console.log(`\u2705 \u5DF2\u6253\u5305 ${path26.basename(tgzPath)} \u2192 ${path26.resolve(opts.out)}`);
2992
3214
  if (opts.check) {
2993
3215
  const issues = await verifyTarball(tgzPath);
2994
3216
  printIssues(issues);
@@ -2999,19 +3221,19 @@ async function packCommand(opts) {
2999
3221
  // src/commands/publish.ts
3000
3222
  async function publishModule(opts) {
3001
3223
  const cwd = process.cwd();
3002
- const moduleDir = path26.resolve(cwd, opts.module);
3003
- if (!existsSync22(moduleDir) || !existsSync22(path26.join(moduleDir, "package.json"))) {
3224
+ const moduleDir = path27.resolve(cwd, opts.module);
3225
+ if (!existsSync23(moduleDir) || !existsSync23(path27.join(moduleDir, "package.json"))) {
3004
3226
  throw new Error(`\u6A21\u5757\u76EE\u5F55\u65E0\u6548\uFF08\u7F3A package.json\uFF09: ${opts.module}`);
3005
3227
  }
3006
3228
  let tgzPath;
3007
3229
  let workDir = null;
3008
3230
  if (opts.tgz) {
3009
- tgzPath = path26.resolve(opts.tgz);
3010
- if (!existsSync22(tgzPath)) throw new Error(`tgz \u4EA7\u7269\u4E0D\u5B58\u5728: ${opts.tgz}`);
3231
+ tgzPath = path27.resolve(opts.tgz);
3232
+ if (!existsSync23(tgzPath)) throw new Error(`tgz \u4EA7\u7269\u4E0D\u5B58\u5728: ${opts.tgz}`);
3011
3233
  const tarball = new TarballSource(tgzPath);
3012
3234
  try {
3013
3235
  const tgzPkg = JSON.parse(await tarball.readFile("package.json"));
3014
- const modulePkg = JSON.parse(readFileSync10(path26.join(moduleDir, "package.json"), "utf8"));
3236
+ const modulePkg = JSON.parse(readFileSync11(path27.join(moduleDir, "package.json"), "utf8"));
3015
3237
  if (tgzPkg.name !== modulePkg.name) {
3016
3238
  throw new Error(
3017
3239
  `--tgz \u5305\u540D ${tgzPkg.name ?? "(\u672A\u77E5)"} \u4E0E\u6A21\u5757 ${modulePkg.name ?? "(\u672A\u77E5)"} \u4E0D\u4E00\u81F4\uFF08\u8BF7\u786E\u8BA4 --tgz \u4E0E\u6A21\u5757\u5339\u914D\uFF09`
@@ -3021,7 +3243,7 @@ async function publishModule(opts) {
3021
3243
  tarball.dispose();
3022
3244
  }
3023
3245
  } else {
3024
- workDir = mkdtempSync2(path26.join(tmpdir2(), "tbox-publish-"));
3246
+ workDir = mkdtempSync2(path27.join(tmpdir2(), "tbox-publish-"));
3025
3247
  tgzPath = packModule(moduleDir, workDir);
3026
3248
  }
3027
3249
  try {
@@ -3029,9 +3251,9 @@ async function publishModule(opts) {
3029
3251
  if (issues.length > 0) printIssues(issues);
3030
3252
  const errors = issues.filter((i) => i.level === "error");
3031
3253
  if (errors.length > 0) {
3032
- throw new Error(`\u4EA7\u7269\u95E8\u7981\u5931\u8D25\uFF08${errors.length} \u5904 error\uFF09\uFF0C\u5DF2\u4E2D\u6B62\u53D1\u5E03: ${path26.basename(tgzPath)}`);
3254
+ throw new Error(`\u4EA7\u7269\u95E8\u7981\u5931\u8D25\uFF08${errors.length} \u5904 error\uFF09\uFF0C\u5DF2\u4E2D\u6B62\u53D1\u5E03: ${path27.basename(tgzPath)}`);
3033
3255
  }
3034
- if (!workDir) workDir = mkdtempSync2(path26.join(tmpdir2(), "tbox-publish-"));
3256
+ if (!workDir) workDir = mkdtempSync2(path27.join(tmpdir2(), "tbox-publish-"));
3035
3257
  const { execFileSync: execFileSync4 } = await import("child_process");
3036
3258
  const registryArgs = opts.registry ? ["--registry", opts.registry] : [];
3037
3259
  execFileSync4(
@@ -3040,7 +3262,7 @@ async function publishModule(opts) {
3040
3262
  { stdio: "inherit", cwd: workDir }
3041
3263
  );
3042
3264
  console.log(
3043
- `\u2705 \u5DF2\u53D1\u5E03 ${path26.basename(tgzPath)}${opts.registry ? ` \u2192 ${opts.registry}` : ""}${opts.dryRun ? "\uFF08dry-run\uFF09" : ""}`
3265
+ `\u2705 \u5DF2\u53D1\u5E03 ${path27.basename(tgzPath)}${opts.registry ? ` \u2192 ${opts.registry}` : ""}${opts.dryRun ? "\uFF08dry-run\uFF09" : ""}`
3044
3266
  );
3045
3267
  } finally {
3046
3268
  if (workDir) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tbox.cn/app-cli",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "type": "module",
5
5
  "description": "tbox-app CLI:create / module add|remove|list|sync|diff|doctor|update|publish(纯函数核心 + commander 薄壳)。",
6
6
  "bin": {