u1s1-cli 1.0.0 → 1.2.0

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/deploy.d.ts CHANGED
@@ -1,2 +1,10 @@
1
1
  import { type CliConfig } from "./config.js";
2
+ type SiteVisibility = "public" | "private";
3
+ interface DeployArgs {
4
+ name?: string;
5
+ dirArg?: string;
6
+ visibility?: SiteVisibility;
7
+ }
8
+ export declare function parseDeployArgs(args: string[]): DeployArgs;
2
9
  export declare function deployCommand(cfg: CliConfig, args: string[]): Promise<void>;
10
+ export {};
package/dist/deploy.js CHANGED
@@ -4,8 +4,8 @@ import { createInterface } from "node:readline/promises";
4
4
  import { VERSION, u1s1Dir } from "./config.js";
5
5
  import { authorizedFetch } from "./device-auth.js";
6
6
  /**
7
- * u1s1 deploy:把静态网页一键发布到 <name>.u1s1.app
8
- * 检测项目里的静态站点根目录 首次询问子域名(记在 ~/.u1s1/deploys.json)
7
+ * u1s1 deploy publishes a static site to <project>.<account-code>.u1s1.app.
8
+ * Detect the site root, ask for a project slug, and remember it in ~/.u1s1/deploys.json.
9
9
  * → 并发上传 → 网关原子切换生效,输出可分享的网址。
10
10
  */
11
11
  const deploysFile = join(u1s1Dir, "deploys.json");
@@ -84,6 +84,37 @@ function fmtBytes(n) {
84
84
  return `${Math.round(n / 1024)}KB`;
85
85
  return `${n}B`;
86
86
  }
87
+ export function parseDeployArgs(args) {
88
+ const parsed = {};
89
+ for (let i = 0; i < args.length; i++) {
90
+ const arg = args[i];
91
+ if (arg === "--name" || arg === "-n") {
92
+ const value = args[++i];
93
+ if (!value || value.startsWith("-"))
94
+ throw new Error(`${arg} 后面需要站点名`);
95
+ parsed.name = value.toLowerCase();
96
+ }
97
+ else if (arg.startsWith("--name=")) {
98
+ parsed.name = arg.slice(7).toLowerCase();
99
+ if (!parsed.name)
100
+ throw new Error("--name 后面需要站点名");
101
+ }
102
+ else if (arg === "--public" || arg === "--private") {
103
+ const visibility = arg.slice(2);
104
+ if (parsed.visibility && parsed.visibility !== visibility) {
105
+ throw new Error("--public 和 --private 不能同时使用");
106
+ }
107
+ parsed.visibility = visibility;
108
+ }
109
+ else if (arg.startsWith("-")) {
110
+ throw new Error(`不认识的 deploy 参数:${arg}`);
111
+ }
112
+ else {
113
+ parsed.dirArg = arg;
114
+ }
115
+ }
116
+ return parsed;
117
+ }
87
118
  async function api(cfg, method, path, body) {
88
119
  let resp;
89
120
  try {
@@ -137,15 +168,33 @@ async function promptSiteName(def) {
137
168
  return def;
138
169
  const rl = createInterface({ input: process.stdin, output: process.stdout });
139
170
  try {
140
- const answer = (await rl.question(` 站点子域名(回车用 ${def}):`)).trim().toLowerCase();
171
+ const answer = (await rl.question(` 项目名(回车用 ${def},只需在你的账号内唯一):`)).trim().toLowerCase();
141
172
  return answer || def;
142
173
  }
143
174
  finally {
144
175
  rl.close();
145
176
  }
146
177
  }
178
+ async function promptVisibility() {
179
+ if (!process.stdin.isTTY)
180
+ return "private";
181
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
182
+ try {
183
+ while (true) {
184
+ const answer = (await rl.question(" 发布方式 [1] 公开(进入作品社区) [2] 私密(仅自己登录后可看,默认):")).trim().toLowerCase();
185
+ if (!answer || answer === "2" || answer === "private" || answer === "私密")
186
+ return "private";
187
+ if (answer === "1" || answer === "public" || answer === "公开")
188
+ return "public";
189
+ console.log(" 请输入 1 或 2");
190
+ }
191
+ }
192
+ finally {
193
+ rl.close();
194
+ }
195
+ }
147
196
  export async function deployCommand(cfg, args) {
148
- // 参数:[dir] [--name xxx];u1s1 deploy list 列出已有站点
197
+ // 参数:[dir] [--name xxx] [--public|--private];u1s1 deploy list 列出已有站点
149
198
  if (args[0] === "list") {
150
199
  const { sites } = await api(cfg, "GET", "/deploy/sites");
151
200
  if (!sites.length) {
@@ -154,22 +203,14 @@ export async function deployCommand(cfg, args) {
154
203
  }
155
204
  console.log("");
156
205
  for (const s of sites) {
157
- console.log(` ${s.deployed ? "" : ""} ${s.url} ${fmtBytes(s.total_bytes)} · ${s.updated_at} UTC`);
206
+ const visibility = s.visibility === "private" ? "私密" : s.community_listed ? "公开(社区)" : "公开(未展示)";
207
+ console.log(` ${s.deployed ? "●" : "○"} ${s.url} ${visibility} · ${fmtBytes(s.total_bytes)} · ${s.updated_at} UTC`);
158
208
  }
159
209
  console.log("");
160
210
  return;
161
211
  }
162
- let name;
163
- let dirArg;
164
- for (let i = 0; i < args.length; i++) {
165
- const a = args[i];
166
- if (a === "--name" || a === "-n")
167
- name = args[++i]?.toLowerCase();
168
- else if (a.startsWith("--name="))
169
- name = a.slice(7).toLowerCase();
170
- else if (!a.startsWith("-"))
171
- dirArg = a;
172
- }
212
+ const parsed = parseDeployArgs(args);
213
+ let { name, dirArg, visibility } = parsed;
173
214
  const dir = resolveSiteDir(dirArg);
174
215
  const files = collectFiles(dir);
175
216
  if (!files.some((f) => f.path === "index.html")) {
@@ -187,6 +228,10 @@ export async function deployCommand(cfg, args) {
187
228
  const projectName = BUILD_DIRS.includes(basename(dir)) ? basename(resolve(dir, "..")) : basename(dir);
188
229
  name = await promptSiteName(slugify(projectName));
189
230
  }
231
+ // 同一目录再次部署时保持上次设置;首次部署显式选择。CI/脚本没有交互时
232
+ // 取更安全的 private,用户仍可用 --public 明确公开。
233
+ if (!visibility && remembered !== name)
234
+ visibility = await promptVisibility();
190
235
  let start;
191
236
  for (let attempt = 0; !start; attempt++) {
192
237
  try {
@@ -222,12 +267,25 @@ export async function deployCommand(cfg, args) {
222
267
  const fin = await api(cfg, "POST", "/deploy/finish", {
223
268
  site: start.site,
224
269
  deploy_id: start.deploy_id,
270
+ visibility,
225
271
  });
226
- rememberSite(dir, start.site);
272
+ rememberSite(dir, start.slug || name || start.site);
227
273
  console.log(` ✅ 部署完成,${fin.file_count} 个文件已上线`);
228
274
  console.log("");
229
- console.log(` 🌐 ${fin.url}`);
275
+ console.log(` ${fin.visibility === "private" ? "🔒" : "🌐"} ${fin.url}`);
230
276
  console.log("");
231
- console.log(" 把网址发给朋友就能看。改完代码再跑一次 u1s1 deploy 即可更新。");
277
+ if ((fin.hostname || start.hostname || "").split(".").length > 3) {
278
+ console.log(" 新 hostname 的 HTTPS 证书会由 Total TLS 自动签发,首次访问可能需要等待几分钟。");
279
+ }
280
+ if (fin.visibility === "private") {
281
+ console.log(" 私密站点仅你可见,请从 https://u1s1.io/dashboard#sec-sites 打开。");
282
+ }
283
+ else if (fin.community_listed) {
284
+ console.log(" 已进入 https://u1s1.io/community ,把网址发给朋友就能看。");
285
+ }
286
+ else {
287
+ console.log(" 公开链接可直接访问;运行 u1s1 deploy --public 可明确加入作品社区。");
288
+ }
289
+ console.log(" 改完代码再跑一次 u1s1 deploy 即可更新。");
232
290
  console.log("");
233
291
  }
package/dist/index.js CHANGED
@@ -314,7 +314,7 @@ async function run() {
314
314
  }
315
315
  if (cmd === "--help" || cmd === "-h") {
316
316
  printConsoleBanner(VERSION);
317
- console.log(" u1s1 命令:deploy(发布网页)· login / logout · model · usage · update · import · bench");
317
+ console.log(" u1s1 命令:deploy(发布网页,可选 --public / --private)· login / logout · model · usage · update · import · bench");
318
318
  console.log("");
319
319
  }
320
320
  if (cmd === "web") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "u1s1-cli",
3
- "version": "1.0.0",
3
+ "version": "1.2.0",
4
4
  "description": "u1s1 — 有一说一,最省心的 AI 编程搭子。终端里用中文说需求,AI 帮你读文件、改代码、跑命令。",
5
5
  "type": "module",
6
6
  "bin": {