@lark-apaas/miaoda-cli 0.1.0-alpha.097a394
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/LICENSE +13 -0
- package/README.md +66 -0
- package/bin/miaoda.js +2 -0
- package/dist/api/db/api.js +160 -0
- package/dist/api/db/client.js +108 -0
- package/dist/api/db/index.js +16 -0
- package/dist/api/db/parsers.js +157 -0
- package/dist/api/db/types.js +10 -0
- package/dist/api/file/api.js +420 -0
- package/dist/api/file/client.js +161 -0
- package/dist/api/file/detect.js +56 -0
- package/dist/api/file/index.js +17 -0
- package/dist/api/file/parsers.js +72 -0
- package/dist/api/file/types.js +3 -0
- package/dist/api/index.js +42 -0
- package/dist/api/plugin/api.js +243 -0
- package/dist/api/plugin/index.js +12 -0
- package/dist/api/plugin/types.js +3 -0
- package/dist/cli/commands/db/index.js +73 -0
- package/dist/cli/commands/file/index.js +67 -0
- package/dist/cli/commands/index.js +11 -0
- package/dist/cli/commands/plugin/index.js +204 -0
- package/dist/cli/commands/shared.js +53 -0
- package/dist/cli/handlers/db/data.js +167 -0
- package/dist/cli/handlers/db/index.js +11 -0
- package/dist/cli/handlers/db/schema.js +161 -0
- package/dist/cli/handlers/db/sql.js +173 -0
- package/dist/cli/handlers/file/cp.js +220 -0
- package/dist/cli/handlers/file/helpers.js +16 -0
- package/dist/cli/handlers/file/index.js +13 -0
- package/dist/cli/handlers/file/ls.js +109 -0
- package/dist/cli/handlers/file/rm.js +243 -0
- package/dist/cli/handlers/file/sign.js +96 -0
- package/dist/cli/handlers/file/stat.js +97 -0
- package/dist/cli/handlers/index.js +19 -0
- package/dist/cli/handlers/plugin/index.js +10 -0
- package/dist/cli/handlers/plugin/plugin-local.js +382 -0
- package/dist/cli/handlers/plugin/plugin.js +308 -0
- package/dist/cli/handlers/shared.js +139 -0
- package/dist/main.js +31 -0
- package/dist/utils/config.js +31 -0
- package/dist/utils/error.js +35 -0
- package/dist/utils/http.js +46 -0
- package/dist/utils/index.js +25 -0
- package/dist/utils/log_id.js +13 -0
- package/dist/utils/logger.js +15 -0
- package/dist/utils/output.js +59 -0
- package/package.json +53 -0
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.handleDbSql = handleDbSql;
|
|
37
|
+
const api = __importStar(require("../../../api/index"));
|
|
38
|
+
const error_1 = require("../../../utils/error");
|
|
39
|
+
const output_1 = require("../../../utils/output");
|
|
40
|
+
const shared_1 = require("../../../cli/commands/shared");
|
|
41
|
+
const shared_2 = require("../../../cli/handlers/shared");
|
|
42
|
+
const index_1 = require("../../../api/db/index");
|
|
43
|
+
/**
|
|
44
|
+
* miaoda db sql <query> — 执行任意 SQL。
|
|
45
|
+
*
|
|
46
|
+
* - query 为空时读 stdin
|
|
47
|
+
* - --env 在 P0 阶段不开放(返回 MULTI_ENV_NOT_INITIALIZED)
|
|
48
|
+
* - 多条语句时只展示最后一条的结果(与 PRD 对齐);所有为 DDL 时展示批量摘要
|
|
49
|
+
*/
|
|
50
|
+
async function handleDbSql(query, opts) {
|
|
51
|
+
const appId = (0, shared_1.resolveAppId)(opts);
|
|
52
|
+
if (opts.env && opts.env.length > 0) {
|
|
53
|
+
throw new error_1.AppError("MULTI_ENV_NOT_INITIALIZED", "--env is not available (multi-env not initialized)", {
|
|
54
|
+
next_actions: [
|
|
55
|
+
"Current app uses a single database for dev and production.",
|
|
56
|
+
'Run "miaoda db migration init" to set up multi-env.',
|
|
57
|
+
],
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
const sql = await readSql(query);
|
|
61
|
+
if (!sql.trim()) {
|
|
62
|
+
throw new error_1.AppError("ARGS_INVALID", "Empty SQL (no inline query and stdin is empty)");
|
|
63
|
+
}
|
|
64
|
+
const results = await api.db.execSql({ appId, sql });
|
|
65
|
+
if (results.length === 0) {
|
|
66
|
+
// 后端未返回任何结果,通常不会发生
|
|
67
|
+
if ((0, output_1.isJsonMode)()) {
|
|
68
|
+
(0, output_1.emit)({ data: [] });
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
(0, output_1.emit)("✓ No results");
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
// 全部 DDL 的批量场景:展示统计摘要(对齐 PRD `✓ 3 statements executed`)
|
|
75
|
+
const allDdl = results.every((r) => r.sqlType === "DDL");
|
|
76
|
+
if (allDdl && results.length > 1) {
|
|
77
|
+
if ((0, output_1.isJsonMode)()) {
|
|
78
|
+
(0, output_1.emit)({ data: { statements: results.length } });
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
const tty = (0, shared_2.isStdoutTty)();
|
|
82
|
+
(0, output_1.emit)(tty
|
|
83
|
+
? `✓ ${String(results.length)} statements executed`
|
|
84
|
+
: `OK ${String(results.length)} statements executed`);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
// 其他场景:展示最后一条
|
|
88
|
+
const last = results[results.length - 1];
|
|
89
|
+
renderSingle(last);
|
|
90
|
+
}
|
|
91
|
+
/** 读取 stdin 并返回完整 SQL 文本(stdin 不是 TTY 即认为被 pipe)。 */
|
|
92
|
+
async function readSql(inline) {
|
|
93
|
+
if (inline !== undefined && inline.length > 0)
|
|
94
|
+
return inline;
|
|
95
|
+
const stdin = process.stdin;
|
|
96
|
+
if (stdin.isTTY)
|
|
97
|
+
return "";
|
|
98
|
+
return new Promise((resolve, reject) => {
|
|
99
|
+
let data = "";
|
|
100
|
+
process.stdin.setEncoding("utf8");
|
|
101
|
+
process.stdin.on("data", (chunk) => {
|
|
102
|
+
data += chunk;
|
|
103
|
+
});
|
|
104
|
+
process.stdin.on("end", () => {
|
|
105
|
+
resolve(data);
|
|
106
|
+
});
|
|
107
|
+
process.stdin.on("error", reject);
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
function renderSingle(raw) {
|
|
111
|
+
const parsed = (0, index_1.parseSqlResult)(raw);
|
|
112
|
+
const tty = (0, shared_2.isStdoutTty)();
|
|
113
|
+
if ((0, output_1.isJsonMode)()) {
|
|
114
|
+
(0, output_1.emit)(toJson(parsed));
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
if (parsed.kind === "select") {
|
|
118
|
+
if (parsed.rows.length === 0) {
|
|
119
|
+
(0, output_1.emit)("(0 rows)");
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
const cols = collectColumns(parsed.rows);
|
|
123
|
+
const rows = parsed.rows.map((r) => cols.map((c) => formatCell(r[c])));
|
|
124
|
+
(0, output_1.emit)(tty ? (0, shared_2.renderAlignedTable)(cols, rows) : (0, shared_2.renderTsv)(cols, rows));
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
if (parsed.kind === "dml") {
|
|
128
|
+
const verb = dmlVerb(parsed.sqlType);
|
|
129
|
+
(0, output_1.emit)(tty
|
|
130
|
+
? `✓ ${String(parsed.affectedRows)} row${parsed.affectedRows === 1 ? "" : "s"} ${verb}`
|
|
131
|
+
: `OK ${String(parsed.affectedRows)} rows ${verb}`);
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
// DDL
|
|
135
|
+
(0, output_1.emit)(tty ? "✓ DDL executed" : "OK DDL executed");
|
|
136
|
+
}
|
|
137
|
+
function toJson(parsed) {
|
|
138
|
+
if (parsed.kind === "select") {
|
|
139
|
+
return { data: parsed.rows };
|
|
140
|
+
}
|
|
141
|
+
if (parsed.kind === "dml") {
|
|
142
|
+
return {
|
|
143
|
+
data: {
|
|
144
|
+
sql_type: parsed.sqlType.toLowerCase(),
|
|
145
|
+
affected_rows: parsed.affectedRows,
|
|
146
|
+
},
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
return { data: { sql_type: "ddl" } };
|
|
150
|
+
}
|
|
151
|
+
function dmlVerb(type) {
|
|
152
|
+
switch (type) {
|
|
153
|
+
case "INSERT": return "inserted";
|
|
154
|
+
case "UPDATE": return "updated";
|
|
155
|
+
case "DELETE": return "deleted";
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
/** 从第一行收集列顺序;缺失列保留空白(兼容稀疏行)。 */
|
|
159
|
+
function collectColumns(rows) {
|
|
160
|
+
if (rows.length === 0)
|
|
161
|
+
return [];
|
|
162
|
+
return Object.keys(rows[0]);
|
|
163
|
+
}
|
|
164
|
+
function formatCell(v) {
|
|
165
|
+
if (v === null || v === undefined)
|
|
166
|
+
return "—";
|
|
167
|
+
if (typeof v === "string")
|
|
168
|
+
return v;
|
|
169
|
+
if (typeof v === "number" || typeof v === "boolean")
|
|
170
|
+
return String(v);
|
|
171
|
+
// object / array → JSON
|
|
172
|
+
return JSON.stringify(v);
|
|
173
|
+
}
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.handleFileCp = handleFileCp;
|
|
40
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
41
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
42
|
+
const node_os_1 = __importDefault(require("node:os"));
|
|
43
|
+
const api = __importStar(require("../../../api/index"));
|
|
44
|
+
const output_1 = require("../../../utils/output");
|
|
45
|
+
const error_1 = require("../../../utils/error");
|
|
46
|
+
const shared_1 = require("../../../cli/commands/shared");
|
|
47
|
+
const helpers_1 = require("./helpers");
|
|
48
|
+
const MAX_UPLOAD_BYTES = 100 * 1024 * 1024;
|
|
49
|
+
/**
|
|
50
|
+
* 判断 src 是本地文件还是远程引用:
|
|
51
|
+
* - src 本地 fs 可访问 → upload(dst 当 remote)
|
|
52
|
+
* - 其他 → download(src 是 /path 或 file_name,由 resolveRemotePath 解析)
|
|
53
|
+
*
|
|
54
|
+
* `cp` 语义要求 src 必须存在;本地不存在就认为用户指向远程。不需要给 dst 猜方向。
|
|
55
|
+
*/
|
|
56
|
+
function isLocalSrc(src) {
|
|
57
|
+
const expanded = expandHome(src);
|
|
58
|
+
try {
|
|
59
|
+
return node_fs_1.default.existsSync(expanded);
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
function expandHome(p) {
|
|
66
|
+
if (p.startsWith("~/"))
|
|
67
|
+
return node_path_1.default.join(node_os_1.default.homedir(), p.slice(2));
|
|
68
|
+
return p;
|
|
69
|
+
}
|
|
70
|
+
function detectMime(filePath) {
|
|
71
|
+
const ext = node_path_1.default.extname(filePath).toLowerCase();
|
|
72
|
+
const map = {
|
|
73
|
+
".png": "image/png",
|
|
74
|
+
".jpg": "image/jpeg",
|
|
75
|
+
".jpeg": "image/jpeg",
|
|
76
|
+
".gif": "image/gif",
|
|
77
|
+
".webp": "image/webp",
|
|
78
|
+
".svg": "image/svg+xml",
|
|
79
|
+
".pdf": "application/pdf",
|
|
80
|
+
".json": "application/json",
|
|
81
|
+
".csv": "text/csv",
|
|
82
|
+
".txt": "text/plain",
|
|
83
|
+
".html": "text/html",
|
|
84
|
+
".zip": "application/zip",
|
|
85
|
+
".tar": "application/x-tar",
|
|
86
|
+
".gz": "application/gzip",
|
|
87
|
+
".mp4": "video/mp4",
|
|
88
|
+
".mp3": "audio/mpeg",
|
|
89
|
+
};
|
|
90
|
+
return map[ext] ?? "application/octet-stream";
|
|
91
|
+
}
|
|
92
|
+
/** 把 src 的远程形式(`/path` / `file_name`)解析成后端 sign 可用的 remote path。 */
|
|
93
|
+
async function resolveRemotePath(appId, input) {
|
|
94
|
+
if (input.startsWith("/"))
|
|
95
|
+
return input;
|
|
96
|
+
const [resolved] = await api.file.resolveInputs({ appId, inputs: [input] });
|
|
97
|
+
if (resolved.status === "error") {
|
|
98
|
+
throw new error_1.AppError(resolved.error.code, resolved.error.message, {
|
|
99
|
+
next_actions: resolved.error.hint ? [resolved.error.hint] : undefined,
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
return resolved.file.path;
|
|
103
|
+
}
|
|
104
|
+
async function handleUpload(appId, localRaw, remoteRaw, rename) {
|
|
105
|
+
const localPath = expandHome(localRaw);
|
|
106
|
+
if (!node_fs_1.default.existsSync(localPath) || !node_fs_1.default.statSync(localPath).isFile()) {
|
|
107
|
+
throw new error_1.AppError("FILE_SRC_NOT_FOUND", `Local file '${localRaw}' does not exist`);
|
|
108
|
+
}
|
|
109
|
+
const stat = node_fs_1.default.statSync(localPath);
|
|
110
|
+
if (stat.size > MAX_UPLOAD_BYTES) {
|
|
111
|
+
throw new error_1.AppError("FILE_SIZE_EXCEEDED", `File size ${(0, helpers_1.formatSize)(stat.size)} exceeds the 100 MB upload limit`, {
|
|
112
|
+
next_actions: [
|
|
113
|
+
"Split the file, or use the web console for large uploads.",
|
|
114
|
+
],
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
const fileName = rename ?? node_path_1.default.basename(localPath);
|
|
118
|
+
let remotePath = remoteRaw;
|
|
119
|
+
if (remoteRaw.endsWith("/")) {
|
|
120
|
+
remotePath = remoteRaw + fileName;
|
|
121
|
+
}
|
|
122
|
+
else if (remoteRaw === "/") {
|
|
123
|
+
remotePath = "/" + fileName;
|
|
124
|
+
}
|
|
125
|
+
const contentType = detectMime(localPath);
|
|
126
|
+
const result = await api.file.uploadFile({
|
|
127
|
+
appId,
|
|
128
|
+
localPath,
|
|
129
|
+
remotePath,
|
|
130
|
+
fileName,
|
|
131
|
+
fileSize: stat.size,
|
|
132
|
+
contentType,
|
|
133
|
+
readFile: async () => node_fs_1.default.promises.readFile(localPath),
|
|
134
|
+
});
|
|
135
|
+
if ((0, output_1.isJsonMode)()) {
|
|
136
|
+
const payload = {
|
|
137
|
+
file_name: result.file_name,
|
|
138
|
+
path: result.path,
|
|
139
|
+
size_bytes: result.size,
|
|
140
|
+
type: result.type,
|
|
141
|
+
};
|
|
142
|
+
if (result.download_url)
|
|
143
|
+
payload.download_url = result.download_url;
|
|
144
|
+
(0, helpers_1.emitOk)(payload);
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
const tty = (0, helpers_1.isStdoutTty)();
|
|
148
|
+
const lines = [];
|
|
149
|
+
if (tty) {
|
|
150
|
+
lines.push(`✓ Uploaded ${node_path_1.default.basename(localPath)} → ${result.path}`);
|
|
151
|
+
lines.push(` file_name: ${result.file_name}`);
|
|
152
|
+
lines.push(` path: ${result.path}`);
|
|
153
|
+
lines.push(` size: ${(0, helpers_1.formatSize)(result.size)} (${String(result.size)} bytes)`);
|
|
154
|
+
lines.push(` type: ${result.type}`);
|
|
155
|
+
if (result.download_url) {
|
|
156
|
+
lines.push(` download_url: ${result.download_url}`);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
lines.push(`OK Uploaded ${node_path_1.default.basename(localPath)} -> ${result.path}`);
|
|
161
|
+
lines.push(`file_name\t${result.file_name}`);
|
|
162
|
+
lines.push(`path\t${result.path}`);
|
|
163
|
+
lines.push(`size\t${String(result.size)}`);
|
|
164
|
+
lines.push(`type\t${result.type}`);
|
|
165
|
+
if (result.download_url) {
|
|
166
|
+
lines.push(`download_url\t${result.download_url}`);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
(0, output_1.emit)(lines.join("\n"));
|
|
170
|
+
}
|
|
171
|
+
async function handleDownload(appId, remoteRaw, localRaw) {
|
|
172
|
+
const filePath = await resolveRemotePath(appId, remoteRaw);
|
|
173
|
+
const sign = await api.file.signDownload({
|
|
174
|
+
appId,
|
|
175
|
+
filePath,
|
|
176
|
+
expiresIn: 300,
|
|
177
|
+
});
|
|
178
|
+
const baseName = node_path_1.default.basename(filePath);
|
|
179
|
+
let localTarget = expandHome(localRaw);
|
|
180
|
+
if (localTarget === "./" || localTarget === "." || localTarget.endsWith("/")) {
|
|
181
|
+
localTarget = node_path_1.default.join(localTarget, baseName);
|
|
182
|
+
}
|
|
183
|
+
else if (node_fs_1.default.existsSync(localTarget) && node_fs_1.default.statSync(localTarget).isDirectory()) {
|
|
184
|
+
localTarget = node_path_1.default.join(localTarget, baseName);
|
|
185
|
+
}
|
|
186
|
+
let writtenBytes = 0;
|
|
187
|
+
await api.file.downloadFile({
|
|
188
|
+
signedURL: sign.signed_url,
|
|
189
|
+
writeFile: async (buf) => {
|
|
190
|
+
await node_fs_1.default.promises.mkdir(node_path_1.default.dirname(node_path_1.default.resolve(localTarget)), {
|
|
191
|
+
recursive: true,
|
|
192
|
+
});
|
|
193
|
+
await node_fs_1.default.promises.writeFile(localTarget, buf);
|
|
194
|
+
writtenBytes = buf.length;
|
|
195
|
+
},
|
|
196
|
+
});
|
|
197
|
+
if ((0, output_1.isJsonMode)()) {
|
|
198
|
+
(0, helpers_1.emitOk)({
|
|
199
|
+
path: filePath,
|
|
200
|
+
local_path: localTarget,
|
|
201
|
+
size: writtenBytes,
|
|
202
|
+
});
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
const tty = (0, helpers_1.isStdoutTty)();
|
|
206
|
+
if (tty) {
|
|
207
|
+
(0, output_1.emit)(`✓ Downloaded ${baseName} → ${localTarget} (${(0, helpers_1.formatSize)(writtenBytes)})`);
|
|
208
|
+
}
|
|
209
|
+
else {
|
|
210
|
+
(0, output_1.emit)(`OK Downloaded ${baseName} -> ${localTarget} (${String(writtenBytes)} bytes)`);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
async function handleFileCp(src, dst, opts) {
|
|
214
|
+
const appId = (0, shared_1.resolveAppId)(opts);
|
|
215
|
+
// src 本地存在 → upload;其他情况(file_ref / `/path` / 裸文件名)→ download
|
|
216
|
+
if (isLocalSrc(src)) {
|
|
217
|
+
return handleUpload(appId, src, dst, opts.rename);
|
|
218
|
+
}
|
|
219
|
+
return handleDownload(appId, src, dst);
|
|
220
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseSize = exports.parseDuration = exports.isStdoutTty = exports.emitPaged = exports.emitOk = exports.renderKeyValue = exports.renderTsv = exports.renderAlignedTable = exports.formatTime = exports.formatSize = void 0;
|
|
4
|
+
// file 域渲染 helpers 已统一迁移至 @/cli/handlers/shared
|
|
5
|
+
// 这里仅做 re-export 保持历史 import 路径稳定(`from "./helpers"` 仍可用)
|
|
6
|
+
var shared_1 = require("../../../cli/handlers/shared");
|
|
7
|
+
Object.defineProperty(exports, "formatSize", { enumerable: true, get: function () { return shared_1.formatSize; } });
|
|
8
|
+
Object.defineProperty(exports, "formatTime", { enumerable: true, get: function () { return shared_1.formatTime; } });
|
|
9
|
+
Object.defineProperty(exports, "renderAlignedTable", { enumerable: true, get: function () { return shared_1.renderAlignedTable; } });
|
|
10
|
+
Object.defineProperty(exports, "renderTsv", { enumerable: true, get: function () { return shared_1.renderTsv; } });
|
|
11
|
+
Object.defineProperty(exports, "renderKeyValue", { enumerable: true, get: function () { return shared_1.renderKeyValue; } });
|
|
12
|
+
Object.defineProperty(exports, "emitOk", { enumerable: true, get: function () { return shared_1.emitOk; } });
|
|
13
|
+
Object.defineProperty(exports, "emitPaged", { enumerable: true, get: function () { return shared_1.emitPaged; } });
|
|
14
|
+
Object.defineProperty(exports, "isStdoutTty", { enumerable: true, get: function () { return shared_1.isStdoutTty; } });
|
|
15
|
+
Object.defineProperty(exports, "parseDuration", { enumerable: true, get: function () { return shared_1.parseDuration; } });
|
|
16
|
+
Object.defineProperty(exports, "parseSize", { enumerable: true, get: function () { return shared_1.parseSize; } });
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.handleFileSign = exports.handleFileRm = exports.handleFileCp = exports.handleFileStat = exports.handleFileLs = void 0;
|
|
4
|
+
var ls_1 = require("./ls");
|
|
5
|
+
Object.defineProperty(exports, "handleFileLs", { enumerable: true, get: function () { return ls_1.handleFileLs; } });
|
|
6
|
+
var stat_1 = require("./stat");
|
|
7
|
+
Object.defineProperty(exports, "handleFileStat", { enumerable: true, get: function () { return stat_1.handleFileStat; } });
|
|
8
|
+
var cp_1 = require("./cp");
|
|
9
|
+
Object.defineProperty(exports, "handleFileCp", { enumerable: true, get: function () { return cp_1.handleFileCp; } });
|
|
10
|
+
var rm_1 = require("./rm");
|
|
11
|
+
Object.defineProperty(exports, "handleFileRm", { enumerable: true, get: function () { return rm_1.handleFileRm; } });
|
|
12
|
+
var sign_1 = require("./sign");
|
|
13
|
+
Object.defineProperty(exports, "handleFileSign", { enumerable: true, get: function () { return sign_1.handleFileSign; } });
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.handleFileLs = handleFileLs;
|
|
37
|
+
const api = __importStar(require("../../../api/index"));
|
|
38
|
+
const output_1 = require("../../../utils/output");
|
|
39
|
+
const error_1 = require("../../../utils/error");
|
|
40
|
+
const shared_1 = require("../../../cli/commands/shared");
|
|
41
|
+
const index_1 = require("../../../api/file/index");
|
|
42
|
+
const helpers_1 = require("./helpers");
|
|
43
|
+
/**
|
|
44
|
+
* 把位置参数 `query` 路由到 `--path` 或 `--name`:
|
|
45
|
+
* - `looksLikePath(query)` → path 精确匹配
|
|
46
|
+
* - 否则 → file_name 精确匹配
|
|
47
|
+
*
|
|
48
|
+
* 显式 `--path` / `--name` 传入时跳过 query 自动识别。
|
|
49
|
+
* 同时传 query 又传 --path/--name 视为歧义,直接报错。
|
|
50
|
+
*/
|
|
51
|
+
function resolveQueryRouting(opts) {
|
|
52
|
+
const explicit = {
|
|
53
|
+
path: opts.path,
|
|
54
|
+
name: opts.name,
|
|
55
|
+
};
|
|
56
|
+
if (!opts.query)
|
|
57
|
+
return explicit;
|
|
58
|
+
if (explicit.path || explicit.name) {
|
|
59
|
+
throw new error_1.AppError("ARGS_INVALID", "Do not mix positional <query> with --path / --name; pick one.");
|
|
60
|
+
}
|
|
61
|
+
if ((0, index_1.looksLikePath)(opts.query)) {
|
|
62
|
+
// 补齐前导 `/`,对齐 ls sidecar 比较逻辑(info.path 永远带前导 `/`)
|
|
63
|
+
return { path: (0, index_1.toAbsolutePath)(opts.query) };
|
|
64
|
+
}
|
|
65
|
+
return { name: opts.query };
|
|
66
|
+
}
|
|
67
|
+
async function handleFileLs(opts) {
|
|
68
|
+
const appId = (0, shared_1.resolveAppId)(opts);
|
|
69
|
+
const limit = opts.limit ? Number(opts.limit) : undefined;
|
|
70
|
+
const sizeGt = opts.sizeGt ? (0, helpers_1.parseSize)(opts.sizeGt) : undefined;
|
|
71
|
+
const sizeLt = opts.sizeLt ? (0, helpers_1.parseSize)(opts.sizeLt) : undefined;
|
|
72
|
+
const { path, name } = resolveQueryRouting(opts);
|
|
73
|
+
const result = await api.file.listFiles({
|
|
74
|
+
appId,
|
|
75
|
+
limit,
|
|
76
|
+
cursor: opts.cursor,
|
|
77
|
+
all: opts.all,
|
|
78
|
+
path,
|
|
79
|
+
name,
|
|
80
|
+
type: opts.type,
|
|
81
|
+
sizeGt,
|
|
82
|
+
sizeLt,
|
|
83
|
+
uploadedSince: opts.uploadedSince,
|
|
84
|
+
});
|
|
85
|
+
if ((0, output_1.isJsonMode)()) {
|
|
86
|
+
(0, helpers_1.emitPaged)(result.items, result.next_cursor, result.has_more);
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
if (result.items.length === 0) {
|
|
90
|
+
(0, output_1.emit)("No files found.");
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
const tty = (0, helpers_1.isStdoutTty)();
|
|
94
|
+
const headers = ["file_name", "path", "size", "type", "uploaded_at"];
|
|
95
|
+
const rows = result.items.map((info) => [
|
|
96
|
+
info.file_name || "—",
|
|
97
|
+
info.path,
|
|
98
|
+
tty ? (0, helpers_1.formatSize)(info.size_bytes) : String(info.size_bytes),
|
|
99
|
+
info.type,
|
|
100
|
+
(0, helpers_1.formatTime)(info.uploaded_at, tty),
|
|
101
|
+
]);
|
|
102
|
+
const table = tty
|
|
103
|
+
? (0, helpers_1.renderAlignedTable)(headers, rows)
|
|
104
|
+
: (0, helpers_1.renderTsv)(headers, rows);
|
|
105
|
+
const hint = result.has_more && result.next_cursor
|
|
106
|
+
? `\n— ${String(result.items.length)} results. Next: --cursor ${result.next_cursor}`
|
|
107
|
+
: "";
|
|
108
|
+
(0, output_1.emit)(table + hint);
|
|
109
|
+
}
|