@skylandnpm/octopus-cli 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.
- package/bin/octopus.js +2 -0
- package/dist/commands/attachments.js +94 -0
- package/dist/commands/config.js +54 -0
- package/dist/commands/tasks.js +225 -0
- package/dist/commands/todos.js +120 -0
- package/dist/config.js +37 -0
- package/dist/index.js +13 -0
- package/package.json +33 -0
package/bin/octopus.js
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { getClient } from "../config.js";
|
|
2
|
+
import axios from "axios";
|
|
3
|
+
import { createWriteStream, createReadStream } from "fs";
|
|
4
|
+
export function registerAttachmentsCommands(program) {
|
|
5
|
+
const attachmentsCmd = program
|
|
6
|
+
.command("attachments")
|
|
7
|
+
.description("附件相关命令");
|
|
8
|
+
// attachments download
|
|
9
|
+
attachmentsCmd
|
|
10
|
+
.command("download")
|
|
11
|
+
.description("下载任务附件")
|
|
12
|
+
.requiredOption("--project-no <number>", "项目编号", parseInt)
|
|
13
|
+
.requiredOption("--attachment-id <id>", "附件ID")
|
|
14
|
+
.option("--output <path>", "下载保存路径")
|
|
15
|
+
.action(async (opts) => {
|
|
16
|
+
try {
|
|
17
|
+
const client = getClient();
|
|
18
|
+
const res = await client.get(`/api/open/tasks/attachments/${opts.attachmentId}/download?projectNo=${opts.projectNo}`);
|
|
19
|
+
if (res.data.success) {
|
|
20
|
+
const { fileName, fileUrl } = res.data.data;
|
|
21
|
+
const outputPath = opts.output || fileName;
|
|
22
|
+
console.log(`正在下载: ${fileName}`);
|
|
23
|
+
const fileRes = await axios.get(fileUrl, { responseType: "stream" });
|
|
24
|
+
const writer = createWriteStream(outputPath);
|
|
25
|
+
fileRes.data.pipe(writer);
|
|
26
|
+
writer.on("finish", () => {
|
|
27
|
+
console.log(`已保存到: ${outputPath}`);
|
|
28
|
+
});
|
|
29
|
+
writer.on("error", (err) => {
|
|
30
|
+
console.error("保存失败:", err.message);
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
console.error("请求失败:", res.data.message);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
catch (err) {
|
|
38
|
+
console.error("请求失败:", err.response?.data?.message || err.message);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
// logs 子命令
|
|
42
|
+
const logsCmd = program.command("logs").description("任务流水记录附件命令");
|
|
43
|
+
logsCmd
|
|
44
|
+
.command("upload")
|
|
45
|
+
.description("上传流水记录附件")
|
|
46
|
+
.requiredOption("--log-id <logId>", "流水记录ID")
|
|
47
|
+
.requiredOption("--project-no <number>", "项目编号", parseInt)
|
|
48
|
+
.requiredOption("--file <path>", "附件文件路径")
|
|
49
|
+
.action(async (opts) => {
|
|
50
|
+
try {
|
|
51
|
+
const client = getClient();
|
|
52
|
+
const FormData = (await import("form-data")).default;
|
|
53
|
+
const form = new FormData();
|
|
54
|
+
form.append("projectNo", opts.projectNo);
|
|
55
|
+
form.append("file", createReadStream(opts.file));
|
|
56
|
+
const res = await axios.post(`${client.defaults.baseURL}/api/open/task-logs/attachments/${opts.logId}`, form, {
|
|
57
|
+
headers: {
|
|
58
|
+
...client.defaults.headers.common,
|
|
59
|
+
"Content-Type": "multipart/form-data",
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
if (res.data.success) {
|
|
63
|
+
console.log("附件上传成功");
|
|
64
|
+
console.log(JSON.stringify(res.data.data, null, 2));
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
console.error("请求失败:", res.data.message);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
catch (err) {
|
|
71
|
+
console.error("请求失败:", err.response?.data?.message || err.message);
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
logsCmd
|
|
75
|
+
.command("attachments")
|
|
76
|
+
.description("获取流水记录附件列表")
|
|
77
|
+
.requiredOption("--log-id <logId>", "流水记录ID")
|
|
78
|
+
.requiredOption("--project-no <number>", "项目编号", parseInt)
|
|
79
|
+
.action(async (opts) => {
|
|
80
|
+
try {
|
|
81
|
+
const client = getClient();
|
|
82
|
+
const res = await client.post(`/api/open/task-logs/attachments/${opts.logId}/list`, { projectNo: opts.projectNo });
|
|
83
|
+
if (res.data.success) {
|
|
84
|
+
console.log(JSON.stringify(res.data.data, null, 2));
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
console.error("请求失败:", res.data.message);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
catch (err) {
|
|
91
|
+
console.error("请求失败:", err.response?.data?.message || err.message);
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { loadConfig, saveConfig } from "../config.js";
|
|
2
|
+
const KEY_MAP = {
|
|
3
|
+
baseUrl: "OCTOPUS_BASE_URL",
|
|
4
|
+
token: "OCTOPUS_ACCESS_TOKEN",
|
|
5
|
+
};
|
|
6
|
+
export function registerConfigCommands(program) {
|
|
7
|
+
const configCmd = program.command("config").description("配置管理");
|
|
8
|
+
configCmd
|
|
9
|
+
.command("get")
|
|
10
|
+
.description("查看当前配置")
|
|
11
|
+
.action(() => {
|
|
12
|
+
const config = loadConfig();
|
|
13
|
+
const baseUrl = config.env?.OCTOPUS_BASE_URL || "(未设置)";
|
|
14
|
+
const token = config.env?.OCTOPUS_ACCESS_TOKEN
|
|
15
|
+
? "********" + config.env.OCTOPUS_ACCESS_TOKEN.slice(-10)
|
|
16
|
+
: "(未设置)";
|
|
17
|
+
console.log(`baseUrl: ${baseUrl}`);
|
|
18
|
+
console.log(`token: ${token}`);
|
|
19
|
+
});
|
|
20
|
+
configCmd
|
|
21
|
+
.command("set <key> <value>")
|
|
22
|
+
.description("设置配置项 (baseUrl | token)")
|
|
23
|
+
.action((key, value) => {
|
|
24
|
+
if (key !== "baseUrl" && key !== "token") {
|
|
25
|
+
console.log("仅支持设置 baseUrl 或 token");
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const config = loadConfig();
|
|
29
|
+
config.env = config.env || {};
|
|
30
|
+
const finalValue = key === "baseUrl" ? value.replace(/\/+$/, "") : value;
|
|
31
|
+
config.env[KEY_MAP[key]] =
|
|
32
|
+
finalValue;
|
|
33
|
+
saveConfig(config);
|
|
34
|
+
console.log(`已设置 ${key},保存到 ~/.octopus/settings.json`);
|
|
35
|
+
});
|
|
36
|
+
configCmd
|
|
37
|
+
.command("delete <key>")
|
|
38
|
+
.description("删除配置项 (baseUrl | token)")
|
|
39
|
+
.action((key) => {
|
|
40
|
+
if (key !== "baseUrl" && key !== "token") {
|
|
41
|
+
console.log("仅支持删除 baseUrl 或 token");
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
const config = loadConfig();
|
|
45
|
+
const envKey = KEY_MAP[key];
|
|
46
|
+
if (!config.env?.[envKey]) {
|
|
47
|
+
console.log(`配置项 ${key} 不存在`);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
delete config.env[envKey];
|
|
51
|
+
saveConfig(config);
|
|
52
|
+
console.log(`已删除配置项 ${key},保存到 ~/.octopus/settings.json`);
|
|
53
|
+
});
|
|
54
|
+
}
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import { getClient } from "../config.js";
|
|
2
|
+
export function registerTasksCommands(program) {
|
|
3
|
+
const tasksCmd = program.command("tasks").description("任务相关命令");
|
|
4
|
+
// tasks list
|
|
5
|
+
tasksCmd
|
|
6
|
+
.command("list")
|
|
7
|
+
.description("获取任务列表")
|
|
8
|
+
.requiredOption("--project-no <number>", "项目编号", parseInt)
|
|
9
|
+
.requiredOption("--email <email>", "用户邮箱")
|
|
10
|
+
.option("--status <status>", "任务状态筛选: not_started, in_progress, completed, error, closed")
|
|
11
|
+
.action(async (opts) => {
|
|
12
|
+
try {
|
|
13
|
+
const client = getClient();
|
|
14
|
+
const res = await client.post("/api/open/tasks/list", {
|
|
15
|
+
projectNo: opts.projectNo,
|
|
16
|
+
email: opts.email,
|
|
17
|
+
status: opts.status,
|
|
18
|
+
});
|
|
19
|
+
if (res.data.success) {
|
|
20
|
+
console.log(JSON.stringify(res.data.data, null, 2));
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
console.error("请求失败:", res.data.message);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
catch (err) {
|
|
27
|
+
console.error("请求失败:", err.response?.data?.message || err.message);
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
// tasks detail
|
|
31
|
+
tasksCmd
|
|
32
|
+
.command("detail")
|
|
33
|
+
.description("获取任务详情")
|
|
34
|
+
.requiredOption("--project-no <number>", "项目编号", parseInt)
|
|
35
|
+
.requiredOption("--task-no <number>", "任务编号", parseInt)
|
|
36
|
+
.action(async (opts) => {
|
|
37
|
+
try {
|
|
38
|
+
const client = getClient();
|
|
39
|
+
const res = await client.post("/api/open/tasks/detail", {
|
|
40
|
+
projectNo: opts.projectNo,
|
|
41
|
+
taskNo: opts.taskNo,
|
|
42
|
+
});
|
|
43
|
+
if (res.data.success) {
|
|
44
|
+
console.log(JSON.stringify(res.data.data, null, 2));
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
console.error("请求失败:", res.data.message);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
console.error("请求失败:", err.response?.data?.message || err.message);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
// tasks approve
|
|
55
|
+
tasksCmd
|
|
56
|
+
.command("approve")
|
|
57
|
+
.description("批准执行任务")
|
|
58
|
+
.requiredOption("--project-no <number>", "项目编号", parseInt)
|
|
59
|
+
.requiredOption("--task-no <number>", "任务编号", parseInt)
|
|
60
|
+
.requiredOption("--email <email>", "用户邮箱")
|
|
61
|
+
.option("--remark <remark>", "备注信息")
|
|
62
|
+
.action(async (opts) => {
|
|
63
|
+
try {
|
|
64
|
+
const client = getClient();
|
|
65
|
+
const res = await client.post("/api/open/tasks/approve", {
|
|
66
|
+
projectNo: opts.projectNo,
|
|
67
|
+
taskNo: opts.taskNo,
|
|
68
|
+
email: opts.email,
|
|
69
|
+
remark: opts.remark,
|
|
70
|
+
});
|
|
71
|
+
if (res.data.success) {
|
|
72
|
+
console.log("任务已批准执行");
|
|
73
|
+
console.log(JSON.stringify(res.data.data, null, 2));
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
console.error("请求失败:", res.data.message);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
catch (err) {
|
|
80
|
+
console.error("请求失败:", err.response?.data?.message || err.message);
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
// tasks start
|
|
84
|
+
tasksCmd
|
|
85
|
+
.command("start")
|
|
86
|
+
.description("开始任务")
|
|
87
|
+
.requiredOption("--project-no <number>", "项目编号", parseInt)
|
|
88
|
+
.requiredOption("--task-no <number>", "任务编号", parseInt)
|
|
89
|
+
.requiredOption("--email <email>", "用户邮箱")
|
|
90
|
+
.option("--remark <remark>", "备注信息")
|
|
91
|
+
.action(async (opts) => {
|
|
92
|
+
try {
|
|
93
|
+
const client = getClient();
|
|
94
|
+
const res = await client.post("/api/open/tasks/start", {
|
|
95
|
+
projectNo: opts.projectNo,
|
|
96
|
+
taskNo: opts.taskNo,
|
|
97
|
+
email: opts.email,
|
|
98
|
+
remark: opts.remark,
|
|
99
|
+
});
|
|
100
|
+
if (res.data.success) {
|
|
101
|
+
console.log("任务已开始");
|
|
102
|
+
console.log(JSON.stringify(res.data.data, null, 2));
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
console.error("请求失败:", res.data.message);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
catch (err) {
|
|
109
|
+
console.error("请求失败:", err.response?.data?.message || err.message);
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
// tasks complete
|
|
113
|
+
tasksCmd
|
|
114
|
+
.command("complete")
|
|
115
|
+
.description("完成任务")
|
|
116
|
+
.requiredOption("--project-no <number>", "项目编号", parseInt)
|
|
117
|
+
.requiredOption("--task-no <number>", "任务编号", parseInt)
|
|
118
|
+
.requiredOption("--email <email>", "用户邮箱")
|
|
119
|
+
.option("--remark <remark>", "完成说明")
|
|
120
|
+
.option("--hours-spent <minutes>", "本次消耗工时(分钟)", parseInt)
|
|
121
|
+
.action(async (opts) => {
|
|
122
|
+
try {
|
|
123
|
+
const client = getClient();
|
|
124
|
+
const res = await client.post("/api/open/tasks/complete", {
|
|
125
|
+
projectNo: opts.projectNo,
|
|
126
|
+
taskNo: opts.taskNo,
|
|
127
|
+
email: opts.email,
|
|
128
|
+
remark: opts.remark,
|
|
129
|
+
hoursSpent: opts.hoursSpent,
|
|
130
|
+
});
|
|
131
|
+
if (res.data.success) {
|
|
132
|
+
console.log("任务已完成");
|
|
133
|
+
console.log(JSON.stringify(res.data.data, null, 2));
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
console.error("请求失败:", res.data.message);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
catch (err) {
|
|
140
|
+
console.error("请求失败:", err.response?.data?.message || err.message);
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
// tasks error
|
|
144
|
+
tasksCmd
|
|
145
|
+
.command("error")
|
|
146
|
+
.description("标记任务异常")
|
|
147
|
+
.requiredOption("--project-no <number>", "项目编号", parseInt)
|
|
148
|
+
.requiredOption("--task-no <number>", "任务编号", parseInt)
|
|
149
|
+
.requiredOption("--email <email>", "用户邮箱")
|
|
150
|
+
.requiredOption("--remark <remark>", "异常原因")
|
|
151
|
+
.action(async (opts) => {
|
|
152
|
+
try {
|
|
153
|
+
const client = getClient();
|
|
154
|
+
const res = await client.post("/api/open/tasks/error", {
|
|
155
|
+
projectNo: opts.projectNo,
|
|
156
|
+
taskNo: opts.taskNo,
|
|
157
|
+
email: opts.email,
|
|
158
|
+
remark: opts.remark,
|
|
159
|
+
});
|
|
160
|
+
if (res.data.success) {
|
|
161
|
+
console.log("任务已标记异常");
|
|
162
|
+
console.log(JSON.stringify(res.data.data, null, 2));
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
console.error("请求失败:", res.data.message);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
catch (err) {
|
|
169
|
+
console.error("请求失败:", err.response?.data?.message || err.message);
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
// tasks comment
|
|
173
|
+
tasksCmd
|
|
174
|
+
.command("comment")
|
|
175
|
+
.description("添加任务备注")
|
|
176
|
+
.requiredOption("--project-no <number>", "项目编号", parseInt)
|
|
177
|
+
.requiredOption("--task-no <number>", "任务编号", parseInt)
|
|
178
|
+
.requiredOption("--email <email>", "用户邮箱")
|
|
179
|
+
.requiredOption("--remark <remark>", "备注内容")
|
|
180
|
+
.action(async (opts) => {
|
|
181
|
+
try {
|
|
182
|
+
const client = getClient();
|
|
183
|
+
const res = await client.post("/api/open/tasks/comments", {
|
|
184
|
+
projectNo: opts.projectNo,
|
|
185
|
+
taskNo: opts.taskNo,
|
|
186
|
+
email: opts.email,
|
|
187
|
+
remark: opts.remark,
|
|
188
|
+
});
|
|
189
|
+
if (res.data.success) {
|
|
190
|
+
console.log("备注添加成功");
|
|
191
|
+
console.log(JSON.stringify(res.data.data, null, 2));
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
console.error("请求失败:", res.data.message);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
catch (err) {
|
|
198
|
+
console.error("请求失败:", err.response?.data?.message || err.message);
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
// tasks attachments
|
|
202
|
+
tasksCmd
|
|
203
|
+
.command("attachments")
|
|
204
|
+
.description("获取任务附件列表")
|
|
205
|
+
.requiredOption("--project-no <number>", "项目编号", parseInt)
|
|
206
|
+
.requiredOption("--task-no <number>", "任务编号", parseInt)
|
|
207
|
+
.action(async (opts) => {
|
|
208
|
+
try {
|
|
209
|
+
const client = getClient();
|
|
210
|
+
const res = await client.post("/api/open/tasks/attachments", {
|
|
211
|
+
projectNo: opts.projectNo,
|
|
212
|
+
taskNo: opts.taskNo,
|
|
213
|
+
});
|
|
214
|
+
if (res.data.success) {
|
|
215
|
+
console.log(JSON.stringify(res.data.data, null, 2));
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
console.error("请求失败:", res.data.message);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
catch (err) {
|
|
222
|
+
console.error("请求失败:", err.response?.data?.message || err.message);
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { getClient } from "../config.js";
|
|
2
|
+
export function registerTodosCommands(program) {
|
|
3
|
+
const todosCmd = program.command("todos").description("待办事项相关命令");
|
|
4
|
+
// todos pending
|
|
5
|
+
todosCmd
|
|
6
|
+
.command("pending")
|
|
7
|
+
.description("获取待处理待办列表")
|
|
8
|
+
.requiredOption("--project-no <number>", "项目编号", parseInt)
|
|
9
|
+
.requiredOption("--email <email>", "用户邮箱")
|
|
10
|
+
.action(async (opts) => {
|
|
11
|
+
try {
|
|
12
|
+
const client = getClient();
|
|
13
|
+
const res = await client.post("/api/open/todos/pending", {
|
|
14
|
+
projectNo: opts.projectNo,
|
|
15
|
+
email: opts.email,
|
|
16
|
+
});
|
|
17
|
+
if (res.data.success) {
|
|
18
|
+
console.log(JSON.stringify(res.data.data, null, 2));
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
console.error("请求失败:", res.data.message);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
catch (err) {
|
|
25
|
+
console.error("请求失败:", err.response?.data?.message || err.message);
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
// todos approved
|
|
29
|
+
todosCmd
|
|
30
|
+
.command("approved")
|
|
31
|
+
.description("获取已批准待办列表")
|
|
32
|
+
.requiredOption("--project-no <number>", "项目编号", parseInt)
|
|
33
|
+
.requiredOption("--email <email>", "用户邮箱")
|
|
34
|
+
.option("--status <status>", "待办状态筛选: pending, approved, completed, failed, suspended, closed")
|
|
35
|
+
.action(async (opts) => {
|
|
36
|
+
try {
|
|
37
|
+
const client = getClient();
|
|
38
|
+
const res = await client.post("/api/open/todos/approved", {
|
|
39
|
+
projectNo: opts.projectNo,
|
|
40
|
+
email: opts.email,
|
|
41
|
+
status: opts.status,
|
|
42
|
+
});
|
|
43
|
+
if (res.data.success) {
|
|
44
|
+
console.log(JSON.stringify(res.data.data, null, 2));
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
console.error("请求失败:", res.data.message);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
console.error("请求失败:", err.response?.data?.message || err.message);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
// todos create
|
|
55
|
+
todosCmd
|
|
56
|
+
.command("create")
|
|
57
|
+
.description("创建待办")
|
|
58
|
+
.requiredOption("--project-no <number>", "项目编号", parseInt)
|
|
59
|
+
.requiredOption("--task-no <number>", "任务编号", parseInt)
|
|
60
|
+
.requiredOption("--email <email>", "用户邮箱")
|
|
61
|
+
.requiredOption("--title <title>", "待办标题")
|
|
62
|
+
.option("--description <description>", "待办描述")
|
|
63
|
+
.action(async (opts) => {
|
|
64
|
+
try {
|
|
65
|
+
const client = getClient();
|
|
66
|
+
const res = await client.post("/api/open/todos/create", {
|
|
67
|
+
projectNo: opts.projectNo,
|
|
68
|
+
taskNo: opts.taskNo,
|
|
69
|
+
email: opts.email,
|
|
70
|
+
title: opts.title,
|
|
71
|
+
description: opts.description,
|
|
72
|
+
});
|
|
73
|
+
if (res.data.success) {
|
|
74
|
+
console.log("待办创建成功");
|
|
75
|
+
console.log(JSON.stringify(res.data.data, null, 2));
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
console.error("请求失败:", res.data.message);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
catch (err) {
|
|
82
|
+
console.error("请求失败:", err.response?.data?.message || err.message);
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
// todos feedback
|
|
86
|
+
todosCmd
|
|
87
|
+
.command("feedback")
|
|
88
|
+
.description("待办反馈(状态变更)")
|
|
89
|
+
.requiredOption("--project-no <number>", "项目编号", parseInt)
|
|
90
|
+
.requiredOption("--todo-id <todoId>", "待办事项ID")
|
|
91
|
+
.requiredOption("--email <email>", "用户邮箱")
|
|
92
|
+
.requiredOption("--status <status>", "目标状态: completed, failed, suspended")
|
|
93
|
+
.option("--feedback <feedback>", "处理结果反馈内容")
|
|
94
|
+
.option("--processing-time <minutes>", "处理用时(分钟)", parseInt)
|
|
95
|
+
.option("--tokens-consumed <count>", "消耗Token数量", parseInt)
|
|
96
|
+
.action(async (opts) => {
|
|
97
|
+
try {
|
|
98
|
+
const client = getClient();
|
|
99
|
+
const res = await client.post("/api/open/todos/feedback", {
|
|
100
|
+
projectNo: opts.projectNo,
|
|
101
|
+
todoId: opts.todoId,
|
|
102
|
+
email: opts.email,
|
|
103
|
+
status: opts.status,
|
|
104
|
+
feedback: opts.feedback,
|
|
105
|
+
processingTime: opts.processingTime,
|
|
106
|
+
tokensConsumed: opts.tokensConsumed,
|
|
107
|
+
});
|
|
108
|
+
if (res.data.success) {
|
|
109
|
+
console.log("待办状态更新成功");
|
|
110
|
+
console.log(JSON.stringify(res.data.data, null, 2));
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
console.error("请求失败:", res.data.message);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
catch (err) {
|
|
117
|
+
console.error("请求失败:", err.response?.data?.message || err.message);
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import axios from "axios";
|
|
2
|
+
import { homedir } from "os";
|
|
3
|
+
import { join } from "path";
|
|
4
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs";
|
|
5
|
+
const CONFIG_DIR = join(homedir(), ".octopus");
|
|
6
|
+
const CONFIG_FILE = join(CONFIG_DIR, "settings.json");
|
|
7
|
+
export function loadConfig() {
|
|
8
|
+
if (!existsSync(CONFIG_FILE))
|
|
9
|
+
return {};
|
|
10
|
+
try {
|
|
11
|
+
return JSON.parse(readFileSync(CONFIG_FILE, "utf-8"));
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return {};
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export function saveConfig(config) {
|
|
18
|
+
if (!existsSync(CONFIG_DIR))
|
|
19
|
+
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
20
|
+
writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
|
|
21
|
+
}
|
|
22
|
+
export function getClient() {
|
|
23
|
+
const config = loadConfig();
|
|
24
|
+
const baseUrl = config.env?.OCTOPUS_BASE_URL || process.env.OCTOPUS_BASE_URL;
|
|
25
|
+
const token = config.env?.OCTOPUS_ACCESS_TOKEN || process.env.OCTOPUS_ACCESS_TOKEN;
|
|
26
|
+
if (!baseUrl)
|
|
27
|
+
throw new Error("缺少 baseUrl,请先运行 octopus config set baseUrl <url>");
|
|
28
|
+
if (!token)
|
|
29
|
+
throw new Error("缺少 token,请先运行 octopus config set token <token>");
|
|
30
|
+
return axios.create({
|
|
31
|
+
baseURL: baseUrl.replace(/\/+$/, ""),
|
|
32
|
+
headers: {
|
|
33
|
+
"X-Access-Token": token,
|
|
34
|
+
"Content-Type": "application/json",
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { registerConfigCommands } from "./commands/config.js";
|
|
3
|
+
import { registerTasksCommands } from "./commands/tasks.js";
|
|
4
|
+
import { registerTodosCommands } from "./commands/todos.js";
|
|
5
|
+
import { registerAttachmentsCommands } from "./commands/attachments.js";
|
|
6
|
+
import pkg from "../package.json" with { type: "json" };
|
|
7
|
+
const program = new Command();
|
|
8
|
+
program.name("octopus").description("Octopus CLI").version(pkg.version);
|
|
9
|
+
registerConfigCommands(program);
|
|
10
|
+
registerTasksCommands(program);
|
|
11
|
+
registerTodosCommands(program);
|
|
12
|
+
registerAttachmentsCommands(program);
|
|
13
|
+
program.parse();
|
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@skylandnpm/octopus-cli",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"bin": {
|
|
6
|
+
"octopus": "./bin/octopus.js"
|
|
7
|
+
},
|
|
8
|
+
"scripts": {
|
|
9
|
+
"build": "tsc",
|
|
10
|
+
"build:patch:publish": "pnpm build && npm version patch && npm publish",
|
|
11
|
+
"dev": "tsc -w"
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"bin",
|
|
15
|
+
"dist"
|
|
16
|
+
],
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"axios": "^1.7.9",
|
|
19
|
+
"commander": "^12.1.0",
|
|
20
|
+
"form-data": "^4.0.5"
|
|
21
|
+
},
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"@types/node": "^22.10.2",
|
|
24
|
+
"vite": "8.0.3"
|
|
25
|
+
},
|
|
26
|
+
"peerDependencies": {
|
|
27
|
+
"typescript": "^5"
|
|
28
|
+
},
|
|
29
|
+
"publishConfig": {
|
|
30
|
+
"access": "public",
|
|
31
|
+
"registry": "https://registry.npmjs.org"
|
|
32
|
+
}
|
|
33
|
+
}
|