ossput 0.0.1

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 (72) hide show
  1. package/.cursor/skills/ossput/SKILL.md +87 -0
  2. package/.cursor/skills/ossput/examples.md +59 -0
  3. package/.cursor/skills/ossput/reference.md +78 -0
  4. package/.ossput.json.example +3 -0
  5. package/AGENTS.md +16 -0
  6. package/CHANGELOG.md +25 -0
  7. package/LICENSE +21 -0
  8. package/README.md +173 -0
  9. package/config.index.example.json +8 -0
  10. package/dist/batch-upload.d.ts +28 -0
  11. package/dist/batch-upload.js +34 -0
  12. package/dist/cli.d.ts +1 -0
  13. package/dist/cli.js +253 -0
  14. package/dist/config-profiles.d.ts +45 -0
  15. package/dist/config-profiles.js +282 -0
  16. package/dist/config.d.ts +14 -0
  17. package/dist/config.js +81 -0
  18. package/dist/constants.d.ts +5 -0
  19. package/dist/constants.js +5 -0
  20. package/dist/delete-object.d.ts +6 -0
  21. package/dist/delete-object.js +26 -0
  22. package/dist/doctor.d.ts +9 -0
  23. package/dist/doctor.js +128 -0
  24. package/dist/index.d.ts +2 -0
  25. package/dist/index.js +21 -0
  26. package/dist/key-builder.d.ts +1 -0
  27. package/dist/key-builder.js +13 -0
  28. package/dist/list-directories.d.ts +11 -0
  29. package/dist/list-directories.js +64 -0
  30. package/dist/list-format.d.ts +6 -0
  31. package/dist/list-format.js +57 -0
  32. package/dist/list-objects.d.ts +7 -0
  33. package/dist/list-objects.js +47 -0
  34. package/dist/mcp-annotations.d.ts +16 -0
  35. package/dist/mcp-annotations.js +16 -0
  36. package/dist/mcp-result.d.ts +14 -0
  37. package/dist/mcp-result.js +57 -0
  38. package/dist/mcp.d.ts +4 -0
  39. package/dist/mcp.js +244 -0
  40. package/dist/object-key.d.ts +10 -0
  41. package/dist/object-key.js +46 -0
  42. package/dist/oss-client.d.ts +4 -0
  43. package/dist/oss-client.js +24 -0
  44. package/dist/profile-cli.d.ts +16 -0
  45. package/dist/profile-cli.js +191 -0
  46. package/dist/setup/connectivity.d.ts +2 -0
  47. package/dist/setup/connectivity.js +5 -0
  48. package/dist/setup/logo.d.ts +1 -0
  49. package/dist/setup/logo.js +30 -0
  50. package/dist/setup/mcp-registry.d.ts +17 -0
  51. package/dist/setup/mcp-registry.js +128 -0
  52. package/dist/setup/prompts.d.ts +24 -0
  53. package/dist/setup/prompts.js +410 -0
  54. package/dist/setup/run-setup.d.ts +9 -0
  55. package/dist/setup/run-setup.js +156 -0
  56. package/dist/setup/skill-install.d.ts +19 -0
  57. package/dist/setup/skill-install.js +85 -0
  58. package/dist/setup/ui.d.ts +49 -0
  59. package/dist/setup/ui.js +164 -0
  60. package/dist/setup/write-config.d.ts +5 -0
  61. package/dist/setup/write-config.js +5 -0
  62. package/dist/skill-cli.d.ts +6 -0
  63. package/dist/skill-cli.js +34 -0
  64. package/dist/types.d.ts +82 -0
  65. package/dist/types.js +1 -0
  66. package/dist/upload-pipeline.d.ts +7 -0
  67. package/dist/upload-pipeline.js +96 -0
  68. package/dist/validators.d.ts +10 -0
  69. package/dist/validators.js +77 -0
  70. package/docs/ram-policy.example.json +31 -0
  71. package/package.json +59 -0
  72. package/profiles.example/default.json +21 -0
@@ -0,0 +1,156 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { confirm } from "@inquirer/prompts";
3
+ import { parseConfig } from "../config.js";
4
+ import { indexExists, profileFilePath, writeProjectBinding, } from "../config-profiles.js";
5
+ import { testConnectivity } from "./connectivity.js";
6
+ import { buildMcpServerEntry, formatMergeAction, getPackageVersion, MCP_CLIENTS, mergeMcpConfig, readOurMcpEntry, MCP_SERVER_NAME, } from "./mcp-registry.js";
7
+ import { promptOverwriteExisting, runInteractiveSetup, } from "./prompts.js";
8
+ import { writeProfileConfig } from "./write-config.js";
9
+ import { installAgentSkills } from "./skill-install.js";
10
+ import { printConfigSummary, printError, printSuccessFooter, printWarn, ui, withSpinner, } from "./ui.js";
11
+ const SERVER_NAME = MCP_SERVER_NAME;
12
+ export async function runSetup(options = {}) {
13
+ let profileName;
14
+ let profileLabel;
15
+ let config;
16
+ let clientIds;
17
+ let skippedOssConfig = false;
18
+ let bindProject = false;
19
+ if (options.nonInteractive && options.configPath) {
20
+ const raw = JSON.parse(await readFile(options.configPath, "utf8"));
21
+ config = parseConfig(raw);
22
+ profileName = options.profileName?.trim() || "default";
23
+ clientIds = options.clientIds ?? MCP_CLIENTS.map((c) => c.id);
24
+ const path = await writeProfileConfig(profileName, config, {
25
+ setDefault: true,
26
+ });
27
+ console.log(ui.dim(`正在写入 → ${path}`));
28
+ console.log(ui.green(`✓ 配置已保存`));
29
+ }
30
+ else if (options.nonInteractive) {
31
+ throw new Error("--non-interactive 需要同时指定 --config <配置文件路径>");
32
+ }
33
+ else {
34
+ const interactive = await runInteractiveSetup();
35
+ profileName = interactive.profileName;
36
+ profileLabel = interactive.profileLabel;
37
+ config = interactive.config;
38
+ clientIds = interactive.clientIds;
39
+ skippedOssConfig = interactive.skippedOssConfig;
40
+ bindProject = interactive.bindProject;
41
+ if (!skippedOssConfig) {
42
+ const path = profileFilePath(profileName);
43
+ printConfigSummary(config, path, profileLabel ? { name: profileName, label: profileLabel } : { name: profileName });
44
+ const saveOk = await confirm({
45
+ message: "确认保存以上配置?",
46
+ default: true,
47
+ });
48
+ if (!saveOk) {
49
+ console.log(ui.dim("\n 已取消。\n"));
50
+ process.exit(0);
51
+ }
52
+ const hadIndex = await indexExists();
53
+ await writeProfileConfig(profileName, config, {
54
+ label: profileLabel,
55
+ setDefault: !hadIndex,
56
+ });
57
+ console.log(ui.green(`\n ✓ 账号已保存(权限 600)`));
58
+ console.log(ui.dim(` ${path}\n`));
59
+ }
60
+ }
61
+ if (!options.skipConnectivity && !skippedOssConfig) {
62
+ try {
63
+ await withSpinner("正在检测 OSS 连通性", async () => {
64
+ await testConnectivity(config);
65
+ });
66
+ console.log(ui.green(" ✓ Bucket 连通性正常,凭证有效"));
67
+ }
68
+ catch (err) {
69
+ const msg = err instanceof Error ? err.message : String(err);
70
+ printWarn(`OSS 连通性检测未通过:${msg}`);
71
+ printWarn("配置已保存,请检查 Region / Bucket / 密钥 / 网络后重试上传。");
72
+ const cont = options.nonInteractive
73
+ ? true
74
+ : await confirm({
75
+ message: "是否仍继续写入 MCP 配置?",
76
+ default: true,
77
+ });
78
+ if (!cont) {
79
+ console.log(ui.dim("\n 已中止。\n"));
80
+ process.exit(1);
81
+ }
82
+ }
83
+ }
84
+ else if (skippedOssConfig) {
85
+ printWarn("已跳过 OSS 连通性检测。");
86
+ }
87
+ if (bindProject) {
88
+ const p = await writeProjectBinding(profileName);
89
+ console.log(ui.green(` ✓ 已写入 ${p}`));
90
+ }
91
+ const version = await getPackageVersion();
92
+ const entry = buildMcpServerEntry(version);
93
+ const mergedClients = [];
94
+ console.log("");
95
+ console.log(ui.bold(" 正在注册 MCP 客户端…"));
96
+ for (const id of clientIds) {
97
+ const client = MCP_CLIENTS.find((c) => c.id === id);
98
+ if (!client) {
99
+ printWarn(`未知客户端:${id}`);
100
+ continue;
101
+ }
102
+ const mcpPath = client.resolveConfigPath();
103
+ if (!mcpPath) {
104
+ printWarn(`${client.displayName}:当前系统无默认配置路径,请手动添加。`);
105
+ continue;
106
+ }
107
+ try {
108
+ const existing = await readOurMcpEntry(mcpPath);
109
+ let force = true;
110
+ if (existing != null) {
111
+ const same = JSON.stringify(existing) === JSON.stringify(entry);
112
+ if (!same && !options.nonInteractive) {
113
+ force = await promptOverwriteExisting(client.displayName);
114
+ if (!force) {
115
+ printWarn(`${client.displayName}:保留原有 MCP 条目,未修改。`);
116
+ mergedClients.push({
117
+ name: client.displayName,
118
+ path: mcpPath,
119
+ action: "已跳过",
120
+ });
121
+ continue;
122
+ }
123
+ }
124
+ }
125
+ const result = await mergeMcpConfig(mcpPath, SERVER_NAME, entry, {
126
+ force,
127
+ });
128
+ mergedClients.push({
129
+ name: client.displayName,
130
+ path: mcpPath,
131
+ action: formatMergeAction(result),
132
+ });
133
+ }
134
+ catch (err) {
135
+ const msg = err instanceof Error ? err.message : String(err);
136
+ printError(`${client.displayName}:${msg}`);
137
+ }
138
+ }
139
+ let skillResults = [];
140
+ if (!options.skipSkillInstall) {
141
+ console.log("");
142
+ console.log(ui.bold(" 正在安装 Agent Skill(用户级,无需复制到项目)…"));
143
+ try {
144
+ skillResults = await installAgentSkills();
145
+ for (const r of skillResults) {
146
+ console.log(ui.dim(` ${r.target.displayName} → ${r.action}`));
147
+ }
148
+ }
149
+ catch (err) {
150
+ const msg = err instanceof Error ? err.message : String(err);
151
+ printWarn(`Agent Skill 安装失败:${msg}`);
152
+ printWarn("可稍后执行:ossput skill install");
153
+ }
154
+ }
155
+ printSuccessFooter(mergedClients, profileName, skillResults);
156
+ }
@@ -0,0 +1,19 @@
1
+ export declare const SKILL_NAME = "ossput";
2
+ export type SkillTargetId = "cursor" | "claude";
3
+ export interface SkillTarget {
4
+ id: SkillTargetId;
5
+ displayName: string;
6
+ resolvePath: () => string;
7
+ }
8
+ export declare const SKILL_TARGETS: SkillTarget[];
9
+ /** npm 包内 `.cursor/skills/ossput` 的绝对路径 */
10
+ export declare function resolveBundledSkillDir(): string;
11
+ export interface SkillInstallResult {
12
+ target: SkillTarget;
13
+ dest: string;
14
+ action: string;
15
+ }
16
+ export declare function installSkillToTarget(target: SkillTarget, options?: {
17
+ preferSymlink?: boolean;
18
+ }): Promise<SkillInstallResult>;
19
+ export declare function installAgentSkills(targetIds?: SkillTargetId[]): Promise<SkillInstallResult[]>;
@@ -0,0 +1,85 @@
1
+ import { access, cp, lstat, mkdir, readlink, rm, symlink } from "node:fs/promises";
2
+ import { homedir } from "node:os";
3
+ import { dirname, join, resolve } from "node:path";
4
+ import { constants } from "node:fs";
5
+ import { fileURLToPath } from "node:url";
6
+ export const SKILL_NAME = "ossput";
7
+ export const SKILL_TARGETS = [
8
+ {
9
+ id: "cursor",
10
+ displayName: "Cursor(用户级)",
11
+ resolvePath: () => join(homedir(), ".cursor", "skills", SKILL_NAME),
12
+ },
13
+ {
14
+ id: "claude",
15
+ displayName: "Claude Code(用户级)",
16
+ resolvePath: () => join(homedir(), ".claude", "skills", SKILL_NAME),
17
+ },
18
+ ];
19
+ /** npm 包内 `.cursor/skills/ossput` 的绝对路径 */
20
+ export function resolveBundledSkillDir() {
21
+ const here = dirname(fileURLToPath(import.meta.url));
22
+ return join(here, "..", "..", ".cursor", "skills", SKILL_NAME);
23
+ }
24
+ async function pathExists(path) {
25
+ try {
26
+ await access(path, constants.F_OK);
27
+ return true;
28
+ }
29
+ catch {
30
+ return false;
31
+ }
32
+ }
33
+ async function sameSymlinkTarget(linkPath, expectedSrc) {
34
+ try {
35
+ const st = await lstat(linkPath);
36
+ if (!st.isSymbolicLink())
37
+ return false;
38
+ const raw = await readlink(linkPath);
39
+ return resolve(dirname(linkPath), raw) === resolve(expectedSrc);
40
+ }
41
+ catch {
42
+ return false;
43
+ }
44
+ }
45
+ export async function installSkillToTarget(target, options) {
46
+ const src = resolve(resolveBundledSkillDir());
47
+ const dest = target.resolvePath();
48
+ try {
49
+ await access(src, constants.R_OK);
50
+ }
51
+ catch {
52
+ throw new Error(`找不到内置 Skill:${src}`);
53
+ }
54
+ if (await sameSymlinkTarget(dest, src)) {
55
+ return { target, dest, action: "已链接(无需更新)" };
56
+ }
57
+ if (await pathExists(dest)) {
58
+ await rm(dest, { recursive: true, force: true });
59
+ }
60
+ await mkdir(dirname(dest), { recursive: true });
61
+ const preferSymlink = options?.preferSymlink !== false;
62
+ if (preferSymlink) {
63
+ try {
64
+ const type = process.platform === "win32" ? "junction" : "dir";
65
+ await symlink(src, dest, type);
66
+ return { target, dest, action: "已创建符号链接" };
67
+ }
68
+ catch {
69
+ /* fall through to copy */
70
+ }
71
+ }
72
+ await cp(src, dest, { recursive: true });
73
+ return { target, dest, action: "已复制(符号链接不可用)" };
74
+ }
75
+ export async function installAgentSkills(targetIds) {
76
+ const ids = targetIds ?? SKILL_TARGETS.map((t) => t.id);
77
+ const results = [];
78
+ for (const id of ids) {
79
+ const target = SKILL_TARGETS.find((t) => t.id === id);
80
+ if (!target)
81
+ continue;
82
+ results.push(await installSkillToTarget(target));
83
+ }
84
+ return results;
85
+ }
@@ -0,0 +1,49 @@
1
+ export declare const ui: {
2
+ bold: (t: string) => string;
3
+ dim: (t: string) => string;
4
+ green: (t: string) => string;
5
+ yellow: (t: string) => string;
6
+ cyan: (t: string) => string;
7
+ red: (t: string) => string;
8
+ };
9
+ export declare function line(text?: string): void;
10
+ /** 统一 inquirer 前缀,避免默认 `?` 与正文脱节 */
11
+ export declare const inquirerTheme: {
12
+ style: {
13
+ answer: (text: string) => string;
14
+ highlight: (text: string) => string;
15
+ description: (text: string) => string;
16
+ };
17
+ prefix: string;
18
+ };
19
+ export declare function printWelcome(version: string): void;
20
+ export declare function printStep(current: number, total: number, title: string): void;
21
+ export declare function printBlock(title: string): void;
22
+ export declare function maskSecret(value: string, visible?: number): string;
23
+ export declare function printConfigSummary(config: {
24
+ region: string;
25
+ bucket: string;
26
+ prefix: string;
27
+ accessKeyId: string;
28
+ endpoint?: string | null;
29
+ presignExpiresSec: number;
30
+ allowedExtensions: string[];
31
+ }, configPath: string, profile?: {
32
+ name: string;
33
+ label?: string;
34
+ }): void;
35
+ export declare function withSpinner<T>(label: string, fn: () => Promise<T>): Promise<T>;
36
+ export declare function printSuccessFooter(clients: {
37
+ name: string;
38
+ path: string;
39
+ action: string;
40
+ }[], activeProfile?: string, skills?: {
41
+ target: {
42
+ displayName: string;
43
+ };
44
+ dest: string;
45
+ action: string;
46
+ }[]): void;
47
+ export declare function printHint(message: string): void;
48
+ export declare function printWarn(message: string): void;
49
+ export declare function printError(message: string): void;
@@ -0,0 +1,164 @@
1
+ const supportsColor = process.stdout.isTTY && process.env.NO_COLOR !== "1" && process.env.TERM !== "dumb";
2
+ function c(code, text) {
3
+ return supportsColor ? `\x1b[${code}m${text}\x1b[0m` : text;
4
+ }
5
+ export const ui = {
6
+ bold: (t) => c("1", t),
7
+ dim: (t) => c("2", t),
8
+ green: (t) => c("32", t),
9
+ yellow: (t) => c("33", t),
10
+ cyan: (t) => c("36", t),
11
+ red: (t) => c("31", t),
12
+ };
13
+ const MARGIN = " ";
14
+ export function line(text = "") {
15
+ console.log(MARGIN + text);
16
+ }
17
+ function rule(char = "─", width = 44) {
18
+ line(ui.dim(char.repeat(width)));
19
+ }
20
+ import { printAsciiLogo } from "./logo.js";
21
+ /** 统一 inquirer 前缀,避免默认 `?` 与正文脱节 */
22
+ export const inquirerTheme = {
23
+ style: {
24
+ answer: (text) => ui.green(text),
25
+ highlight: (text) => ui.cyan(text),
26
+ description: (text) => ui.dim(text),
27
+ },
28
+ prefix: supportsColor ? c("36", "›") : ">",
29
+ };
30
+ export function printWelcome(version) {
31
+ printAsciiLogo(version);
32
+ rule("═");
33
+ line(ui.bold("安装向导"));
34
+ line(ui.dim("阿里云 OSS 直传 · 一键配置 MCP"));
35
+ rule("═");
36
+ console.log("");
37
+ line(ui.dim("将依次完成:"));
38
+ bullet("创建本机账号配置(profiles/,密钥不会写入 mcp.json)");
39
+ bullet("注册 Cursor / Claude Desktop 等 MCP 客户端");
40
+ bullet("检测与 Bucket 的连通性");
41
+ console.log("");
42
+ line(ui.dim("请在下方终端输入 AccessKey,勿粘贴到 AI 对话中。"));
43
+ console.log("");
44
+ }
45
+ function bullet(text) {
46
+ line(`${ui.dim("·")} ${text}`);
47
+ }
48
+ function numbered(n, text) {
49
+ line(`${ui.dim(String(n).padStart(2))} ${text}`);
50
+ }
51
+ export function printStep(current, total, title) {
52
+ console.log("");
53
+ rule();
54
+ line(ui.dim(`[${current}/${total}]`) + " " + ui.bold(title));
55
+ rule();
56
+ console.log("");
57
+ }
58
+ export function printBlock(title) {
59
+ console.log("");
60
+ line(ui.bold(title));
61
+ }
62
+ export function maskSecret(value, visible = 4) {
63
+ if (value.length <= visible)
64
+ return "****";
65
+ return `${value.slice(0, visible)}${"*".repeat(Math.min(12, value.length - visible))}`;
66
+ }
67
+ export function printConfigSummary(config, configPath, profile) {
68
+ printBlock("确认配置");
69
+ console.log("");
70
+ const rows = [
71
+ ...(profile
72
+ ? [
73
+ [
74
+ "Profile",
75
+ profile.label ? `${profile.name}(${profile.label})` : profile.name,
76
+ ],
77
+ ]
78
+ : []),
79
+ ["Region", config.region],
80
+ ["Bucket", config.bucket],
81
+ ["Prefix", config.prefix ? config.prefix : "/ (根目录)"],
82
+ ["AccessKey ID", maskSecret(config.accessKeyId, 6)],
83
+ ["URL expires", `${config.presignExpiresSec}s`],
84
+ ["Endpoint", config.endpoint || ui.dim("(default public)")],
85
+ ["Extensions", config.allowedExtensions.join(", ")],
86
+ ["Config file", configPath],
87
+ ];
88
+ for (const [k, v] of rows) {
89
+ line(`${ui.dim(pad(k, 12))} ${v}`);
90
+ }
91
+ console.log("");
92
+ }
93
+ function pad(s, n) {
94
+ const w = [...s].reduce((a, ch) => a + (ch.charCodeAt(0) > 127 ? 2 : 1), 0);
95
+ return s + " ".repeat(Math.max(0, n - w));
96
+ }
97
+ export async function withSpinner(label, fn) {
98
+ if (!process.stdout.isTTY) {
99
+ line(ui.dim(`${label}...`));
100
+ return fn();
101
+ }
102
+ const frames = ["-", "\\", "|", "/"];
103
+ let i = 0;
104
+ const timer = setInterval(() => {
105
+ process.stdout.write(`\r${MARGIN}${ui.cyan(frames[i++ % frames.length])} ${label}...`);
106
+ }, 120);
107
+ try {
108
+ return await fn();
109
+ }
110
+ finally {
111
+ clearInterval(timer);
112
+ process.stdout.write("\r\x1b[K");
113
+ }
114
+ }
115
+ export function printSuccessFooter(clients, activeProfile, skills = []) {
116
+ console.log("");
117
+ rule("═");
118
+ line(ui.green(ui.bold("安装完成")));
119
+ rule("═");
120
+ console.log("");
121
+ if (clients.length > 0) {
122
+ line(ui.bold("MCP 配置"));
123
+ for (const cl of clients) {
124
+ line(` ${ui.dim("·")} ${cl.name} ${ui.dim(`(${cl.action})`)}`);
125
+ line(ui.dim(` ${cl.path}`));
126
+ }
127
+ console.log("");
128
+ }
129
+ if (skills.length > 0) {
130
+ line(ui.bold("Agent Skill(用户级)"));
131
+ for (const sk of skills) {
132
+ line(` ${ui.dim("·")} ${sk.target.displayName} ${ui.dim(`(${sk.action})`)}`);
133
+ line(ui.dim(` ${sk.dest}`));
134
+ }
135
+ console.log("");
136
+ }
137
+ line(ui.bold("接下来"));
138
+ numbered(1, "完全退出并重新打开 Cursor / Claude Desktop / Claude Code");
139
+ numbered(2, "设置 → MCP → 确认 " + ui.bold("ossput") + " 已连接");
140
+ if (skills.length > 0) {
141
+ numbered(3, "新开 Agent 会话;Skill 已写入本机目录,无需复制到项目");
142
+ }
143
+ const n = skills.length > 0 ? 4 : 3;
144
+ if (activeProfile) {
145
+ numbered(n, `本仓库 profile: ${ui.bold(activeProfile)}(见 .ossput.json)`);
146
+ numbered(n + 1, "对 Agent 说:把 ./file.png 上传到 OSS,目录 demo/test");
147
+ }
148
+ else {
149
+ numbered(n, "对 Agent 说:把 ./file.png 上传到 OSS,目录 demo/test");
150
+ }
151
+ console.log("");
152
+ line(ui.dim("命令行:npx ossput put ./file.png --subdir demo/test"));
153
+ console.log("");
154
+ }
155
+ export function printHint(message) {
156
+ console.log("");
157
+ line(ui.dim(`提示:${message}`));
158
+ }
159
+ export function printWarn(message) {
160
+ line(ui.yellow(`注意:${message}`));
161
+ }
162
+ export function printError(message) {
163
+ line(ui.red(`错误:${message}`));
164
+ }
@@ -0,0 +1,5 @@
1
+ import type { AppConfig } from "../types.js";
2
+ export declare function writeProfileConfig(name: string, config: AppConfig, options?: {
3
+ label?: string;
4
+ setDefault?: boolean;
5
+ }): Promise<string>;
@@ -0,0 +1,5 @@
1
+ import { profileFilePath, saveProfile, } from "../config-profiles.js";
2
+ export async function writeProfileConfig(name, config, options) {
3
+ await saveProfile(name, config, options);
4
+ return profileFilePath(name);
5
+ }
@@ -0,0 +1,6 @@
1
+ import { type SkillTargetId } from "./setup/skill-install.js";
2
+ export interface SkillInstallOptions {
3
+ targets?: SkillTargetId[];
4
+ }
5
+ export declare function runSkillInstall(options?: SkillInstallOptions): Promise<void>;
6
+ export declare function runSkillCommand(sub: string, _rest: string[], flags: Record<string, string | boolean>): Promise<number>;
@@ -0,0 +1,34 @@
1
+ import { installAgentSkills } from "./setup/skill-install.js";
2
+ import { ui } from "./setup/ui.js";
3
+ export async function runSkillInstall(options = {}) {
4
+ const results = await installAgentSkills(options.targets);
5
+ for (const r of results) {
6
+ console.log(ui.green(`✓ ${r.target.displayName}`) +
7
+ ui.dim(` — ${r.action}`) +
8
+ `\n ${r.dest}`);
9
+ }
10
+ console.log("");
11
+ console.log(ui.dim("新开 Agent 会话后 Skill 生效;Claude Code 可用 /ossput 调用。"));
12
+ }
13
+ export async function runSkillCommand(sub, _rest, flags) {
14
+ switch (sub) {
15
+ case "install": {
16
+ let targets;
17
+ if (flags.cursor === true) {
18
+ targets = [...(targets ?? []), "cursor"];
19
+ }
20
+ if (flags.claude === true) {
21
+ targets = [...(targets ?? []), "claude"];
22
+ }
23
+ await runSkillInstall({ targets });
24
+ return 0;
25
+ }
26
+ default:
27
+ console.error(`Unknown skill command: ${sub || "(none)"}`);
28
+ console.log(`Usage:
29
+ ossput skill install 安装到 ~/.cursor/skills 与 ~/.claude/skills
30
+ ossput skill install --cursor 仅 Cursor
31
+ ossput skill install --claude 仅 Claude Code`);
32
+ return 1;
33
+ }
34
+ }
@@ -0,0 +1,82 @@
1
+ export interface AppConfig {
2
+ region: string;
3
+ bucket: string;
4
+ prefix: string;
5
+ accessKeyId: string;
6
+ accessKeySecret: string;
7
+ presignExpiresSec: number;
8
+ allowedExtensions: string[];
9
+ endpoint?: string | null;
10
+ /** 公网访问根 URL,如 https://cdn.example.com(无尾斜杠) */
11
+ publicBaseUrl?: string | null;
12
+ /** 是否允许 delete_object(默认 false,须在 profile 中显式开启) */
13
+ allowDelete?: boolean;
14
+ }
15
+ export interface OssputIndexConfig {
16
+ version: 1;
17
+ defaultProfile: string;
18
+ profiles: Record<string, {
19
+ label?: string;
20
+ }>;
21
+ }
22
+ export interface ProjectBinding {
23
+ profile: string;
24
+ }
25
+ export type ProfileBindingSource = "arg" | "env" | "project" | "default";
26
+ export interface ResolvedProfile {
27
+ name: string;
28
+ source: ProfileBindingSource;
29
+ projectFile?: string;
30
+ }
31
+ export interface PrepareUploadResult {
32
+ bucket: string;
33
+ objectKey: string;
34
+ uploadUrl: string;
35
+ method: "PUT";
36
+ headers: Record<string, string>;
37
+ expiresAt: string;
38
+ maxSizeBytes: number;
39
+ }
40
+ export interface ConfirmUploadResult {
41
+ exists: boolean;
42
+ size: number;
43
+ etag?: string;
44
+ objectUrl: string;
45
+ lastModified?: string;
46
+ }
47
+ export interface UploadFileResult extends ConfirmUploadResult {
48
+ objectKey: string;
49
+ }
50
+ export interface OssObjectInfo {
51
+ objectKey: string;
52
+ size: number;
53
+ lastModified: string;
54
+ objectUrl: string;
55
+ }
56
+ export interface ListObjectsResult {
57
+ prefix: string;
58
+ count: number;
59
+ objects: OssObjectInfo[];
60
+ truncated: boolean;
61
+ }
62
+ export declare const MAX_FILE_BYTES: number;
63
+ export interface DeleteObjectResult {
64
+ objectKey: string;
65
+ deleted: boolean;
66
+ objectUrl: string;
67
+ }
68
+ export interface BatchUploadResult {
69
+ subdir: string;
70
+ total: number;
71
+ succeeded: number;
72
+ failed: number;
73
+ results: Array<{
74
+ localPath: string;
75
+ ok: true;
76
+ result: UploadFileResult;
77
+ } | {
78
+ localPath: string;
79
+ ok: false;
80
+ error: string;
81
+ }>;
82
+ }
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ export const MAX_FILE_BYTES = 100 * 1024 * 1024;
@@ -0,0 +1,7 @@
1
+ import type { AppConfig } from "./types.js";
2
+ import type { ConfirmUploadResult, PrepareUploadResult, UploadFileResult } from "./types.js";
3
+ export declare function prepareUpload(config: AppConfig, filename: string, contentType: string, subdir?: string, overwrite?: boolean): Promise<PrepareUploadResult>;
4
+ /** Presigned PUT via Node fetch (no external curl). */
5
+ export declare function putPresignedFile(uploadUrl: string, filePath: string, contentType: string): Promise<void>;
6
+ export declare function confirmUpload(config: AppConfig, objectKey: string, expectedSizeBytes?: number): Promise<ConfirmUploadResult>;
7
+ export declare function uploadFile(config: AppConfig, localPath: string, subdir?: string, contentType?: string): Promise<UploadFileResult>;