@arcships/morula-runtime 0.1.0-alpha.6 → 0.1.0-alpha.8
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/index.js +2236 -608
- package/dist/morula.js +1584 -109
- package/dist/plugin/plugin.json +1 -1
- package/dist/plugin/skills/morula-cli/SKILL.md +0 -1
- package/dist/plugin/skills/morula-cli/references/commands.md +1533 -254
- package/dist/plugin/skills/morula-working-on-issues/SKILL.md +11 -9
- package/dist/plugin/skills/morula-working-on-issues/references/working-on-issues-source-map.md +1 -1
- package/package.json +3 -2
package/dist/morula.js
CHANGED
|
@@ -41,6 +41,11 @@ function parseArgs(argv) {
|
|
|
41
41
|
const positionals = [];
|
|
42
42
|
const flags = {};
|
|
43
43
|
const bareFlags = [];
|
|
44
|
+
const valueOccurrences = {};
|
|
45
|
+
const recordValue = (key, value) => {
|
|
46
|
+
flags[key] = value;
|
|
47
|
+
(valueOccurrences[key] ??= []).push(value);
|
|
48
|
+
};
|
|
44
49
|
let positionalOnly = false;
|
|
45
50
|
for (let index = 0; index < argv.length; index += 1) {
|
|
46
51
|
const value = argv[index];
|
|
@@ -62,7 +67,7 @@ function parseArgs(argv) {
|
|
|
62
67
|
}
|
|
63
68
|
const equal = value.indexOf("=");
|
|
64
69
|
if (equal > 2) {
|
|
65
|
-
|
|
70
|
+
recordValue(value.slice(2, equal), value.slice(equal + 1));
|
|
66
71
|
continue;
|
|
67
72
|
}
|
|
68
73
|
const key = value.slice(2);
|
|
@@ -70,21 +75,34 @@ function parseArgs(argv) {
|
|
|
70
75
|
throw usage("invalid empty flag");
|
|
71
76
|
const next = argv[index + 1];
|
|
72
77
|
if (next !== void 0 && !next.startsWith("--")) {
|
|
73
|
-
|
|
78
|
+
recordValue(key, next);
|
|
74
79
|
index += 1;
|
|
75
80
|
} else {
|
|
76
81
|
flags[key] = true;
|
|
77
82
|
bareFlags.push(key);
|
|
78
83
|
}
|
|
79
84
|
}
|
|
85
|
+
const repeatedFlags = {};
|
|
86
|
+
for (const [key, values] of Object.entries(valueOccurrences)) {
|
|
87
|
+
if (values.length > 1)
|
|
88
|
+
repeatedFlags[key] = values;
|
|
89
|
+
}
|
|
80
90
|
return {
|
|
81
91
|
command: positionals.shift(),
|
|
82
92
|
action: positionals.shift(),
|
|
83
93
|
positionals,
|
|
84
94
|
flags,
|
|
85
|
-
bareFlags
|
|
95
|
+
bareFlags,
|
|
96
|
+
repeatedFlags
|
|
86
97
|
};
|
|
87
98
|
}
|
|
99
|
+
function flagStrings(parsed, name) {
|
|
100
|
+
const repeated = parsed.repeatedFlags[name];
|
|
101
|
+
if (repeated?.length)
|
|
102
|
+
return repeated;
|
|
103
|
+
const single = flagString(parsed.flags, name);
|
|
104
|
+
return single === void 0 ? [] : [single];
|
|
105
|
+
}
|
|
88
106
|
function flagString(flags, ...names) {
|
|
89
107
|
for (const name of names) {
|
|
90
108
|
const value = flags[name];
|
|
@@ -686,8 +704,8 @@ function page(ok, message) {
|
|
|
686
704
|
}
|
|
687
705
|
|
|
688
706
|
// ../morula-cli-core/dist/build-env.js
|
|
689
|
-
var BUILD_VERSION = "0.1.0-alpha.
|
|
690
|
-
var BUILD_ID = "
|
|
707
|
+
var BUILD_VERSION = "0.1.0-alpha.8";
|
|
708
|
+
var BUILD_ID = "20260921065825.nogit";
|
|
691
709
|
var BUILD_CONTEXTS = {
|
|
692
710
|
"local": "http://localhost:8080/api",
|
|
693
711
|
"test": "https://morula.basecastle.com/api",
|
|
@@ -695,6 +713,42 @@ var BUILD_CONTEXTS = {
|
|
|
695
713
|
};
|
|
696
714
|
var BUILD_DEFAULT_CONTEXT = "prod";
|
|
697
715
|
|
|
716
|
+
// ../morula-api-client/dist/agent-task.js
|
|
717
|
+
var AgentTaskApi = class {
|
|
718
|
+
client;
|
|
719
|
+
constructor(client) {
|
|
720
|
+
this.client = client;
|
|
721
|
+
}
|
|
722
|
+
/** 列出 AgentTask(objectId 必填;status/page/pageSize 可选) */
|
|
723
|
+
list(query = {}) {
|
|
724
|
+
return this.client.get("/agent-tasks", query);
|
|
725
|
+
}
|
|
726
|
+
/**
|
|
727
|
+
* 取消执行。
|
|
728
|
+
*
|
|
729
|
+
* 服务端语义(`agent-task.controller.ts` cancel,2026-09-20 起):
|
|
730
|
+
* - 成功 → 200 `{ ok: true, message: 'Task cancelled' }`;
|
|
731
|
+
* - 任务不存在 → **404** `NOT_FOUND`;
|
|
732
|
+
* - 状态不允许(`completed` / `cancelled`)→ **409** `CONFLICT`(带可读原因)。
|
|
733
|
+
*
|
|
734
|
+
* 即:**失败会 reject**(不再 200 假成功,见 issues/agent-task-cancel-returns-200-on-failure.md)——
|
|
735
|
+
* 调用方按异常/退出码判断,不要假定「调用返回了就是已取消」。
|
|
736
|
+
*/
|
|
737
|
+
cancel(id) {
|
|
738
|
+
return this.client.post(`/agent-tasks/${encodeURIComponent(requiredId(id))}/cancel`);
|
|
739
|
+
}
|
|
740
|
+
/** 重跑失败/已取消的执行(服务端复制原任务重新入队,返回**新** taskId) */
|
|
741
|
+
rerun(id) {
|
|
742
|
+
return this.client.post(`/agent-tasks/${encodeURIComponent(requiredId(id))}/rerun`);
|
|
743
|
+
}
|
|
744
|
+
};
|
|
745
|
+
function requiredId(id) {
|
|
746
|
+
const normalized = id.trim();
|
|
747
|
+
if (!normalized)
|
|
748
|
+
throw new TypeError("agent task id is required");
|
|
749
|
+
return normalized;
|
|
750
|
+
}
|
|
751
|
+
|
|
698
752
|
// ../morula-api-client/dist/attachment.js
|
|
699
753
|
var AttachmentApi = class {
|
|
700
754
|
client;
|
|
@@ -740,6 +794,13 @@ var AttachmentApi = class {
|
|
|
740
794
|
getDownloadUrl(id) {
|
|
741
795
|
return this.client.get(`/attachments/${encodeURIComponent(id)}/download-url`);
|
|
742
796
|
}
|
|
797
|
+
/**
|
|
798
|
+
* 读取附件的解析产物全文(MinerU markdown)。
|
|
799
|
+
* 未解析/解析中/解析失败由服务端在返回体里说明,不当作 HTTP 错误。
|
|
800
|
+
*/
|
|
801
|
+
content(id, maxChars) {
|
|
802
|
+
return this.client.get(`/attachments/${encodeURIComponent(id)}/content`, { maxChars });
|
|
803
|
+
}
|
|
743
804
|
/** 更新附件关联的资源 ID */
|
|
744
805
|
updateResourceId(id, resourceId) {
|
|
745
806
|
return this.client.patch(`/attachments/${encodeURIComponent(id)}`, { resourceId });
|
|
@@ -770,6 +831,81 @@ var AuthApi = class {
|
|
|
770
831
|
}
|
|
771
832
|
};
|
|
772
833
|
|
|
834
|
+
// ../morula-api-client/dist/autopilot.js
|
|
835
|
+
var AutopilotApi = class {
|
|
836
|
+
client;
|
|
837
|
+
constructor(client) {
|
|
838
|
+
this.client = client;
|
|
839
|
+
}
|
|
840
|
+
list(query = {}) {
|
|
841
|
+
return this.client.get("/agent-autopilots", query);
|
|
842
|
+
}
|
|
843
|
+
create(input) {
|
|
844
|
+
return this.client.post("/agent-autopilots", input);
|
|
845
|
+
}
|
|
846
|
+
};
|
|
847
|
+
|
|
848
|
+
// ../morula-api-client/dist/ci.js
|
|
849
|
+
var CiApi = class {
|
|
850
|
+
client;
|
|
851
|
+
constructor(client) {
|
|
852
|
+
this.client = client;
|
|
853
|
+
}
|
|
854
|
+
/** 任务面 CI 视图(本任务关联的流水线运行 + 部署记录 + 归属依据) */
|
|
855
|
+
taskView(taskId, query = {}) {
|
|
856
|
+
return this.client.get(`/agent-tasks/${encodeURIComponent(requiredId2(taskId, "task id"))}/vcs/ci`, query);
|
|
857
|
+
}
|
|
858
|
+
/** 任务面部署记录(D3:仅展示,不驱动流转) */
|
|
859
|
+
taskDeployments(taskId) {
|
|
860
|
+
return this.client.get(`/agent-tasks/${encodeURIComponent(requiredId2(taskId, "task id"))}/vcs/ci/deployments`);
|
|
861
|
+
}
|
|
862
|
+
/** 空间面 CI 巡检视图(管家主入口;`ref` / `failed` / `limit` 为服务端过滤) */
|
|
863
|
+
spaceView(spaceId, query = {}) {
|
|
864
|
+
return this.client.get(`/vcs/spaces/${encodeURIComponent(requiredId2(spaceId, "space id"))}/ci`, query);
|
|
865
|
+
}
|
|
866
|
+
/** 空间面部署记录(D3:仅展示) */
|
|
867
|
+
spaceDeployments(spaceId) {
|
|
868
|
+
return this.client.get(`/vcs/spaces/${encodeURIComponent(requiredId2(spaceId, "space id"))}/ci/deployments`);
|
|
869
|
+
}
|
|
870
|
+
/**
|
|
871
|
+
* job 日志(按 job id;服务端反查所属运行)。
|
|
872
|
+
*
|
|
873
|
+
* 两个面共用本端点:任务凭证按 tenantId 收敛,会话凭证按 `connection.spaceId === scopeId` 收敛。
|
|
874
|
+
* `truncated` 显式返回——日志被尾部截断时调用方必须知道(不能把截断当全文)。
|
|
875
|
+
*/
|
|
876
|
+
jobLog(jobId, query = {}) {
|
|
877
|
+
return this.client.get(`/vcs/jobs/${encodeURIComponent(requiredId2(jobId, "job id"))}/log`, query);
|
|
878
|
+
}
|
|
879
|
+
/** 失败用例清单(平台可选能力:GitLab test_report 有、GitHub 无 → `CAPABILITY_UNSUPPORTED`) */
|
|
880
|
+
testReport(runId) {
|
|
881
|
+
return this.client.get(`/vcs/runs/${encodeURIComponent(requiredId2(runId, "run id"))}/test-report`);
|
|
882
|
+
}
|
|
883
|
+
/**
|
|
884
|
+
* 重跑整条流水线的失败 job(Phase 3;开放面 = 人 + 管家)。
|
|
885
|
+
*
|
|
886
|
+
* 只允许 failure / cancelled 的运行,其余状态服务端回 `CI_RETRY_NOT_ALLOWED`(不是 4xx)。
|
|
887
|
+
* **非幂等**:每次调用都会在平台上产生一次新的重跑,重复调用不会去重。
|
|
888
|
+
*/
|
|
889
|
+
retryRun(runId) {
|
|
890
|
+
return this.client.post(`/vcs/runs/${encodeURIComponent(requiredId2(runId, "run id"))}/retry`);
|
|
891
|
+
}
|
|
892
|
+
/**
|
|
893
|
+
* 重跑单个 job(Phase 3;开放面 = 人 + 管家)。
|
|
894
|
+
*
|
|
895
|
+
* 服务端按 jobId 反查所属运行(`CI_JOB_NOT_FOUND` 覆盖「job 不存在」与「反查不到运行」两种情况);
|
|
896
|
+
* 状态门禁与 `retryRun` 相同。非幂等。
|
|
897
|
+
*/
|
|
898
|
+
retryJob(jobId) {
|
|
899
|
+
return this.client.post(`/vcs/jobs/${encodeURIComponent(requiredId2(jobId, "job id"))}/retry`);
|
|
900
|
+
}
|
|
901
|
+
};
|
|
902
|
+
function requiredId2(id, label) {
|
|
903
|
+
const normalized = id.trim();
|
|
904
|
+
if (!normalized)
|
|
905
|
+
throw new TypeError(`${label} is required`);
|
|
906
|
+
return normalized;
|
|
907
|
+
}
|
|
908
|
+
|
|
773
909
|
// ../morula-api-client/dist/client.js
|
|
774
910
|
var EXIT_CODE = {
|
|
775
911
|
OK: 0,
|
|
@@ -787,14 +923,16 @@ var MorulaApiError = class extends Error {
|
|
|
787
923
|
status;
|
|
788
924
|
retryable;
|
|
789
925
|
details;
|
|
926
|
+
errorCode;
|
|
790
927
|
name = "MorulaApiError";
|
|
791
|
-
constructor(code, message, exitCode, status2, retryable = false, details) {
|
|
928
|
+
constructor(code, message, exitCode, status2, retryable = false, details, errorCode) {
|
|
792
929
|
super(message);
|
|
793
930
|
this.code = code;
|
|
794
931
|
this.exitCode = exitCode;
|
|
795
932
|
this.status = status2;
|
|
796
933
|
this.retryable = retryable;
|
|
797
934
|
this.details = details;
|
|
935
|
+
this.errorCode = errorCode;
|
|
798
936
|
}
|
|
799
937
|
};
|
|
800
938
|
var CLI_BUILD_HEADER = "X-Morula-Cli-Build";
|
|
@@ -960,28 +1098,35 @@ function isEnvelope(value) {
|
|
|
960
1098
|
function errorFromResponse(status2, parsed, raw) {
|
|
961
1099
|
const message = extractMessage(parsed, raw, status2);
|
|
962
1100
|
const details = isEnvelope(parsed) ? parsed.data : parsed;
|
|
1101
|
+
const errorCode = extractErrorCode(parsed);
|
|
963
1102
|
if (status2 === 400 || status2 === 422) {
|
|
964
|
-
return new MorulaApiError("BAD_REQUEST", message, EXIT_CODE.USAGE, status2, false, details);
|
|
1103
|
+
return new MorulaApiError("BAD_REQUEST", message, EXIT_CODE.USAGE, status2, false, details, errorCode);
|
|
965
1104
|
}
|
|
966
1105
|
if (status2 === 401) {
|
|
967
|
-
return new MorulaApiError("UNAUTHENTICATED", message, EXIT_CODE.UNAUTHENTICATED, status2, false, details);
|
|
1106
|
+
return new MorulaApiError("UNAUTHENTICATED", message, EXIT_CODE.UNAUTHENTICATED, status2, false, details, errorCode);
|
|
968
1107
|
}
|
|
969
1108
|
if (status2 === 403) {
|
|
970
|
-
return new MorulaApiError("FORBIDDEN", message, EXIT_CODE.FORBIDDEN, status2, false, details);
|
|
1109
|
+
return new MorulaApiError("FORBIDDEN", message, EXIT_CODE.FORBIDDEN, status2, false, details, errorCode);
|
|
971
1110
|
}
|
|
972
1111
|
if (status2 === 404) {
|
|
973
|
-
return new MorulaApiError("NOT_FOUND", message, EXIT_CODE.NOT_FOUND, status2, false, details);
|
|
1112
|
+
return new MorulaApiError("NOT_FOUND", message, EXIT_CODE.NOT_FOUND, status2, false, details, errorCode);
|
|
974
1113
|
}
|
|
975
1114
|
if (status2 === 409) {
|
|
976
|
-
return new MorulaApiError("CONFLICT", message, EXIT_CODE.CONFLICT, status2, false, details);
|
|
1115
|
+
return new MorulaApiError("CONFLICT", message, EXIT_CODE.CONFLICT, status2, false, details, errorCode);
|
|
977
1116
|
}
|
|
978
1117
|
if (status2 === 429) {
|
|
979
|
-
return new MorulaApiError("RATE_LIMITED", message, EXIT_CODE.UPSTREAM, status2, true, details);
|
|
1118
|
+
return new MorulaApiError("RATE_LIMITED", message, EXIT_CODE.UPSTREAM, status2, true, details, errorCode);
|
|
980
1119
|
}
|
|
981
1120
|
if (status2 >= 500) {
|
|
982
|
-
return new MorulaApiError("UPSTREAM", message, EXIT_CODE.UPSTREAM, status2, true, details);
|
|
1121
|
+
return new MorulaApiError("UPSTREAM", message, EXIT_CODE.UPSTREAM, status2, true, details, errorCode);
|
|
983
1122
|
}
|
|
984
|
-
return new MorulaApiError("HTTP_ERROR", message, EXIT_CODE.OTHER, status2, false, details);
|
|
1123
|
+
return new MorulaApiError("HTTP_ERROR", message, EXIT_CODE.OTHER, status2, false, details, errorCode);
|
|
1124
|
+
}
|
|
1125
|
+
function extractErrorCode(parsed) {
|
|
1126
|
+
if (!parsed || typeof parsed !== "object")
|
|
1127
|
+
return void 0;
|
|
1128
|
+
const value = parsed.errorCode;
|
|
1129
|
+
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
985
1130
|
}
|
|
986
1131
|
function extractMessage(parsed, raw, status2) {
|
|
987
1132
|
if (parsed && typeof parsed === "object" && "message" in parsed) {
|
|
@@ -1011,25 +1156,120 @@ var CommentApi = class {
|
|
|
1011
1156
|
return this.client.get("/comments", params);
|
|
1012
1157
|
}
|
|
1013
1158
|
get(id) {
|
|
1014
|
-
return this.client.get(`/comments/${encodeURIComponent(
|
|
1159
|
+
return this.client.get(`/comments/${encodeURIComponent(requiredId3(id))}`);
|
|
1015
1160
|
}
|
|
1016
1161
|
create(input) {
|
|
1017
1162
|
return this.client.post("/comments", input);
|
|
1018
1163
|
}
|
|
1019
1164
|
update(id, input) {
|
|
1020
|
-
return this.client.patch(`/comments/${encodeURIComponent(
|
|
1165
|
+
return this.client.patch(`/comments/${encodeURIComponent(requiredId3(id))}`, input);
|
|
1021
1166
|
}
|
|
1022
1167
|
delete(id) {
|
|
1023
|
-
return this.client.delete(`/comments/${encodeURIComponent(
|
|
1168
|
+
return this.client.delete(`/comments/${encodeURIComponent(requiredId3(id))}`);
|
|
1024
1169
|
}
|
|
1025
1170
|
};
|
|
1026
|
-
function
|
|
1171
|
+
function requiredId3(id) {
|
|
1027
1172
|
const normalized = id.trim();
|
|
1028
1173
|
if (!normalized)
|
|
1029
1174
|
throw new TypeError("comment id is required");
|
|
1030
1175
|
return normalized;
|
|
1031
1176
|
}
|
|
1032
1177
|
|
|
1178
|
+
// ../morula-api-client/dist/dashboard.js
|
|
1179
|
+
var DashboardApi = class {
|
|
1180
|
+
client;
|
|
1181
|
+
constructor(client) {
|
|
1182
|
+
this.client = client;
|
|
1183
|
+
}
|
|
1184
|
+
get(spaceId) {
|
|
1185
|
+
return this.client.get(`/spaces/${encodeURIComponent(requiredId4(spaceId))}/dashboard`);
|
|
1186
|
+
}
|
|
1187
|
+
statistics(spaceId) {
|
|
1188
|
+
return this.client.get(`/spaces/${encodeURIComponent(requiredId4(spaceId))}/statistics`);
|
|
1189
|
+
}
|
|
1190
|
+
workload(spaceId) {
|
|
1191
|
+
return this.client.get(`/spaces/${encodeURIComponent(requiredId4(spaceId))}/workload`);
|
|
1192
|
+
}
|
|
1193
|
+
};
|
|
1194
|
+
function requiredId4(id) {
|
|
1195
|
+
const normalized = id.trim();
|
|
1196
|
+
if (!normalized)
|
|
1197
|
+
throw new TypeError("space id is required");
|
|
1198
|
+
return normalized;
|
|
1199
|
+
}
|
|
1200
|
+
|
|
1201
|
+
// ../morula-api-client/dist/document.js
|
|
1202
|
+
var DocumentApi = class {
|
|
1203
|
+
client;
|
|
1204
|
+
constructor(client) {
|
|
1205
|
+
this.client = client;
|
|
1206
|
+
}
|
|
1207
|
+
list(query = {}) {
|
|
1208
|
+
return this.client.get("/documents", query);
|
|
1209
|
+
}
|
|
1210
|
+
get(id) {
|
|
1211
|
+
return this.client.get(`/documents/${encodeURIComponent(requiredId5(id))}`);
|
|
1212
|
+
}
|
|
1213
|
+
/** 已解析归档的文档内容(Markdown 正文等) */
|
|
1214
|
+
artifacts(id) {
|
|
1215
|
+
return this.client.get(`/documents/${encodeURIComponent(requiredId5(id))}/artifacts`);
|
|
1216
|
+
}
|
|
1217
|
+
};
|
|
1218
|
+
function requiredId5(id) {
|
|
1219
|
+
const normalized = String(id).trim();
|
|
1220
|
+
if (!normalized)
|
|
1221
|
+
throw new TypeError("document id is required");
|
|
1222
|
+
return normalized;
|
|
1223
|
+
}
|
|
1224
|
+
|
|
1225
|
+
// ../morula-api-client/dist/object-meta.js
|
|
1226
|
+
var ObjectMetaApi = class {
|
|
1227
|
+
client;
|
|
1228
|
+
constructor(client) {
|
|
1229
|
+
this.client = client;
|
|
1230
|
+
}
|
|
1231
|
+
list(objectId) {
|
|
1232
|
+
return this.client.get(`/objects/${encodeURIComponent(requiredId6(objectId))}/agent-meta`);
|
|
1233
|
+
}
|
|
1234
|
+
set(objectId, key, value) {
|
|
1235
|
+
return this.client.request(`/objects/${encodeURIComponent(requiredId6(objectId))}/agent-meta/${encodeURIComponent(requiredKey(key))}`, { method: "PUT", body: { value } });
|
|
1236
|
+
}
|
|
1237
|
+
};
|
|
1238
|
+
function requiredId6(id) {
|
|
1239
|
+
const normalized = id.trim();
|
|
1240
|
+
if (!normalized)
|
|
1241
|
+
throw new TypeError("object id is required");
|
|
1242
|
+
return normalized;
|
|
1243
|
+
}
|
|
1244
|
+
function requiredKey(key) {
|
|
1245
|
+
const normalized = key.trim();
|
|
1246
|
+
if (!normalized)
|
|
1247
|
+
throw new TypeError("meta key is required");
|
|
1248
|
+
return normalized;
|
|
1249
|
+
}
|
|
1250
|
+
|
|
1251
|
+
// ../morula-api-client/dist/repo.js
|
|
1252
|
+
var RepoApi = class {
|
|
1253
|
+
client;
|
|
1254
|
+
constructor(client) {
|
|
1255
|
+
this.client = client;
|
|
1256
|
+
}
|
|
1257
|
+
/** 目录清单(path 缺省 = 仓库根) */
|
|
1258
|
+
files(spaceId, query = {}) {
|
|
1259
|
+
return this.client.get(`/spaces/${encodeURIComponent(requiredId7(spaceId))}/repo/files`, query);
|
|
1260
|
+
}
|
|
1261
|
+
/** 单文件内容(path 必填) */
|
|
1262
|
+
read(spaceId, query) {
|
|
1263
|
+
return this.client.get(`/spaces/${encodeURIComponent(requiredId7(spaceId))}/repo/file`, query);
|
|
1264
|
+
}
|
|
1265
|
+
};
|
|
1266
|
+
function requiredId7(id) {
|
|
1267
|
+
const normalized = id.trim();
|
|
1268
|
+
if (!normalized)
|
|
1269
|
+
throw new TypeError("space id is required");
|
|
1270
|
+
return normalized;
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1033
1273
|
// ../morula-api-client/dist/report.js
|
|
1034
1274
|
var ReportApi = class {
|
|
1035
1275
|
client;
|
|
@@ -1040,13 +1280,13 @@ var ReportApi = class {
|
|
|
1040
1280
|
return this.client.post("/agent-reports", input);
|
|
1041
1281
|
}
|
|
1042
1282
|
get(id) {
|
|
1043
|
-
return this.client.get(`/agent-reports/${encodeURIComponent(
|
|
1283
|
+
return this.client.get(`/agent-reports/${encodeURIComponent(requiredId8(id))}`);
|
|
1044
1284
|
}
|
|
1045
1285
|
listByAutopilot(autopilotId, query = {}) {
|
|
1046
|
-
return this.client.get(`/agent-autopilots/${encodeURIComponent(
|
|
1286
|
+
return this.client.get(`/agent-autopilots/${encodeURIComponent(requiredId8(autopilotId, "autopilot"))}/reports`, { ...query });
|
|
1047
1287
|
}
|
|
1048
1288
|
};
|
|
1049
|
-
function
|
|
1289
|
+
function requiredId8(id, label = "report") {
|
|
1050
1290
|
const normalized = id.trim();
|
|
1051
1291
|
if (!normalized)
|
|
1052
1292
|
throw new TypeError(`${label} id is required`);
|
|
@@ -1063,19 +1303,19 @@ var SpaceMemberApi = class {
|
|
|
1063
1303
|
return this.client.get("/space-members", { spaceId, ...query });
|
|
1064
1304
|
}
|
|
1065
1305
|
get(id) {
|
|
1066
|
-
return this.client.get(`/space-members/${encodeURIComponent(
|
|
1306
|
+
return this.client.get(`/space-members/${encodeURIComponent(requiredId9(id))}`);
|
|
1067
1307
|
}
|
|
1068
1308
|
create(input) {
|
|
1069
1309
|
return this.client.post("/space-members", input);
|
|
1070
1310
|
}
|
|
1071
1311
|
update(id, input) {
|
|
1072
|
-
return this.client.patch(`/space-members/${encodeURIComponent(
|
|
1312
|
+
return this.client.patch(`/space-members/${encodeURIComponent(requiredId9(id))}`, input);
|
|
1073
1313
|
}
|
|
1074
1314
|
delete(id) {
|
|
1075
|
-
return this.client.delete(`/space-members/${encodeURIComponent(
|
|
1315
|
+
return this.client.delete(`/space-members/${encodeURIComponent(requiredId9(id))}`);
|
|
1076
1316
|
}
|
|
1077
1317
|
};
|
|
1078
|
-
function
|
|
1318
|
+
function requiredId9(id) {
|
|
1079
1319
|
const normalized = id.trim();
|
|
1080
1320
|
if (!normalized)
|
|
1081
1321
|
throw new TypeError("space member id is required");
|
|
@@ -1092,25 +1332,47 @@ var SpaceApi = class {
|
|
|
1092
1332
|
return this.client.get("/spaces", query);
|
|
1093
1333
|
}
|
|
1094
1334
|
get(id) {
|
|
1095
|
-
return this.client.get(`/spaces/${encodeURIComponent(
|
|
1335
|
+
return this.client.get(`/spaces/${encodeURIComponent(requiredId10(id))}`);
|
|
1096
1336
|
}
|
|
1097
1337
|
create(input) {
|
|
1098
1338
|
return this.client.post("/spaces", input);
|
|
1099
1339
|
}
|
|
1100
1340
|
update(id, input) {
|
|
1101
|
-
return this.client.patch(`/spaces/${encodeURIComponent(
|
|
1341
|
+
return this.client.patch(`/spaces/${encodeURIComponent(requiredId10(id))}`, input);
|
|
1102
1342
|
}
|
|
1103
1343
|
delete(id) {
|
|
1104
|
-
return this.client.delete(`/spaces/${encodeURIComponent(
|
|
1344
|
+
return this.client.delete(`/spaces/${encodeURIComponent(requiredId10(id))}`);
|
|
1105
1345
|
}
|
|
1106
1346
|
};
|
|
1107
|
-
function
|
|
1347
|
+
function requiredId10(id) {
|
|
1108
1348
|
const normalized = id.trim();
|
|
1109
1349
|
if (!normalized)
|
|
1110
1350
|
throw new TypeError("space id is required");
|
|
1111
1351
|
return normalized;
|
|
1112
1352
|
}
|
|
1113
1353
|
|
|
1354
|
+
// ../morula-api-client/dist/steward.js
|
|
1355
|
+
var StewardApi = class {
|
|
1356
|
+
client;
|
|
1357
|
+
constructor(client) {
|
|
1358
|
+
this.client = client;
|
|
1359
|
+
}
|
|
1360
|
+
/** 管家信息(未接管的空间返回 null) */
|
|
1361
|
+
get(projectId) {
|
|
1362
|
+
return this.client.get(`/stewards/projects/${encodeURIComponent(requiredId11(projectId))}`);
|
|
1363
|
+
}
|
|
1364
|
+
/** 派单:建任务并派发(目标状态由 state 决定,backlog 不派发执行) */
|
|
1365
|
+
dispatch(projectId, input) {
|
|
1366
|
+
return this.client.post(`/stewards/projects/${encodeURIComponent(requiredId11(projectId))}/dispatch`, input);
|
|
1367
|
+
}
|
|
1368
|
+
};
|
|
1369
|
+
function requiredId11(id) {
|
|
1370
|
+
const normalized = id.trim();
|
|
1371
|
+
if (!normalized)
|
|
1372
|
+
throw new TypeError("project id is required");
|
|
1373
|
+
return normalized;
|
|
1374
|
+
}
|
|
1375
|
+
|
|
1114
1376
|
// ../morula-api-client/dist/task.js
|
|
1115
1377
|
var TaskApi = class {
|
|
1116
1378
|
client;
|
|
@@ -1121,16 +1383,16 @@ var TaskApi = class {
|
|
|
1121
1383
|
return this.client.get("/objects", query);
|
|
1122
1384
|
}
|
|
1123
1385
|
get(id) {
|
|
1124
|
-
return this.client.get(`/objects/${encodeURIComponent(
|
|
1386
|
+
return this.client.get(`/objects/${encodeURIComponent(requiredId12(id))}`);
|
|
1125
1387
|
}
|
|
1126
1388
|
create(input) {
|
|
1127
1389
|
return this.client.post("/objects", input);
|
|
1128
1390
|
}
|
|
1129
1391
|
update(id, input) {
|
|
1130
|
-
return this.client.patch(`/objects/${encodeURIComponent(
|
|
1392
|
+
return this.client.patch(`/objects/${encodeURIComponent(requiredId12(id))}`, input);
|
|
1131
1393
|
}
|
|
1132
1394
|
delete(id) {
|
|
1133
|
-
return this.client.delete(`/objects/${encodeURIComponent(
|
|
1395
|
+
return this.client.delete(`/objects/${encodeURIComponent(requiredId12(id))}`);
|
|
1134
1396
|
}
|
|
1135
1397
|
/** 查询空间字段模板(字段 key → id 映射、options) */
|
|
1136
1398
|
getSchemaFields(spaceId) {
|
|
@@ -1159,7 +1421,7 @@ var TaskApi = class {
|
|
|
1159
1421
|
return this.client.delete(`/object-field-values`, { objectId, schemaFieldId });
|
|
1160
1422
|
}
|
|
1161
1423
|
};
|
|
1162
|
-
function
|
|
1424
|
+
function requiredId12(id) {
|
|
1163
1425
|
const normalized = id.trim();
|
|
1164
1426
|
if (!normalized)
|
|
1165
1427
|
throw new TypeError("task id is required");
|
|
@@ -1183,23 +1445,39 @@ var WebhookApi = class {
|
|
|
1183
1445
|
// ../morula-api-client/dist/index.js
|
|
1184
1446
|
var MorulaClient = class {
|
|
1185
1447
|
http;
|
|
1448
|
+
agentTasks;
|
|
1186
1449
|
attachments;
|
|
1187
1450
|
auth;
|
|
1451
|
+
autopilots;
|
|
1452
|
+
ci;
|
|
1188
1453
|
comments;
|
|
1454
|
+
dashboard;
|
|
1455
|
+
documents;
|
|
1456
|
+
objectMeta;
|
|
1189
1457
|
reports;
|
|
1458
|
+
repos;
|
|
1190
1459
|
tasks;
|
|
1191
1460
|
spaces;
|
|
1192
1461
|
spaceMembers;
|
|
1462
|
+
stewards;
|
|
1193
1463
|
webhooks;
|
|
1194
1464
|
constructor(options) {
|
|
1195
1465
|
this.http = new MorulaApiClient(options);
|
|
1466
|
+
this.agentTasks = new AgentTaskApi(this.http);
|
|
1196
1467
|
this.attachments = new AttachmentApi(this.http);
|
|
1197
1468
|
this.auth = new AuthApi(this.http);
|
|
1469
|
+
this.autopilots = new AutopilotApi(this.http);
|
|
1470
|
+
this.ci = new CiApi(this.http);
|
|
1198
1471
|
this.comments = new CommentApi(this.http);
|
|
1472
|
+
this.dashboard = new DashboardApi(this.http);
|
|
1473
|
+
this.documents = new DocumentApi(this.http);
|
|
1474
|
+
this.objectMeta = new ObjectMetaApi(this.http);
|
|
1199
1475
|
this.reports = new ReportApi(this.http);
|
|
1476
|
+
this.repos = new RepoApi(this.http);
|
|
1200
1477
|
this.tasks = new TaskApi(this.http);
|
|
1201
1478
|
this.spaces = new SpaceApi(this.http);
|
|
1202
1479
|
this.spaceMembers = new SpaceMemberApi(this.http);
|
|
1480
|
+
this.stewards = new StewardApi(this.http);
|
|
1203
1481
|
this.webhooks = new WebhookApi(this.http);
|
|
1204
1482
|
}
|
|
1205
1483
|
};
|
|
@@ -1255,7 +1533,8 @@ function renderActionHelp(base, resource, action) {
|
|
|
1255
1533
|
...f.valueHint ? { valueHint: f.valueHint } : {},
|
|
1256
1534
|
required: f.required ?? false,
|
|
1257
1535
|
...f.enum ? { enum: f.enum } : {},
|
|
1258
|
-
...f.default !== void 0 ? { default: f.default } : {}
|
|
1536
|
+
...f.default !== void 0 ? { default: f.default } : {},
|
|
1537
|
+
...f.repeatable ? { repeatable: true } : {}
|
|
1259
1538
|
})),
|
|
1260
1539
|
examples: action.examples ?? [],
|
|
1261
1540
|
writes: action.writes ?? "none",
|
|
@@ -1396,6 +1675,16 @@ function validateArgs(resource, action, parsed, options = {}) {
|
|
|
1396
1675
|
hint: `${usageHint} (e.g. --${flag} ${valuePart})`
|
|
1397
1676
|
});
|
|
1398
1677
|
}
|
|
1678
|
+
for (const [name, values] of Object.entries(parsed.repeatedFlags)) {
|
|
1679
|
+
if (values.length < 2)
|
|
1680
|
+
continue;
|
|
1681
|
+
const spec = declaredFlags.find((f) => f.name === name);
|
|
1682
|
+
if (spec?.repeatable)
|
|
1683
|
+
continue;
|
|
1684
|
+
throw usage(`duplicate flag --${name} (given ${values.length} times; only the last value would be used)`, {
|
|
1685
|
+
hint: usageHint
|
|
1686
|
+
});
|
|
1687
|
+
}
|
|
1399
1688
|
for (const spec of declaredFlags) {
|
|
1400
1689
|
if (!spec.required)
|
|
1401
1690
|
continue;
|
|
@@ -1515,6 +1804,8 @@ function resolveToken(flags, env, context, baseUrl, saved, options) {
|
|
|
1515
1804
|
return { token: explicitToken, tokenSource: "flag" };
|
|
1516
1805
|
if (!options.excludeTaskToken && env.MORULA_TASK_TOKEN)
|
|
1517
1806
|
return { token: env.MORULA_TASK_TOKEN, tokenSource: "env:MORULA_TASK_TOKEN" };
|
|
1807
|
+
if (!options.excludeTaskToken && env.MORULA_SESSION_TOKEN)
|
|
1808
|
+
return { token: env.MORULA_SESSION_TOKEN, tokenSource: "env:MORULA_SESSION_TOKEN" };
|
|
1518
1809
|
if (env.MORULA_TOKEN)
|
|
1519
1810
|
return { token: env.MORULA_TOKEN, tokenSource: "env:MORULA_TOKEN" };
|
|
1520
1811
|
const savedToken = saved?.url && normalizeBaseUrl(saved.url) === baseUrl ? saved.token : void 0;
|
|
@@ -1627,6 +1918,10 @@ async function run(argv, deps = {}) {
|
|
|
1627
1918
|
code: error.code,
|
|
1628
1919
|
message: error.message,
|
|
1629
1920
|
...error.retryable ? { retryable: true } : {},
|
|
1921
|
+
// 服务端业务错误码(如 SESSION_SCOPE_DENIED):`code` 是按 HTTP 状态派生的粗档位,
|
|
1922
|
+
// 行为契约要判断的是业务码——不打印出来,契约就永远不可执行
|
|
1923
|
+
// (issues/api-client-drops-business-error-code.md)。退出码仍由 `error.exitCode` 决定。
|
|
1924
|
+
...error instanceof MorulaApiError && error.errorCode ? { errorCode: error.errorCode } : {},
|
|
1630
1925
|
// 新增字段(可选):可执行的下一步 + typo 建议
|
|
1631
1926
|
...error instanceof CliError && error.hint ? { hint: error.hint } : {},
|
|
1632
1927
|
...error instanceof CliError && error.didYouMean ? { didYouMean: error.didYouMean } : {}
|
|
@@ -1838,6 +2133,13 @@ async function attachmentCommand(context) {
|
|
|
1838
2133
|
rejectUnknownFlags(flags, []);
|
|
1839
2134
|
return context.client.attachments.get(requireId(positionals, "attachment get"));
|
|
1840
2135
|
}
|
|
2136
|
+
if (action === "content") {
|
|
2137
|
+
rejectUnknownFlags(flags, ["max-chars"]);
|
|
2138
|
+
return context.client.attachments.content(
|
|
2139
|
+
requireId(positionals, "attachment content"),
|
|
2140
|
+
flagNumber(flags, "max-chars")
|
|
2141
|
+
);
|
|
2142
|
+
}
|
|
1841
2143
|
if (action === "download-url") {
|
|
1842
2144
|
rejectUnknownFlags(flags, []);
|
|
1843
2145
|
return context.client.attachments.getDownloadUrl(requireId(positionals, "attachment download-url"));
|
|
@@ -1855,6 +2157,198 @@ function requireId(positionals, command) {
|
|
|
1855
2157
|
return id;
|
|
1856
2158
|
}
|
|
1857
2159
|
|
|
2160
|
+
// ../morula-cli/src/commands/autopilot.ts
|
|
2161
|
+
async function autopilotCommand(context) {
|
|
2162
|
+
if (!context.runtime.token)
|
|
2163
|
+
throw new CliError("UNAUTHENTICATED", EXIT.UNAUTHENTICATED, "\u8BF7\u5148\u8FD0\u884C morula auth login");
|
|
2164
|
+
const { action, flags } = context.parsed;
|
|
2165
|
+
if (action === "list") {
|
|
2166
|
+
rejectUnknownFlags(flags, ["space", "page", "page-size"]);
|
|
2167
|
+
return context.client.autopilots.list({
|
|
2168
|
+
spaceId: flagString(flags, "space"),
|
|
2169
|
+
page: flagNumber(flags, "page"),
|
|
2170
|
+
pageSize: flagNumber(flags, "page-size")
|
|
2171
|
+
});
|
|
2172
|
+
}
|
|
2173
|
+
if (action === "create") {
|
|
2174
|
+
rejectUnknownFlags(flags, ["space", "name", "runbook", "executor", "description", "cron", "vcs-connection"]);
|
|
2175
|
+
const spaceId = requireFlag(flags, "space");
|
|
2176
|
+
const name = requireFlag(flags, "name");
|
|
2177
|
+
const runbook = requireFlag(flags, "runbook");
|
|
2178
|
+
const executorKey = requireFlag(flags, "executor");
|
|
2179
|
+
const description = flagString(flags, "description");
|
|
2180
|
+
const cronExpr = flagString(flags, "cron");
|
|
2181
|
+
const vcsConnectionId = flagString(flags, "vcs-connection");
|
|
2182
|
+
return context.client.autopilots.create({
|
|
2183
|
+
spaceId,
|
|
2184
|
+
name,
|
|
2185
|
+
runbook,
|
|
2186
|
+
executorKey,
|
|
2187
|
+
...description !== void 0 ? { description } : {},
|
|
2188
|
+
...cronExpr !== void 0 ? { cronExpr } : {},
|
|
2189
|
+
...vcsConnectionId !== void 0 ? { vcsConnectionId } : {}
|
|
2190
|
+
});
|
|
2191
|
+
}
|
|
2192
|
+
throw usage("usage: morula autopilot <list|create>");
|
|
2193
|
+
}
|
|
2194
|
+
|
|
2195
|
+
// ../morula-cli/src/commands/ci.ts
|
|
2196
|
+
async function ciCommand(context) {
|
|
2197
|
+
if (!context.runtime.token)
|
|
2198
|
+
throw new CliError("UNAUTHENTICATED", EXIT.UNAUTHENTICATED, "\u8BF7\u5148\u8FD0\u884C morula auth login");
|
|
2199
|
+
const { action } = context.parsed;
|
|
2200
|
+
if (action === "status")
|
|
2201
|
+
return ciStatus(context);
|
|
2202
|
+
if (action === "log")
|
|
2203
|
+
return ciLog(context);
|
|
2204
|
+
if (action === "deployments")
|
|
2205
|
+
return ciDeployments(context);
|
|
2206
|
+
if (action === "test-report")
|
|
2207
|
+
return ciTestReport(context);
|
|
2208
|
+
if (action === "retry")
|
|
2209
|
+
return ciRetry(context);
|
|
2210
|
+
throw usage("usage: morula ci <status|log|deployments|test-report|retry>");
|
|
2211
|
+
}
|
|
2212
|
+
async function ciStatus(context) {
|
|
2213
|
+
const { positionals, flags } = context.parsed;
|
|
2214
|
+
rejectUnknownFlags(flags, ["space", "repo", "ref", "failed", "limit"]);
|
|
2215
|
+
const repo = flagString(flags, "repo");
|
|
2216
|
+
const ref = flagString(flags, "ref");
|
|
2217
|
+
const failed = flagBoolean(flags, "failed");
|
|
2218
|
+
const limit = flagNumber(flags, "limit");
|
|
2219
|
+
if (limit != null && (!Number.isInteger(limit) || limit <= 0))
|
|
2220
|
+
throw usage("--limit \u5FC5\u987B\u662F\u6B63\u6574\u6570");
|
|
2221
|
+
const face = resolveFace(context, "usage: morula ci status <taskId> [--repo <owner/name>] [--limit <n>] | morula ci status --space <spaceId> [--ref <branch>] [--failed] [--limit <n>]");
|
|
2222
|
+
if (face.kind === "space") {
|
|
2223
|
+
if (repo)
|
|
2224
|
+
throw usage("--repo \u53EA\u5728\u4EFB\u52A1\u9762\u53EF\u7528\uFF1A\u7A7A\u95F4\u9762\u8BF7\u7528 --ref \u8FC7\u6EE4\u5206\u652F\uFF08\u670D\u52A1\u7AEF\u4E0D\u652F\u6301\u6309\u4ED3\u5E93\u8FC7\u6EE4\uFF09");
|
|
2225
|
+
const result2 = await context.client.ci.spaceView(face.spaceId, {
|
|
2226
|
+
...ref ? { ref } : {},
|
|
2227
|
+
...failed ? { failed: true } : {},
|
|
2228
|
+
...limit ? { limit } : {}
|
|
2229
|
+
});
|
|
2230
|
+
if (result2.ok === false)
|
|
2231
|
+
throw ciFailure(result2);
|
|
2232
|
+
return result2;
|
|
2233
|
+
}
|
|
2234
|
+
const result = await context.client.ci.taskView(face.taskId, { ...limit ? { limit } : {} });
|
|
2235
|
+
if (result.ok === false)
|
|
2236
|
+
throw ciFailure(result);
|
|
2237
|
+
if (!repo)
|
|
2238
|
+
return result;
|
|
2239
|
+
const runs = result.runs.filter((run2) => run2.repoFullName === repo);
|
|
2240
|
+
return { ...result, runs, repoFilter: { repo, total: result.runs.length, matched: runs.length } };
|
|
2241
|
+
}
|
|
2242
|
+
async function ciLog(context) {
|
|
2243
|
+
const { flags } = context.parsed;
|
|
2244
|
+
rejectUnknownFlags(flags, ["space", "job", "tail"]);
|
|
2245
|
+
const jobId = flagString(flags, "job");
|
|
2246
|
+
if (!jobId)
|
|
2247
|
+
throw usage("usage: morula ci log <taskId> --job <jobId> [--tail <n>] | morula ci log --space <spaceId> --job <jobId> [--tail <n>]");
|
|
2248
|
+
const tail = flagNumber(flags, "tail");
|
|
2249
|
+
if (tail != null && (!Number.isInteger(tail) || tail <= 0))
|
|
2250
|
+
throw usage("--tail \u5FC5\u987B\u662F\u6B63\u6574\u6570\uFF08\u4FDD\u7559\u7684\u65E5\u5FD7\u5C3E\u90E8\u5B57\u8282\u6570\uFF09");
|
|
2251
|
+
resolveFace(context, "usage: morula ci log <taskId> --job <jobId> [--tail <n>] | morula ci log --space <spaceId> --job <jobId> [--tail <n>]");
|
|
2252
|
+
const result = await context.client.ci.jobLog(jobId, { ...tail ? { tail } : {} });
|
|
2253
|
+
if (result.ok === false)
|
|
2254
|
+
throw ciFailure(result);
|
|
2255
|
+
return result;
|
|
2256
|
+
}
|
|
2257
|
+
async function ciDeployments(context) {
|
|
2258
|
+
const { flags } = context.parsed;
|
|
2259
|
+
rejectUnknownFlags(flags, ["space"]);
|
|
2260
|
+
const face = resolveFace(context, "usage: morula ci deployments <taskId> | morula ci deployments --space <spaceId>");
|
|
2261
|
+
const result = face.kind === "space" ? await context.client.ci.spaceDeployments(face.spaceId) : await context.client.ci.taskDeployments(face.taskId);
|
|
2262
|
+
if (result.ok === false)
|
|
2263
|
+
throw ciFailure(result);
|
|
2264
|
+
return result;
|
|
2265
|
+
}
|
|
2266
|
+
async function ciTestReport(context) {
|
|
2267
|
+
const { flags } = context.parsed;
|
|
2268
|
+
rejectUnknownFlags(flags, ["space", "run"]);
|
|
2269
|
+
const runFlag = flagString(flags, "run");
|
|
2270
|
+
const face = resolveFace(context, "usage: morula ci test-report <taskId> [--run <runId>] | morula ci test-report --space <spaceId> [--run <runId>]");
|
|
2271
|
+
let runId = runFlag;
|
|
2272
|
+
if (!runId) {
|
|
2273
|
+
const view = face.kind === "space" ? await context.client.ci.spaceView(face.spaceId) : await context.client.ci.taskView(face.taskId);
|
|
2274
|
+
if (view.ok === false)
|
|
2275
|
+
throw ciFailure(view);
|
|
2276
|
+
runId = view.runs[0]?.id;
|
|
2277
|
+
if (!runId) {
|
|
2278
|
+
throw new CliError(
|
|
2279
|
+
"CI_RUN_NOT_FOUND",
|
|
2280
|
+
EXIT.NOT_FOUND,
|
|
2281
|
+
face.kind === "space" ? "\u8BE5\u7A7A\u95F4\u6CA1\u6709\u6D41\u6C34\u7EBF\u8FD0\u884C\u8BB0\u5F55\uFF0C\u53D6\u4E0D\u5230\u5931\u8D25\u7528\u4F8B\u6E05\u5355\uFF08\u53EF\u5148\u7528 morula ci status --space <id> \u786E\u8BA4\uFF09" : "\u672C\u4EFB\u52A1\u6CA1\u6709\u6D41\u6C34\u7EBF\u8FD0\u884C\u8BB0\u5F55\uFF0C\u53D6\u4E0D\u5230\u5931\u8D25\u7528\u4F8B\u6E05\u5355\uFF08\u53EF\u5148\u7528 morula ci status <taskId> \u786E\u8BA4\uFF09"
|
|
2282
|
+
);
|
|
2283
|
+
}
|
|
2284
|
+
}
|
|
2285
|
+
const result = await context.client.ci.testReport(runId);
|
|
2286
|
+
if (result.ok === false)
|
|
2287
|
+
throw ciFailure(result);
|
|
2288
|
+
return result;
|
|
2289
|
+
}
|
|
2290
|
+
async function ciRetry(context) {
|
|
2291
|
+
const { positionals, flags } = context.parsed;
|
|
2292
|
+
rejectUnknownFlags(flags, ["space", "run", "job"]);
|
|
2293
|
+
const usageHint = "usage: morula ci retry --space <spaceId> [--run <runId>] [--job <jobId>]";
|
|
2294
|
+
if (positionals.length)
|
|
2295
|
+
throw usage(`\u91CD\u8DD1\u53EA\u5728\u7A7A\u95F4\u9762\u5F00\u653E\uFF1A\u8BF7\u7528 --space <spaceId>\uFF08\u4EFB\u52A1\u9762\u4E0D\u63D0\u4F9B retry\uFF09\u3002${usageHint}`);
|
|
2296
|
+
const runId = flagString(flags, "run");
|
|
2297
|
+
const jobId = flagString(flags, "job");
|
|
2298
|
+
if (runId && jobId)
|
|
2299
|
+
throw usage(`--run \u4E0E --job \u4E92\u65A5\uFF0C\u53EA\u80FD\u7ED9\u4E00\u4E2A\uFF08${usageHint}\uFF09`);
|
|
2300
|
+
const spaceId = flagString(flags, "space");
|
|
2301
|
+
if (!spaceId)
|
|
2302
|
+
throw usage(usageHint);
|
|
2303
|
+
if (jobId) {
|
|
2304
|
+
const result2 = await context.client.ci.retryJob(jobId);
|
|
2305
|
+
if (result2.ok === false)
|
|
2306
|
+
throw ciFailure(result2, "\u64CD\u4F5C");
|
|
2307
|
+
return result2;
|
|
2308
|
+
}
|
|
2309
|
+
let targetRunId = runId;
|
|
2310
|
+
if (!targetRunId) {
|
|
2311
|
+
const view = await context.client.ci.spaceView(spaceId, { failed: true });
|
|
2312
|
+
if (view.ok === false)
|
|
2313
|
+
throw ciFailure(view);
|
|
2314
|
+
targetRunId = view.runs[0]?.id;
|
|
2315
|
+
if (!targetRunId) {
|
|
2316
|
+
throw new CliError(
|
|
2317
|
+
"CI_RUN_NOT_FOUND",
|
|
2318
|
+
EXIT.NOT_FOUND,
|
|
2319
|
+
`\u7A7A\u95F4 ${spaceId} \u6CA1\u6709\u5931\u8D25\u7684\u6D41\u6C34\u7EBF\u8FD0\u884C\u53EF\u91CD\u8DD1\uFF08\u53EF\u5148\u7528 morula ci status --space ${spaceId} --failed \u786E\u8BA4\uFF09`
|
|
2320
|
+
);
|
|
2321
|
+
}
|
|
2322
|
+
}
|
|
2323
|
+
const result = await context.client.ci.retryRun(targetRunId);
|
|
2324
|
+
if (result.ok === false)
|
|
2325
|
+
throw ciFailure(result, "\u64CD\u4F5C");
|
|
2326
|
+
return result;
|
|
2327
|
+
}
|
|
2328
|
+
function resolveFace(context, usageHint) {
|
|
2329
|
+
const taskId = context.parsed.positionals[0]?.trim();
|
|
2330
|
+
const spaceId = flagString(context.parsed.flags, "space");
|
|
2331
|
+
if (taskId && spaceId)
|
|
2332
|
+
throw usage(`<taskId> \u4E0E --space \u4E92\u65A5\uFF0C\u53EA\u80FD\u7ED9\u4E00\u4E2A\uFF08${usageHint}\uFF09`);
|
|
2333
|
+
if (!taskId && !spaceId)
|
|
2334
|
+
throw usage(usageHint);
|
|
2335
|
+
return taskId ? { kind: "task", taskId } : { kind: "space", spaceId };
|
|
2336
|
+
}
|
|
2337
|
+
function ciFailure(failure, verb = "\u67E5\u8BE2") {
|
|
2338
|
+
return new CliError(
|
|
2339
|
+
failure.code,
|
|
2340
|
+
exitForCiCode(failure.code),
|
|
2341
|
+
`CI ${verb}\u5931\u8D25: ${failure.message || "\u672A\u77E5\u539F\u56E0"}\uFF08${failure.code}\uFF09`
|
|
2342
|
+
);
|
|
2343
|
+
}
|
|
2344
|
+
function exitForCiCode(code) {
|
|
2345
|
+
if (code === "CI_RETRY_NOT_ALLOWED" || code === "CI_JOB_NOT_MANUAL")
|
|
2346
|
+
return EXIT.CONFLICT;
|
|
2347
|
+
if (code === "CI_JOB_NOT_FOUND" || code === "CI_RUN_NOT_FOUND" || code === "TASK_NOT_FOUND" || code === "OBJECT_NOT_FOUND")
|
|
2348
|
+
return EXIT.NOT_FOUND;
|
|
2349
|
+
return EXIT.OTHER;
|
|
2350
|
+
}
|
|
2351
|
+
|
|
1858
2352
|
// ../morula-cli/src/commands/comment.ts
|
|
1859
2353
|
function detectCommentFormat(text) {
|
|
1860
2354
|
if (!text)
|
|
@@ -1888,16 +2382,19 @@ async function commentCommand(context) {
|
|
|
1888
2382
|
return context.client.comments.get(id);
|
|
1889
2383
|
}
|
|
1890
2384
|
if (action === "add") {
|
|
1891
|
-
rejectUnknownFlags(flags, ["object", "content", "parent", "format"]);
|
|
2385
|
+
rejectUnknownFlags(flags, ["object", "content", "parent", "format", "mention"]);
|
|
1892
2386
|
const objectId = requireFlag(flags, "object");
|
|
1893
2387
|
const content = requireFlag(flags, "content");
|
|
1894
2388
|
const formatFlag = flagString(flags, "format");
|
|
1895
2389
|
const format = formatFlag === "markdown" || formatFlag === "plain" || formatFlag === "richtext" ? formatFlag : detectCommentFormat(content);
|
|
2390
|
+
const mentions = parseMentions(flagStrings(context.parsed, "mention"));
|
|
1896
2391
|
const input = compact({
|
|
1897
2392
|
objectId,
|
|
1898
2393
|
content,
|
|
1899
2394
|
parentCommentId: flagString(flags, "parent"),
|
|
1900
|
-
contentFormat: format
|
|
2395
|
+
contentFormat: format,
|
|
2396
|
+
// 无 --mention 时**不带** mentions 字段(服务端按缺省处理,不发任何通知)
|
|
2397
|
+
...mentions.length ? { mentions } : {}
|
|
1901
2398
|
});
|
|
1902
2399
|
return context.client.comments.create(input);
|
|
1903
2400
|
}
|
|
@@ -1923,6 +2420,89 @@ async function commentCommand(context) {
|
|
|
1923
2420
|
function compact(value) {
|
|
1924
2421
|
return Object.fromEntries(Object.entries(value).filter(([, item]) => item !== void 0));
|
|
1925
2422
|
}
|
|
2423
|
+
function parseMentions(rawValues) {
|
|
2424
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2425
|
+
const mentions = [];
|
|
2426
|
+
for (const raw of rawValues) {
|
|
2427
|
+
for (const part of raw.split(",")) {
|
|
2428
|
+
const principalId = part.trim();
|
|
2429
|
+
if (!principalId || seen.has(principalId))
|
|
2430
|
+
continue;
|
|
2431
|
+
seen.add(principalId);
|
|
2432
|
+
mentions.push({ type: "member", principalId });
|
|
2433
|
+
}
|
|
2434
|
+
}
|
|
2435
|
+
return mentions;
|
|
2436
|
+
}
|
|
2437
|
+
|
|
2438
|
+
// ../morula-cli/src/commands/dashboard.ts
|
|
2439
|
+
async function dashboardCommand(context) {
|
|
2440
|
+
if (!context.runtime.token)
|
|
2441
|
+
throw new CliError("UNAUTHENTICATED", EXIT.UNAUTHENTICATED, "\u8BF7\u5148\u8FD0\u884C morula auth login");
|
|
2442
|
+
const { action, flags } = context.parsed;
|
|
2443
|
+
if (action === "get") {
|
|
2444
|
+
rejectUnknownFlags(flags, ["space"]);
|
|
2445
|
+
return context.client.dashboard.get(requireFlag(flags, "space"));
|
|
2446
|
+
}
|
|
2447
|
+
if (action === "statistics") {
|
|
2448
|
+
rejectUnknownFlags(flags, ["space"]);
|
|
2449
|
+
return context.client.dashboard.statistics(requireFlag(flags, "space"));
|
|
2450
|
+
}
|
|
2451
|
+
if (action === "workload") {
|
|
2452
|
+
rejectUnknownFlags(flags, ["space"]);
|
|
2453
|
+
return context.client.dashboard.workload(requireFlag(flags, "space"));
|
|
2454
|
+
}
|
|
2455
|
+
throw usage("usage: morula dashboard <get|statistics|workload>");
|
|
2456
|
+
}
|
|
2457
|
+
|
|
2458
|
+
// ../morula-cli/src/commands/document.ts
|
|
2459
|
+
async function documentCommand(context) {
|
|
2460
|
+
if (!context.runtime.token)
|
|
2461
|
+
throw new CliError("UNAUTHENTICATED", EXIT.UNAUTHENTICATED, "\u8BF7\u5148\u8FD0\u884C morula auth login");
|
|
2462
|
+
const { action, positionals, flags } = context.parsed;
|
|
2463
|
+
if (action === "list") {
|
|
2464
|
+
rejectUnknownFlags(flags, ["page", "page-size"]);
|
|
2465
|
+
return context.client.documents.list({
|
|
2466
|
+
page: flagNumber(flags, "page"),
|
|
2467
|
+
pageSize: flagNumber(flags, "page-size")
|
|
2468
|
+
});
|
|
2469
|
+
}
|
|
2470
|
+
if (action === "get") {
|
|
2471
|
+
rejectUnknownFlags(flags, []);
|
|
2472
|
+
return context.client.documents.get(requireId2(positionals, "document get"));
|
|
2473
|
+
}
|
|
2474
|
+
if (action === "artifacts") {
|
|
2475
|
+
rejectUnknownFlags(flags, []);
|
|
2476
|
+
return context.client.documents.artifacts(requireId2(positionals, "document artifacts"));
|
|
2477
|
+
}
|
|
2478
|
+
throw usage("usage: morula document <list|get|artifacts>");
|
|
2479
|
+
}
|
|
2480
|
+
function requireId2(positionals, command) {
|
|
2481
|
+
const id = positionals[0]?.trim();
|
|
2482
|
+
if (!id)
|
|
2483
|
+
throw usage(`usage: morula ${command} <id>`);
|
|
2484
|
+
return id;
|
|
2485
|
+
}
|
|
2486
|
+
|
|
2487
|
+
// ../morula-cli/src/commands/object-meta.ts
|
|
2488
|
+
async function objectMetaCommand(context) {
|
|
2489
|
+
if (!context.runtime.token)
|
|
2490
|
+
throw new CliError("UNAUTHENTICATED", EXIT.UNAUTHENTICATED, "\u8BF7\u5148\u8FD0\u884C morula auth login");
|
|
2491
|
+
const { action, flags } = context.parsed;
|
|
2492
|
+
if (action === "get") {
|
|
2493
|
+
rejectUnknownFlags(flags, ["object"]);
|
|
2494
|
+
return context.client.objectMeta.list(requireFlag(flags, "object"));
|
|
2495
|
+
}
|
|
2496
|
+
if (action === "set") {
|
|
2497
|
+
rejectUnknownFlags(flags, ["object", "key", "value"]);
|
|
2498
|
+
return context.client.objectMeta.set(
|
|
2499
|
+
requireFlag(flags, "object"),
|
|
2500
|
+
requireFlag(flags, "key"),
|
|
2501
|
+
requireFlag(flags, "value")
|
|
2502
|
+
);
|
|
2503
|
+
}
|
|
2504
|
+
throw usage("usage: morula object-meta <get|set>");
|
|
2505
|
+
}
|
|
1926
2506
|
|
|
1927
2507
|
// ../morula-cli/src/commands/repo.ts
|
|
1928
2508
|
import { execFileSync } from "node:child_process";
|
|
@@ -2000,7 +2580,30 @@ async function repoCommand(context) {
|
|
|
2000
2580
|
if (action === "mr" && positionals[0] === "diff") {
|
|
2001
2581
|
return mrDiff(context, flags);
|
|
2002
2582
|
}
|
|
2003
|
-
|
|
2583
|
+
if (action === "files") {
|
|
2584
|
+
rejectUnknownFlags(flags, ["space", "repo", "path", "ref"]);
|
|
2585
|
+
const spaceId = flagString(flags, "space");
|
|
2586
|
+
if (!spaceId)
|
|
2587
|
+
throw usage("usage: morula repo files --space <id> [--repo <owner/name>] [--path <p>] [--ref <r>]");
|
|
2588
|
+
return context.client.repos.files(spaceId, {
|
|
2589
|
+
repo: flagString(flags, "repo"),
|
|
2590
|
+
path: flagString(flags, "path"),
|
|
2591
|
+
ref: flagString(flags, "ref")
|
|
2592
|
+
});
|
|
2593
|
+
}
|
|
2594
|
+
if (action === "read") {
|
|
2595
|
+
rejectUnknownFlags(flags, ["space", "repo", "path", "ref"]);
|
|
2596
|
+
const spaceId = flagString(flags, "space");
|
|
2597
|
+
const path = flagString(flags, "path");
|
|
2598
|
+
if (!spaceId || !path)
|
|
2599
|
+
throw usage("usage: morula repo read --space <id> --path <p> [--repo <owner/name>] [--ref <r>]");
|
|
2600
|
+
return context.client.repos.read(spaceId, {
|
|
2601
|
+
path,
|
|
2602
|
+
repo: flagString(flags, "repo"),
|
|
2603
|
+
ref: flagString(flags, "ref")
|
|
2604
|
+
});
|
|
2605
|
+
}
|
|
2606
|
+
throw usage("usage: morula repo <list|checkout|prepare|files|read|mr create|mr list|mr comment|mr get|mr diff>");
|
|
2004
2607
|
}
|
|
2005
2608
|
function resolveMrBase(flagBase, env = process.env) {
|
|
2006
2609
|
return env.MORULA_BASE_BRANCH?.trim() || flagBase?.trim() || "main";
|
|
@@ -2114,7 +2717,7 @@ async function mrCreateViaPushOptions(input) {
|
|
|
2114
2717
|
const list = listRes.ok ? await listRes.json().catch(() => null) : null;
|
|
2115
2718
|
const existing = Array.isArray(list) ? list[0] : null;
|
|
2116
2719
|
if (existing?.iid) {
|
|
2117
|
-
|
|
2720
|
+
process.stderr.write("[morula-cli] mr create \u5206\u652F\u5DF2\u6709 opened MR\uFF0C\u590D\u7528\u73B0\u6709 MR\n");
|
|
2118
2721
|
return { ok: true, repoFullName, branch, base, taskCode, title, mrUrl: existing.web_url ?? `${gitlabBase}/${repoFullName}/-/merge_requests/${existing.iid}` };
|
|
2119
2722
|
}
|
|
2120
2723
|
if (listRes.ok) {
|
|
@@ -2499,7 +3102,901 @@ async function spaceCommand(context) {
|
|
|
2499
3102
|
throw usage("usage: morula space get <id>");
|
|
2500
3103
|
return context.client.spaces.get(id);
|
|
2501
3104
|
}
|
|
2502
|
-
|
|
3105
|
+
if (action === "create") {
|
|
3106
|
+
rejectUnknownFlags(flags, ["name", "description", "code", "visibility"]);
|
|
3107
|
+
return context.client.spaces.create({
|
|
3108
|
+
name: requireFlag(flags, "name"),
|
|
3109
|
+
description: flagString(flags, "description"),
|
|
3110
|
+
code: flagString(flags, "code"),
|
|
3111
|
+
visibility: flagString(flags, "visibility")
|
|
3112
|
+
});
|
|
3113
|
+
}
|
|
3114
|
+
if (action === "update") {
|
|
3115
|
+
rejectUnknownFlags(flags, ["name", "description", "visibility"]);
|
|
3116
|
+
const id = requireId3(positionals, "space update");
|
|
3117
|
+
const input = {
|
|
3118
|
+
name: flagString(flags, "name"),
|
|
3119
|
+
description: flagString(flags, "description"),
|
|
3120
|
+
visibility: flagString(flags, "visibility")
|
|
3121
|
+
};
|
|
3122
|
+
if (Object.values(input).every((value) => value === void 0))
|
|
3123
|
+
throw usage("space update \u81F3\u5C11\u9700\u8981\u4E00\u4E2A\u5B57\u6BB5\u65D7\u6807\uFF08--name / --description / --visibility\uFF09");
|
|
3124
|
+
return context.client.spaces.update(id, input);
|
|
3125
|
+
}
|
|
3126
|
+
if (action === "delete") {
|
|
3127
|
+
rejectUnknownFlags(flags, []);
|
|
3128
|
+
return context.client.spaces.delete(requireId3(positionals, "space delete"));
|
|
3129
|
+
}
|
|
3130
|
+
throw usage("usage: morula space <list|get|create|update|delete>");
|
|
3131
|
+
}
|
|
3132
|
+
function requireId3(positionals, command) {
|
|
3133
|
+
const id = positionals[0]?.trim();
|
|
3134
|
+
if (!id)
|
|
3135
|
+
throw usage(`usage: morula ${command} <id>`);
|
|
3136
|
+
return id;
|
|
3137
|
+
}
|
|
3138
|
+
|
|
3139
|
+
// ../morula-cli/src/commands/spec.ts
|
|
3140
|
+
var SPEC = {
|
|
3141
|
+
name: "morula",
|
|
3142
|
+
summary: "Agent-first CLI for Morula task management (plugin surface, injected into task workspaces). Success output is JSON on stdout; errors are JSON on stderr.",
|
|
3143
|
+
resources: [
|
|
3144
|
+
{
|
|
3145
|
+
resource: "auth",
|
|
3146
|
+
summary: "SkyDoor authentication (shared config with morula-runtime)",
|
|
3147
|
+
actions: [
|
|
3148
|
+
{
|
|
3149
|
+
action: "login",
|
|
3150
|
+
summary: "browser SkyDoor SSO using PKCE and loopback callback (writes ~/.morula-cli/config.yaml)",
|
|
3151
|
+
flags: [{ name: "url", type: "string", valueHint: "<baseUrl>", description: "server base URL to log in to" }],
|
|
3152
|
+
examples: ["morula auth login"],
|
|
3153
|
+
writes: "local",
|
|
3154
|
+
interactive: true,
|
|
3155
|
+
emits: ["loggedIn", "context", "baseUrl", "expiresIn"]
|
|
3156
|
+
},
|
|
3157
|
+
{
|
|
3158
|
+
action: "logout",
|
|
3159
|
+
summary: "remove the current context token",
|
|
3160
|
+
flags: [],
|
|
3161
|
+
examples: ["morula auth logout"],
|
|
3162
|
+
writes: "local",
|
|
3163
|
+
idempotent: true,
|
|
3164
|
+
emits: ["loggedIn", "context"]
|
|
3165
|
+
},
|
|
3166
|
+
{
|
|
3167
|
+
action: "status",
|
|
3168
|
+
summary: "show context, endpoint, and authentication state",
|
|
3169
|
+
flags: [],
|
|
3170
|
+
examples: ["morula auth status"],
|
|
3171
|
+
writes: "none",
|
|
3172
|
+
idempotent: true,
|
|
3173
|
+
emits: ["loggedIn", "context", "baseUrl", "user", "expired"]
|
|
3174
|
+
}
|
|
3175
|
+
]
|
|
3176
|
+
},
|
|
3177
|
+
{
|
|
3178
|
+
resource: "task",
|
|
3179
|
+
summary: "task (business Object) read/write + AgentTask machine protocol (branch/state/analysis-verdict/inbox)",
|
|
3180
|
+
actions: [
|
|
3181
|
+
{
|
|
3182
|
+
action: "list",
|
|
3183
|
+
summary: "list tasks (--mine: \u4EC5\u6211\u8D1F\u8D23\u7684\uFF1B--field key=value \u81EA\u5B9A\u4E49\u5B57\u6BB5\u7B5B\u9009\uFF0C\u9700 --space)",
|
|
3184
|
+
flags: [
|
|
3185
|
+
{ name: "space", type: "string", valueHint: "<id>", description: "space id" },
|
|
3186
|
+
{ name: "mine", type: "boolean", description: "\u4EC5\u6211\u8D1F\u8D23\u7684\uFF08\u4E0E --assignee \u4E92\u65A5\uFF09" },
|
|
3187
|
+
{ name: "assignee", type: "string", valueHint: "<principalId>", description: "\u6309\u8D1F\u8D23\u4EBA\u8FC7\u6EE4" },
|
|
3188
|
+
{ name: "principal", type: "string", valueHint: "<id>", description: "\u6309\u521B\u5EFA\u4EBA\u8FC7\u6EE4" },
|
|
3189
|
+
{ name: "page", type: "number", valueHint: "<n>", description: "\u9875\u7801" },
|
|
3190
|
+
{ name: "page-size", type: "number", valueHint: "<n>", description: "\u6BCF\u9875\u6761\u6570" },
|
|
3191
|
+
{ name: "search", type: "string", valueHint: "<text>", description: "\u5173\u952E\u8BCD\u641C\u7D22" },
|
|
3192
|
+
{ name: "priority", type: "string", valueHint: "<low|medium|high|urgent>", description: "\u4F18\u5148\u7EA7\u8FC7\u6EE4" },
|
|
3193
|
+
{ name: "state", type: "string", valueHint: "<id>", description: "\u72B6\u6001\u8FC7\u6EE4" },
|
|
3194
|
+
{ name: "sort", type: "string", valueHint: "<field>", description: "\u6392\u5E8F\u5B57\u6BB5" },
|
|
3195
|
+
{ name: "order", type: "string", valueHint: "<asc|desc>", description: "\u6392\u5E8F\u65B9\u5411" },
|
|
3196
|
+
{ name: "field", type: "string", valueHint: "key=value[,key=value]", description: "\u81EA\u5B9A\u4E49\u5B57\u6BB5\u7B49\u503C\u7B5B\u9009\uFF08\u591A\u6761\u4EF6 AND\uFF1B\u9700 --space \u89E3\u6790\u5B57\u6BB5\u6A21\u677F\uFF09" }
|
|
3197
|
+
],
|
|
3198
|
+
examples: ["morula task list --space <id>", "morula task list --mine", "morula task list --space <id> --field priority=p1"],
|
|
3199
|
+
writes: "none",
|
|
3200
|
+
idempotent: true
|
|
3201
|
+
},
|
|
3202
|
+
{
|
|
3203
|
+
action: "create",
|
|
3204
|
+
summary: "create task (\u5FC5\u586B --space/--title\uFF1B\u843D backlog \u7531\u670D\u52A1\u7AEF\u51B3\u5B9A\u521D\u59CB\u72B6\u6001)",
|
|
3205
|
+
flags: [
|
|
3206
|
+
{ name: "space", type: "string", valueHint: "<id>", description: "\u7A7A\u95F4 ID\uFF08\u5FC5\u586B\uFF09", required: true },
|
|
3207
|
+
{ name: "title", type: "string", valueHint: "<text>", description: "\u6807\u9898\uFF08\u5FC5\u586B\uFF09", required: true },
|
|
3208
|
+
{ name: "description", type: "string", valueHint: "<text>", description: "\u63CF\u8FF0\uFF08\u683C\u5F0F\u81EA\u52A8\u68C0\u6D4B\uFF09" },
|
|
3209
|
+
{ name: "priority", type: "string", valueHint: "<low|medium|high|urgent>", description: "\u4F18\u5148\u7EA7" },
|
|
3210
|
+
{ name: "state", type: "string", valueHint: "<id>", description: "\u521D\u59CB\u72B6\u6001\uFF08\u4E1A\u52A1 Object state id\uFF09" },
|
|
3211
|
+
{ name: "owner", type: "string", valueHint: "<principalId>", description: "\u8D1F\u8D23\u4EBA\uFF08\u4EC5\u521B\u5EFA\u65F6\uFF09" },
|
|
3212
|
+
{ name: "assignee", type: "string", valueHint: "<principalId>", description: "\u7ECF\u529E\u4EBA" },
|
|
3213
|
+
{ name: "visibility", type: "string", valueHint: "<value>", description: "\u53EF\u89C1\u6027" },
|
|
3214
|
+
{ name: "estimate-hours", type: "number", valueHint: "<n>", description: "\u9884\u4F30\u5DE5\u65F6" },
|
|
3215
|
+
{ name: "schema", type: "string", valueHint: "<id>", description: "\u5B57\u6BB5\u6A21\u677F" },
|
|
3216
|
+
{ name: "sort-order", type: "number", valueHint: "<n>", description: "\u6392\u5E8F\u53F7" },
|
|
3217
|
+
{ name: "field", type: "string", valueHint: "key=value[,key=value]", description: "\u81EA\u5B9A\u4E49\u5B57\u6BB5 upsert\uFF08\u521B\u5EFA\u540E\u5199\u5165\uFF09" }
|
|
3218
|
+
],
|
|
3219
|
+
examples: ["morula task create --space <id> --title <text>"],
|
|
3220
|
+
writes: "remote"
|
|
3221
|
+
},
|
|
3222
|
+
{
|
|
3223
|
+
action: "get",
|
|
3224
|
+
summary: "get task details. No argument = the current AgentTask (id resolved from MORULA_TASK_ID / .morula/checkout.json). With an id = the business Object (title/description)",
|
|
3225
|
+
args: [{ name: "objectId", required: false, description: "\u4E1A\u52A1\u4EFB\u52A1\uFF08Object\uFF09ID\uFF1B\u7701\u7565 = \u5F53\u524D AgentTask \u8BE6\u60C5" }],
|
|
3226
|
+
flags: [],
|
|
3227
|
+
examples: ["morula task get", "morula task get <objectId>"],
|
|
3228
|
+
writes: "none",
|
|
3229
|
+
idempotent: true
|
|
3230
|
+
},
|
|
3231
|
+
{
|
|
3232
|
+
action: "update",
|
|
3233
|
+
summary: "update task (--state here is the business Object state id, NOT the AgentTask state code \u2014 see `task state`)",
|
|
3234
|
+
args: [{ name: "id", required: true, description: "\u4EFB\u52A1\uFF08Object\uFF09ID" }],
|
|
3235
|
+
flags: [
|
|
3236
|
+
{ name: "title", type: "string", valueHint: "<text>", description: "\u6807\u9898" },
|
|
3237
|
+
{ name: "description", type: "string", valueHint: "<text>", description: "\u63CF\u8FF0" },
|
|
3238
|
+
{ name: "priority", type: "string", valueHint: "<low|medium|high|urgent>", description: "\u4F18\u5148\u7EA7" },
|
|
3239
|
+
{ name: "state", type: "string", valueHint: "<id>", description: "\u72B6\u6001\uFF08\u4E1A\u52A1 Object state id\uFF09" },
|
|
3240
|
+
{ name: "assignee", type: "string", valueHint: "<principalId>", description: "\u7ECF\u529E\u4EBA" },
|
|
3241
|
+
{ name: "visibility", type: "string", valueHint: "<value>", description: "\u53EF\u89C1\u6027" },
|
|
3242
|
+
{ name: "estimate-hours", type: "number", valueHint: "<n>", description: "\u9884\u4F30\u5DE5\u65F6" },
|
|
3243
|
+
{ name: "schema", type: "string", valueHint: "<id>", description: "\u5B57\u6BB5\u6A21\u677F" },
|
|
3244
|
+
{ name: "sort-order", type: "number", valueHint: "<n>", description: "\u6392\u5E8F\u53F7" },
|
|
3245
|
+
{ name: "field", type: "string", valueHint: "key=value[,key=value]", description: "\u81EA\u5B9A\u4E49\u5B57\u6BB5 upsert\uFF08\u7A7A value = \u6E05\u7A7A\uFF09" }
|
|
3246
|
+
],
|
|
3247
|
+
examples: ["morula task update <id> --title <text>"],
|
|
3248
|
+
writes: "remote"
|
|
3249
|
+
},
|
|
3250
|
+
{
|
|
3251
|
+
action: "delete",
|
|
3252
|
+
summary: "hard delete task",
|
|
3253
|
+
args: [{ name: "id", required: true, description: "\u4EFB\u52A1\uFF08Object\uFF09ID" }],
|
|
3254
|
+
flags: [],
|
|
3255
|
+
examples: ["morula task delete <id>"],
|
|
3256
|
+
writes: "remote"
|
|
3257
|
+
},
|
|
3258
|
+
{
|
|
3259
|
+
action: "branch",
|
|
3260
|
+
summary: "report the final branch name for an agent task (machine protocol; agent naming, runtimeId from env; --repo: secondary repo in a multi-repo task)",
|
|
3261
|
+
args: [{ name: "taskId", required: true, description: "\u672C\u4EFB\u52A1 AgentTask UUID\uFF08morula task get \u65E0\u53C2\u8FD4\u56DE\u7684 id\uFF09" }],
|
|
3262
|
+
flags: [
|
|
3263
|
+
{ name: "name", type: "string", valueHint: "<branch>", description: "\u5206\u652F\u540D\uFF08\u5FC5\u586B\uFF09", required: true },
|
|
3264
|
+
{ name: "repo", type: "string", valueHint: "<owner/name>", description: "\u6B21\u4ED3\u5E93\uFF08\u591A\u4ED3\u5E93\u4EFB\u52A1\u7684\u5206\u652F\u9010\u4ED3\u4E0A\u62A5\uFF09" }
|
|
3265
|
+
],
|
|
3266
|
+
examples: ["morula task branch <taskId> --name <type>/<code>-<slug>"],
|
|
3267
|
+
writes: "remote"
|
|
3268
|
+
},
|
|
3269
|
+
{
|
|
3270
|
+
action: "state",
|
|
3271
|
+
summary: "self-transition task state (machine protocol; agent drives todo\u2192in_progress\u2192review, runtimeId from env)",
|
|
3272
|
+
args: [{ name: "taskId", required: true, description: "\u672C\u4EFB\u52A1 AgentTask UUID" }],
|
|
3273
|
+
flags: [{ name: "state", type: "string", valueHint: "<in_progress|review>", description: "\u76EE\u6807\u72B6\u6001 code\uFF08\u5FC5\u586B\uFF09", required: true }],
|
|
3274
|
+
examples: ["morula task state <taskId> --state in_progress"],
|
|
3275
|
+
writes: "remote"
|
|
3276
|
+
},
|
|
3277
|
+
{
|
|
3278
|
+
action: "analysis-verdict",
|
|
3279
|
+
summary: "report the task-analysis verdict (machine protocol; ready \u2192 platform auto-starts development, blocked \u2192 task stays in analysis)",
|
|
3280
|
+
args: [{ name: "taskId", required: true, description: "\u672C\u4EFB\u52A1 AgentTask UUID" }],
|
|
3281
|
+
flags: [
|
|
3282
|
+
{ name: "verdict", type: "string", valueHint: "<ready|blocked>", enum: ["ready", "blocked"], description: "\u5206\u6790\u7ED3\u8BBA\uFF08\u5FC5\u586B\uFF1B\u4EC5\u4EFB\u52A1\u5206\u6790\u4EFB\u52A1\u53EF\u4E0A\u62A5\uFF09", required: true },
|
|
3283
|
+
{ name: "reason", type: "string", valueHint: "<text>", description: "blocked \u65F6\u7684\u963B\u585E/\u5F85\u6F84\u6E05\u539F\u56E0" }
|
|
3284
|
+
],
|
|
3285
|
+
examples: ["morula task analysis-verdict <taskId> --verdict ready"],
|
|
3286
|
+
writes: "remote"
|
|
3287
|
+
},
|
|
3288
|
+
{
|
|
3289
|
+
action: "inbox",
|
|
3290
|
+
summary: "checkpoint: pull this thread's unconsumed messages into the current turn (machine protocol; --peek reads without marking them consumed)",
|
|
3291
|
+
flags: [
|
|
3292
|
+
{ name: "peek", type: "boolean", description: "\u53EA\u8BFB\uFF0C\u4E0D\u6807\u8BB0\u6D88\u8D39" },
|
|
3293
|
+
{ name: "after-seq", type: "number", valueHint: "<n>", description: "\u4ECE\u8BE5 seq \u4E4B\u540E\u62C9\u53D6" }
|
|
3294
|
+
],
|
|
3295
|
+
examples: ["morula task inbox", "morula task inbox --peek"],
|
|
3296
|
+
writes: "remote"
|
|
3297
|
+
},
|
|
3298
|
+
{
|
|
3299
|
+
action: "agent-tasks",
|
|
3300
|
+
summary: "list the AgentTask executions of a business task (Object). AgentTask UUID \u2260 \u4E1A\u52A1\u4EFB\u52A1 id \u2014 cancel/rerun \u8981\u7684\u662F\u8FD9\u91CC\u7684 id",
|
|
3301
|
+
flags: [
|
|
3302
|
+
{ name: "object", type: "string", valueHint: "<objectId>", description: "\u4E1A\u52A1\u4EFB\u52A1\uFF08Object\uFF09ID\uFF08\u5FC5\u586B\uFF09", required: true },
|
|
3303
|
+
{ name: "status", type: "string", valueHint: "<queued|dispatched|running|awaiting_approval|completed|failed|cancelled>", description: "\u6309\u5355\u4E2A\u72B6\u6001\u8FC7\u6EE4\uFF08\u7F3A\u7701 = \u5168\u90E8\uFF1B\u670D\u52A1\u7AEF\u4E0D\u505A\u679A\u4E3E\u6821\u9A8C\uFF0C\u975E\u6CD5\u503C\u53EA\u8FD4\u56DE\u7A7A\uFF09" },
|
|
3304
|
+
{ name: "page", type: "number", valueHint: "<n>", description: "\u9875\u7801" },
|
|
3305
|
+
{ name: "page-size", type: "number", valueHint: "<n>", description: "\u6BCF\u9875\u6761\u6570\uFF08\u670D\u52A1\u7AEF\u7F3A\u7701 20\uFF09" }
|
|
3306
|
+
],
|
|
3307
|
+
examples: ["morula task agent-tasks --object <objectId>", "morula task agent-tasks --object <objectId> --status failed"],
|
|
3308
|
+
writes: "none",
|
|
3309
|
+
idempotent: true
|
|
3310
|
+
},
|
|
3311
|
+
{
|
|
3312
|
+
action: "cancel",
|
|
3313
|
+
summary: "cancel a running execution (POST /agent-tasks/:id/cancel). queued/dispatched/running/awaiting_approval/failed \u53EF\u53D6\u6D88\uFF1Bcompleted/cancelled \u4E0D\u53EF\uFF08409 CONFLICT\uFF09\uFF1B\u4EFB\u52A1\u4E0D\u5B58\u5728 404 NOT_FOUND\u3002\u6210\u529F\u8FD4\u56DE { ok: true }\u2014\u2014**\u975E\u96F6\u9000\u51FA\u5373\u672A\u53D6\u6D88**\uFF0C\u4E0D\u8981\u5411\u7528\u6237\u6C47\u62A5\u300C\u5DF2\u505C\u6389\u300D",
|
|
3314
|
+
args: [{ name: "taskId", required: true, description: "AgentTask UUID\uFF08\u6765\u81EA morula task agent-tasks\uFF09" }],
|
|
3315
|
+
flags: [],
|
|
3316
|
+
examples: ["morula task cancel <taskId>"],
|
|
3317
|
+
writes: "remote"
|
|
3318
|
+
},
|
|
3319
|
+
{
|
|
3320
|
+
action: "rerun",
|
|
3321
|
+
summary: "rerun a failed/cancelled execution (POST /agent-tasks/:id/rerun; copies the task and re-queues it \u2192 returns a NEW taskId). \u4EC5 failed/cancelled \u53EF\u91CD\u8DD1\uFF0C\u5176\u4ED6\u72B6\u6001 ok:false + code CONFLICT\uFF1B10s \u5185\u5DF2\u6709\u6D3B\u8DC3\u91CD\u8DD1\u4E3A ALREADY_QUEUED",
|
|
3322
|
+
args: [{ name: "taskId", required: true, description: "AgentTask UUID\uFF08\u6765\u81EA morula task agent-tasks\uFF09" }],
|
|
3323
|
+
flags: [],
|
|
3324
|
+
examples: ["morula task rerun <taskId>"],
|
|
3325
|
+
writes: "remote"
|
|
3326
|
+
}
|
|
3327
|
+
]
|
|
3328
|
+
},
|
|
3329
|
+
{
|
|
3330
|
+
resource: "space",
|
|
3331
|
+
summary: "space (project) read/write",
|
|
3332
|
+
actions: [
|
|
3333
|
+
{
|
|
3334
|
+
action: "list",
|
|
3335
|
+
summary: "list visible spaces",
|
|
3336
|
+
flags: [
|
|
3337
|
+
{ name: "page", type: "number", valueHint: "<n>", description: "\u9875\u7801" },
|
|
3338
|
+
{ name: "page-size", type: "number", valueHint: "<n>", description: "\u6BCF\u9875\u6761\u6570" },
|
|
3339
|
+
{ name: "keyword", type: "string", valueHint: "<text>", description: "\u5173\u952E\u8BCD" }
|
|
3340
|
+
],
|
|
3341
|
+
examples: ["morula space list"],
|
|
3342
|
+
writes: "none",
|
|
3343
|
+
idempotent: true
|
|
3344
|
+
},
|
|
3345
|
+
{
|
|
3346
|
+
action: "get",
|
|
3347
|
+
summary: "get space details",
|
|
3348
|
+
args: [{ name: "id", required: true, description: "\u7A7A\u95F4 ID" }],
|
|
3349
|
+
flags: [],
|
|
3350
|
+
examples: ["morula space get <id>"],
|
|
3351
|
+
writes: "none",
|
|
3352
|
+
idempotent: true
|
|
3353
|
+
},
|
|
3354
|
+
{
|
|
3355
|
+
action: "create",
|
|
3356
|
+
summary: "create space (project)",
|
|
3357
|
+
flags: [
|
|
3358
|
+
{ name: "name", type: "string", valueHint: "<text>", description: "\u7A7A\u95F4\u540D\u79F0\uFF08\u5FC5\u586B\uFF09", required: true },
|
|
3359
|
+
{ name: "description", type: "string", valueHint: "<text>", description: "\u63CF\u8FF0" },
|
|
3360
|
+
{ name: "code", type: "string", valueHint: "<code>", description: "\u7A7A\u95F4\u7F16\u53F7\uFF08\u7F3A\u7701\u7531\u670D\u52A1\u7AEF\u751F\u6210\uFF09" },
|
|
3361
|
+
{ name: "visibility", type: "string", valueHint: "<private|internal|public>", enum: ["private", "internal", "public"], description: "\u53EF\u89C1\u6027" }
|
|
3362
|
+
],
|
|
3363
|
+
examples: ["morula space create --name <text>"],
|
|
3364
|
+
writes: "remote"
|
|
3365
|
+
},
|
|
3366
|
+
{
|
|
3367
|
+
action: "update",
|
|
3368
|
+
summary: "update space (\u81F3\u5C11\u4E00\u4E2A\u5B57\u6BB5\u65D7\u6807)",
|
|
3369
|
+
args: [{ name: "id", required: true, description: "\u7A7A\u95F4 ID" }],
|
|
3370
|
+
flags: [
|
|
3371
|
+
{ name: "name", type: "string", valueHint: "<text>", description: "\u7A7A\u95F4\u540D\u79F0" },
|
|
3372
|
+
{ name: "description", type: "string", valueHint: "<text>", description: "\u63CF\u8FF0" },
|
|
3373
|
+
{ name: "visibility", type: "string", valueHint: "<private|internal|public>", enum: ["private", "internal", "public"], description: "\u53EF\u89C1\u6027" }
|
|
3374
|
+
],
|
|
3375
|
+
examples: ["morula space update <id> --name <text>"],
|
|
3376
|
+
writes: "remote"
|
|
3377
|
+
},
|
|
3378
|
+
{
|
|
3379
|
+
action: "delete",
|
|
3380
|
+
summary: "delete space",
|
|
3381
|
+
args: [{ name: "id", required: true, description: "\u7A7A\u95F4 ID" }],
|
|
3382
|
+
flags: [],
|
|
3383
|
+
examples: ["morula space delete <id>"],
|
|
3384
|
+
writes: "remote"
|
|
3385
|
+
}
|
|
3386
|
+
]
|
|
3387
|
+
},
|
|
3388
|
+
{
|
|
3389
|
+
resource: "space-member",
|
|
3390
|
+
summary: "space member management (admin operations)",
|
|
3391
|
+
actions: [
|
|
3392
|
+
{
|
|
3393
|
+
action: "list",
|
|
3394
|
+
summary: "list space members",
|
|
3395
|
+
flags: [{ name: "space", type: "string", valueHint: "<id>", description: "\u7A7A\u95F4 ID\uFF08\u5FC5\u586B\uFF09", required: true }],
|
|
3396
|
+
examples: ["morula space-member list --space <id>"],
|
|
3397
|
+
writes: "none",
|
|
3398
|
+
idempotent: true
|
|
3399
|
+
},
|
|
3400
|
+
{
|
|
3401
|
+
action: "add",
|
|
3402
|
+
summary: "add member to space",
|
|
3403
|
+
flags: [
|
|
3404
|
+
{ name: "space", type: "string", valueHint: "<id>", description: "\u7A7A\u95F4 ID\uFF08\u5FC5\u586B\uFF09", required: true },
|
|
3405
|
+
{ name: "principal", type: "string", valueHint: "<id>", description: "\u6210\u5458 principalId\uFF08\u5FC5\u586B\uFF09", required: true },
|
|
3406
|
+
{ name: "role", type: "string", valueHint: "<admin|member>", enum: ["admin", "member"], description: "\u89D2\u8272\uFF08\u7F3A\u7701 member\uFF09" }
|
|
3407
|
+
],
|
|
3408
|
+
examples: ["morula space-member add --space <id> --principal <id>"],
|
|
3409
|
+
writes: "remote"
|
|
3410
|
+
},
|
|
3411
|
+
{
|
|
3412
|
+
action: "update",
|
|
3413
|
+
summary: "update member role",
|
|
3414
|
+
args: [{ name: "memberId", required: true, description: "\u6210\u5458\u884C ID" }],
|
|
3415
|
+
flags: [{ name: "role", type: "string", valueHint: "<admin|member>", enum: ["admin", "member"], description: "\u65B0\u89D2\u8272\uFF08\u5FC5\u586B\uFF09", required: true }],
|
|
3416
|
+
examples: ["morula space-member update <memberId> --role admin"],
|
|
3417
|
+
writes: "remote"
|
|
3418
|
+
},
|
|
3419
|
+
{
|
|
3420
|
+
action: "remove",
|
|
3421
|
+
summary: "remove member from space",
|
|
3422
|
+
args: [{ name: "memberId", required: true, description: "\u6210\u5458\u884C ID" }],
|
|
3423
|
+
flags: [],
|
|
3424
|
+
examples: ["morula space-member remove <memberId>"],
|
|
3425
|
+
writes: "remote"
|
|
3426
|
+
}
|
|
3427
|
+
]
|
|
3428
|
+
},
|
|
3429
|
+
{
|
|
3430
|
+
resource: "steward",
|
|
3431
|
+
summary: "space steward (project-level agent): read takeover state / dispatch a task with an explicit target state",
|
|
3432
|
+
actions: [
|
|
3433
|
+
{
|
|
3434
|
+
action: "get",
|
|
3435
|
+
summary: "get the steward record of a space (null = \u672A\u63A5\u7BA1)",
|
|
3436
|
+
flags: [{ name: "space", type: "string", valueHint: "<id>", description: "\u7A7A\u95F4\uFF08\u9879\u76EE\uFF09ID\uFF08\u5FC5\u586B\uFF09", required: true }],
|
|
3437
|
+
examples: ["morula steward get --space <id>"],
|
|
3438
|
+
writes: "none",
|
|
3439
|
+
idempotent: true
|
|
3440
|
+
},
|
|
3441
|
+
{
|
|
3442
|
+
action: "dispatch",
|
|
3443
|
+
summary: "dispatch a task: create the task and hand it to the pipeline. --state backlog = \u843D\u5F85\u89C4\u5212\uFF08\u4E0D\u6D3E\u53D1\u6267\u884C\uFF0C\u670D\u52A1\u7AEF\u4E0D\u5EFA AgentTask\uFF09\uFF1B\u7F3A\u7701 todo\uFF08\u5F85\u5206\u6790\uFF09",
|
|
3444
|
+
flags: [
|
|
3445
|
+
{ name: "space", type: "string", valueHint: "<id>", description: "\u7A7A\u95F4\uFF08\u9879\u76EE\uFF09ID\uFF08\u5FC5\u586B\uFF09", required: true },
|
|
3446
|
+
{ name: "title", type: "string", valueHint: "<text>", description: "\u4EFB\u52A1\u6807\u9898\uFF08\u5FC5\u586B\uFF09", required: true },
|
|
3447
|
+
{ name: "description", type: "string", valueHint: "<text>", description: "\u4EFB\u52A1\u63CF\u8FF0" },
|
|
3448
|
+
{ name: "state", type: "string", valueHint: "<backlog|todo|in_progress>", enum: ["backlog", "todo", "in_progress"], description: "\u76EE\u6807\u521D\u59CB\u72B6\u6001\uFF08\u7F3A\u7701 todo\uFF09" },
|
|
3449
|
+
{ name: "assignee", type: "string", valueHint: "<principalId>", description: "\u6307\u5B9A\u6267\u884C\u8005" },
|
|
3450
|
+
{ name: "repo", type: "string", valueHint: "<owner/name>", description: "\u591A\u4ED3\u5E93\u7A7A\u95F4\uFF1A\u6307\u5B9A\u76EE\u6807\u4ED3\u5E93\uFF08\u7F3A\u7701\u7531\u670D\u52A1\u7AEF\u89E3\u6790\uFF09" },
|
|
3451
|
+
{ name: "client-message-id", type: "string", valueHint: "<id>", description: "\u5E42\u7B49\u952E\uFF1A\u540C\u4E00\u952E\u91CD\u590D\u6D3E\u5355\u8FD4\u56DE\u539F\u7ED3\u679C" }
|
|
3452
|
+
],
|
|
3453
|
+
examples: ["morula steward dispatch --space <id> --title <text>", "morula steward dispatch --space <id> --title <text> --state backlog"],
|
|
3454
|
+
writes: "remote"
|
|
3455
|
+
}
|
|
3456
|
+
]
|
|
3457
|
+
},
|
|
3458
|
+
{
|
|
3459
|
+
resource: "autopilot",
|
|
3460
|
+
summary: "agent autopilots (scheduled/webhook-triggered automated runs; list only shows your own)",
|
|
3461
|
+
actions: [
|
|
3462
|
+
{
|
|
3463
|
+
action: "list",
|
|
3464
|
+
summary: "list autopilots created by the current user",
|
|
3465
|
+
flags: [
|
|
3466
|
+
{ name: "space", type: "string", valueHint: "<id>", description: "\u6309\u7A7A\u95F4\u8FC7\u6EE4" },
|
|
3467
|
+
{ name: "page", type: "number", valueHint: "<n>", description: "\u9875\u7801" },
|
|
3468
|
+
{ name: "page-size", type: "number", valueHint: "<n>", description: "\u6BCF\u9875\u6761\u6570" }
|
|
3469
|
+
],
|
|
3470
|
+
examples: ["morula autopilot list", "morula autopilot list --space <id>"],
|
|
3471
|
+
writes: "none",
|
|
3472
|
+
idempotent: true
|
|
3473
|
+
},
|
|
3474
|
+
{
|
|
3475
|
+
action: "create",
|
|
3476
|
+
summary: "create an autopilot (--executor is a runtime key; the server currently only accepts `dim`)",
|
|
3477
|
+
flags: [
|
|
3478
|
+
{ name: "space", type: "string", valueHint: "<id>", description: "\u5F52\u5C5E\u7A7A\u95F4 ID\uFF08\u5FC5\u586B\uFF09", required: true },
|
|
3479
|
+
{ name: "name", type: "string", valueHint: "<text>", description: "\u540D\u79F0\uFF08\u540C\u79DF\u6237\u552F\u4E00\uFF0C\u5FC5\u586B\uFF09", required: true },
|
|
3480
|
+
{ name: "runbook", type: "string", valueHint: "<text>", description: "Runbook\uFF1A\u6BCF\u6B21\u89E6\u53D1\u7ED9\u8FD0\u884C\u65F6\u7684\u76EE\u6807/\u80CC\u666F/\u6B65\u9AA4\uFF08\u5FC5\u586B\uFF09", required: true },
|
|
3481
|
+
{ name: "executor", type: "string", valueHint: "<key>", description: "\u6267\u884C\u8005\u8FD0\u884C\u65F6 key\uFF08\u5FC5\u586B\uFF1B\u5F53\u524D\u4EC5 dim\uFF09", required: true },
|
|
3482
|
+
{ name: "description", type: "string", valueHint: "<text>", description: "\u63CF\u8FF0" },
|
|
3483
|
+
{ name: "cron", type: "string", valueHint: "<expr>", description: "cron \u8868\u8FBE\u5F0F\uFF085 \u5B57\u6BB5\uFF09\uFF1B\u7F3A\u7701 = \u4EC5 webhook \u89E6\u53D1" },
|
|
3484
|
+
{ name: "vcs-connection", type: "string", valueHint: "<id>", description: "\u9650\u5B9A\u4ED3\u5E93\u8FDE\u63A5\uFF08\u7F3A\u7701\u4E0D\u9650\uFF09" }
|
|
3485
|
+
],
|
|
3486
|
+
examples: ["morula autopilot create --space <id> --name <text> --runbook <text> --executor dim"],
|
|
3487
|
+
writes: "remote"
|
|
3488
|
+
}
|
|
3489
|
+
]
|
|
3490
|
+
},
|
|
3491
|
+
{
|
|
3492
|
+
resource: "dashboard",
|
|
3493
|
+
summary: "space dashboard / statistics / member workload (read-only aggregates)",
|
|
3494
|
+
actions: [
|
|
3495
|
+
{
|
|
3496
|
+
action: "get",
|
|
3497
|
+
summary: "get the space dashboard aggregate",
|
|
3498
|
+
flags: [{ name: "space", type: "string", valueHint: "<id>", description: "\u7A7A\u95F4 ID\uFF08\u5FC5\u586B\uFF09", required: true }],
|
|
3499
|
+
examples: ["morula dashboard get --space <id>"],
|
|
3500
|
+
writes: "none",
|
|
3501
|
+
idempotent: true
|
|
3502
|
+
},
|
|
3503
|
+
{
|
|
3504
|
+
action: "statistics",
|
|
3505
|
+
summary: "get space task statistics",
|
|
3506
|
+
flags: [{ name: "space", type: "string", valueHint: "<id>", description: "\u7A7A\u95F4 ID\uFF08\u5FC5\u586B\uFF09", required: true }],
|
|
3507
|
+
examples: ["morula dashboard statistics --space <id>"],
|
|
3508
|
+
writes: "none",
|
|
3509
|
+
idempotent: true
|
|
3510
|
+
},
|
|
3511
|
+
{
|
|
3512
|
+
action: "workload",
|
|
3513
|
+
summary: "get per-member workload in a space",
|
|
3514
|
+
flags: [{ name: "space", type: "string", valueHint: "<id>", description: "\u7A7A\u95F4 ID\uFF08\u5FC5\u586B\uFF09", required: true }],
|
|
3515
|
+
examples: ["morula dashboard workload --space <id>"],
|
|
3516
|
+
writes: "none",
|
|
3517
|
+
idempotent: true
|
|
3518
|
+
}
|
|
3519
|
+
]
|
|
3520
|
+
},
|
|
3521
|
+
{
|
|
3522
|
+
resource: "object-meta",
|
|
3523
|
+
summary: "task-level agent metadata (D-06 high-signal keys only)",
|
|
3524
|
+
actions: [
|
|
3525
|
+
{
|
|
3526
|
+
action: "get",
|
|
3527
|
+
summary: "read all agent metadata of a task",
|
|
3528
|
+
flags: [{ name: "object", type: "string", valueHint: "<id>", description: "\u4EFB\u52A1\uFF08Object\uFF09ID\uFF08\u5FC5\u586B\uFF09", required: true }],
|
|
3529
|
+
examples: ["morula object-meta get --object <id>"],
|
|
3530
|
+
writes: "none",
|
|
3531
|
+
idempotent: true
|
|
3532
|
+
},
|
|
3533
|
+
{
|
|
3534
|
+
action: "set",
|
|
3535
|
+
summary: "write one agent metadata key. Key must be in the high-signal whitelist: pr_url / pr_number / pipeline_status / deploy_url / waiting_on / blocked_reason / decision",
|
|
3536
|
+
flags: [
|
|
3537
|
+
{ name: "object", type: "string", valueHint: "<id>", description: "\u4EFB\u52A1\uFF08Object\uFF09ID\uFF08\u5FC5\u586B\uFF09", required: true },
|
|
3538
|
+
{ name: "key", type: "string", valueHint: "<key>", description: "\u5143\u6570\u636E\u952E\uFF08\u5FC5\u586B\uFF0C\u767D\u540D\u5355\uFF09", required: true },
|
|
3539
|
+
{ name: "value", type: "string", valueHint: "<text>", description: "\u503C\uFF08\u5FC5\u586B\uFF0C\u975E\u7A7A\uFF09", required: true }
|
|
3540
|
+
],
|
|
3541
|
+
examples: ["morula object-meta set --object <id> --key pr_url --value <url>"],
|
|
3542
|
+
writes: "remote"
|
|
3543
|
+
}
|
|
3544
|
+
]
|
|
3545
|
+
},
|
|
3546
|
+
{
|
|
3547
|
+
resource: "document",
|
|
3548
|
+
summary: "document artifacts (ag_artifact; id is a numeric auto-increment id, not a uuid)",
|
|
3549
|
+
actions: [
|
|
3550
|
+
{
|
|
3551
|
+
action: "list",
|
|
3552
|
+
summary: "list document artifacts",
|
|
3553
|
+
flags: [
|
|
3554
|
+
{ name: "page", type: "number", valueHint: "<n>", description: "\u9875\u7801" },
|
|
3555
|
+
{ name: "page-size", type: "number", valueHint: "<n>", description: "\u6BCF\u9875\u6761\u6570" }
|
|
3556
|
+
],
|
|
3557
|
+
examples: ["morula document list"],
|
|
3558
|
+
writes: "none",
|
|
3559
|
+
idempotent: true
|
|
3560
|
+
},
|
|
3561
|
+
{
|
|
3562
|
+
action: "get",
|
|
3563
|
+
summary: "get document metadata (\u4E0D\u542B\u5B8C\u6574\u6B63\u6587)",
|
|
3564
|
+
args: [{ name: "id", required: true, description: "\u6587\u6863 ID\uFF08\u6570\u5B57\uFF0C\u6765\u81EA document list\uFF09" }],
|
|
3565
|
+
flags: [],
|
|
3566
|
+
examples: ["morula document get <id>"],
|
|
3567
|
+
writes: "none",
|
|
3568
|
+
idempotent: true
|
|
3569
|
+
},
|
|
3570
|
+
{
|
|
3571
|
+
action: "artifacts",
|
|
3572
|
+
summary: "read the parsed document content (markdown)",
|
|
3573
|
+
args: [{ name: "id", required: true, description: "\u6587\u6863 ID\uFF08\u6570\u5B57\uFF0C\u6765\u81EA document list\uFF09" }],
|
|
3574
|
+
flags: [],
|
|
3575
|
+
examples: ["morula document artifacts <id>"],
|
|
3576
|
+
writes: "none",
|
|
3577
|
+
idempotent: true
|
|
3578
|
+
}
|
|
3579
|
+
]
|
|
3580
|
+
},
|
|
3581
|
+
{
|
|
3582
|
+
resource: "comment",
|
|
3583
|
+
summary: "object comments (agent summaries live here)",
|
|
3584
|
+
actions: [
|
|
3585
|
+
{
|
|
3586
|
+
action: "list",
|
|
3587
|
+
summary: "list comments for an object",
|
|
3588
|
+
flags: [{ name: "object", type: "string", valueHint: "<id>", description: "\u5BF9\u8C61 ID\uFF08\u5FC5\u586B\uFF09", required: true }],
|
|
3589
|
+
examples: ["morula comment list --object <id>"],
|
|
3590
|
+
writes: "none",
|
|
3591
|
+
idempotent: true
|
|
3592
|
+
},
|
|
3593
|
+
{
|
|
3594
|
+
action: "get",
|
|
3595
|
+
summary: "get comment details",
|
|
3596
|
+
args: [{ name: "id", required: true, description: "\u8BC4\u8BBA ID" }],
|
|
3597
|
+
flags: [],
|
|
3598
|
+
examples: ["morula comment get <id>"],
|
|
3599
|
+
writes: "none",
|
|
3600
|
+
idempotent: true
|
|
3601
|
+
},
|
|
3602
|
+
{
|
|
3603
|
+
action: "add",
|
|
3604
|
+
summary: "add comment (format auto-detected; use markdown for agent final summaries). --mention \u53EF @ \u4EBA\uFF08\u89E6\u53D1\u901A\u77E5/\u50AC\u529E\uFF09",
|
|
3605
|
+
flags: [
|
|
3606
|
+
{ name: "object", type: "string", valueHint: "<id>", description: "\u5BF9\u8C61 ID\uFF08\u5FC5\u586B\uFF09", required: true },
|
|
3607
|
+
{ name: "content", type: "string", valueHint: "<text>", description: "\u8BC4\u8BBA\u5185\u5BB9\uFF08\u5FC5\u586B\uFF09", required: true },
|
|
3608
|
+
{ name: "parent", type: "string", valueHint: "<id>", description: "\u7236\u8BC4\u8BBA\uFF08\u56DE\u590D\uFF09" },
|
|
3609
|
+
{ name: "format", type: "string", valueHint: "<markdown|plain|richtext>", enum: ["markdown", "plain", "richtext"], description: "\u5185\u5BB9\u683C\u5F0F\uFF08\u7F3A\u7701\u81EA\u52A8\u68C0\u6D4B\uFF09" },
|
|
3610
|
+
{ name: "mention", type: "string", valueHint: "<principalId[,principalId]>", repeatable: true, description: "@ \u4EBA\uFF1A\u88AB\u63D0\u53CA\u8005\u7684 principalId\uFF0C\u53EF\u91CD\u590D\u4F20\uFF08--mention a --mention b\uFF09\u6216\u7528\u9017\u53F7\u5206\u9694\u591A\u4E2A\uFF08\u4E24\u79CD\u6DF7\u7528\u81EA\u52A8\u5408\u5E76\u53BB\u91CD\u4FDD\u5E8F\uFF09\uFF1B\u53EA\u652F\u6301\u4EBA\uFF0C\u4E0D\u652F\u6301 @ \u8FD0\u884C\u65F6/\u667A\u80FD\u4F53" }
|
|
3611
|
+
],
|
|
3612
|
+
examples: ["morula comment add --object <id> --content <text>", "morula comment add --object <id> --content <text> --mention <principalId>", "morula comment add --object <id> --content <text> --mention <principalIdA> --mention <principalIdB>"],
|
|
3613
|
+
writes: "remote"
|
|
3614
|
+
},
|
|
3615
|
+
{
|
|
3616
|
+
action: "update",
|
|
3617
|
+
summary: "update comment",
|
|
3618
|
+
args: [{ name: "id", required: true, description: "\u8BC4\u8BBA ID" }],
|
|
3619
|
+
flags: [{ name: "content", type: "string", valueHint: "<text>", description: "\u65B0\u5185\u5BB9\uFF08\u5FC5\u586B\uFF09", required: true }],
|
|
3620
|
+
examples: ["morula comment update <id> --content <text>"],
|
|
3621
|
+
writes: "remote"
|
|
3622
|
+
},
|
|
3623
|
+
{
|
|
3624
|
+
action: "delete",
|
|
3625
|
+
summary: "hard delete comment",
|
|
3626
|
+
args: [{ name: "id", required: true, description: "\u8BC4\u8BBA ID" }],
|
|
3627
|
+
flags: [],
|
|
3628
|
+
examples: ["morula comment delete <id>"],
|
|
3629
|
+
writes: "remote"
|
|
3630
|
+
}
|
|
3631
|
+
]
|
|
3632
|
+
},
|
|
3633
|
+
{
|
|
3634
|
+
resource: "review",
|
|
3635
|
+
summary: "Code Review verdict submission (review task machine protocol)",
|
|
3636
|
+
actions: [
|
|
3637
|
+
{
|
|
3638
|
+
action: "submit",
|
|
3639
|
+
summary: "submit Code Review verdict (machine protocol; review task token)",
|
|
3640
|
+
args: [{ name: "objectId", required: true, description: "\u8BC4\u5BA1\u5BF9\u8C61 ID\uFF08\u7CFB\u7EDF\u63D0\u793A\u300C\u8BC4\u5BA1\u5BF9\u8C61\u300D\uFF09" }],
|
|
3641
|
+
flags: [
|
|
3642
|
+
{ name: "verdict", type: "string", valueHint: "<approved|changes_requested|commented>", enum: ["approved", "changes_requested", "commented"], description: "\u8BC4\u5BA1\u7ED3\u8BBA\uFF08\u5FC5\u586B\uFF09", required: true },
|
|
3643
|
+
{ name: "details", type: "string", valueHint: "<text>", description: "\u8BC4\u5BA1\u610F\u89C1\uFF08changes_requested \u5FC5\u586B\uFF1A\u6587\u4EF6/\u884C/\u95EE\u9898/\u5EFA\u8BAE\uFF09" },
|
|
3644
|
+
{ name: "pr-number", type: "number", valueHint: "<n>", description: "\u8BC4\u5BA1\u5BF9\u8C61\u7684 PR \u7F16\u53F7\uFF08\u6709\u5219\u586B\uFF09" }
|
|
3645
|
+
],
|
|
3646
|
+
examples: ["morula review submit <objectId> --verdict approved"],
|
|
3647
|
+
writes: "remote"
|
|
3648
|
+
}
|
|
3649
|
+
]
|
|
3650
|
+
},
|
|
3651
|
+
{
|
|
3652
|
+
resource: "report",
|
|
3653
|
+
summary: "autopilot reports (conclusion-heavy output of automated runs)",
|
|
3654
|
+
actions: [
|
|
3655
|
+
{
|
|
3656
|
+
action: "create",
|
|
3657
|
+
summary: "create an autopilot report (\u6B63\u6587\u4E8C\u9009\u4E00\uFF1A--content \u77ED\u6B63\u6587 / --content-file \u957F Markdown\uFF1B--autopilot \u7701\u7565\u65F6\u6309\u5F53\u524D\u4EFB\u52A1\u53CD\u67E5\u6240\u5C5E\u81EA\u52A8\u5316)",
|
|
3658
|
+
flags: [
|
|
3659
|
+
{ name: "title", type: "string", valueHint: "<text>", description: "\u6807\u9898\uFF08\u5FC5\u586B\uFF09", required: true },
|
|
3660
|
+
{ name: "content", type: "string", valueHint: "<markdown>", description: "\u77ED\u6B63\u6587\uFF08\u4E0E --content-file \u4E8C\u9009\u4E00\uFF09" },
|
|
3661
|
+
{ name: "content-file", type: "string", valueHint: "<path>", description: "\u957F Markdown \u62A5\u544A\u6587\u4EF6\uFF08\u4E0E --content \u4E8C\u9009\u4E00\uFF09" },
|
|
3662
|
+
{ name: "space", type: "string", valueHint: "<id>", description: "\u5F52\u5C5E\u7A7A\u95F4" },
|
|
3663
|
+
{ name: "autopilot", type: "string", valueHint: "<id>", description: "\u6240\u5C5E\u81EA\u52A8\u5316\uFF08\u7701\u7565\u65F6\u6309\u5F53\u524D\u4EFB\u52A1\u53CD\u67E5\uFF09" }
|
|
3664
|
+
],
|
|
3665
|
+
examples: ["morula report create --title <t> --content-file <path>"],
|
|
3666
|
+
writes: "remote"
|
|
3667
|
+
},
|
|
3668
|
+
{
|
|
3669
|
+
action: "get",
|
|
3670
|
+
summary: "get report details (\u542B Markdown \u6B63\u6587)",
|
|
3671
|
+
args: [{ name: "id", required: true, description: "\u62A5\u544A ID" }],
|
|
3672
|
+
flags: [],
|
|
3673
|
+
examples: ["morula report get <id>"],
|
|
3674
|
+
writes: "none",
|
|
3675
|
+
idempotent: true
|
|
3676
|
+
},
|
|
3677
|
+
{
|
|
3678
|
+
action: "list",
|
|
3679
|
+
summary: "list reports of an autopilot",
|
|
3680
|
+
flags: [
|
|
3681
|
+
{ name: "autopilot", type: "string", valueHint: "<id>", description: "\u81EA\u52A8\u5316 ID\uFF08\u5FC5\u586B\uFF09", required: true },
|
|
3682
|
+
{ name: "page", type: "number", valueHint: "<n>", description: "\u9875\u7801" },
|
|
3683
|
+
{ name: "page-size", type: "number", valueHint: "<n>", description: "\u6BCF\u9875\u6761\u6570" }
|
|
3684
|
+
],
|
|
3685
|
+
examples: ["morula report list --autopilot <id>"],
|
|
3686
|
+
writes: "none",
|
|
3687
|
+
idempotent: true
|
|
3688
|
+
}
|
|
3689
|
+
]
|
|
3690
|
+
},
|
|
3691
|
+
{
|
|
3692
|
+
resource: "repo",
|
|
3693
|
+
summary: "task-space VCS repos: materialize checkout / MR read & comment (server channel; never approves/merges)",
|
|
3694
|
+
actions: [
|
|
3695
|
+
{
|
|
3696
|
+
action: "list",
|
|
3697
|
+
summary: "list task-space VCS connections (the space repo list \u2014 the task prompt does NOT list repos; query this when a task may span multiple repos)",
|
|
3698
|
+
flags: [{ name: "space", type: "string", valueHint: "<id>", description: "\u7A7A\u95F4 ID\uFF08\u5FC5\u586B\uFF09", required: true }],
|
|
3699
|
+
examples: ["morula repo list --space <id>"],
|
|
3700
|
+
writes: "none",
|
|
3701
|
+
idempotent: true
|
|
3702
|
+
},
|
|
3703
|
+
{
|
|
3704
|
+
action: "checkout",
|
|
3705
|
+
summary: "materialize a repo into the task workdir (local daemon endpoint preferred, works same-turn; falls back to server machine protocol which resolves scope + workContext)",
|
|
3706
|
+
args: [
|
|
3707
|
+
{ name: "taskId", required: true, description: "\u672C\u4EFB\u52A1 AgentTask UUID" },
|
|
3708
|
+
{ name: "repoFullName", required: true, description: "\u4ED3\u5E93\u5168\u540D\uFF08owner/name\uFF09" }
|
|
3709
|
+
],
|
|
3710
|
+
flags: [{ name: "ref", type: "string", valueHint: "<branch|sha>", description: "\u68C0\u51FA\u5F15\u7528\uFF08\u7F3A\u7701 = \u7ED1\u5B9A\u5206\u652F\uFF09" }],
|
|
3711
|
+
examples: ["morula repo checkout <taskId> <owner/name>"],
|
|
3712
|
+
writes: "local",
|
|
3713
|
+
idempotent: true
|
|
3714
|
+
},
|
|
3715
|
+
{
|
|
3716
|
+
action: "prepare",
|
|
3717
|
+
summary: "materialize a secondary repo into the task workdir (same level as the primary repo dir)",
|
|
3718
|
+
args: [
|
|
3719
|
+
{ name: "taskId", required: true, description: "\u672C\u4EFB\u52A1 AgentTask UUID" },
|
|
3720
|
+
{ name: "repoFullName", required: true, description: "\u6B21\u4ED3\u5E93\u5168\u540D\uFF08owner/name\uFF09" }
|
|
3721
|
+
],
|
|
3722
|
+
flags: [],
|
|
3723
|
+
examples: ["morula repo prepare <taskId> <owner/name>"],
|
|
3724
|
+
writes: "local",
|
|
3725
|
+
idempotent: true
|
|
3726
|
+
},
|
|
3727
|
+
{
|
|
3728
|
+
action: "files",
|
|
3729
|
+
summary: "list files in a space repo via the server (read-only, non-task: no local checkout, no AgentTask context)",
|
|
3730
|
+
flags: [
|
|
3731
|
+
{ name: "space", type: "string", valueHint: "<id>", description: "\u7A7A\u95F4 ID\uFF08\u5FC5\u586B\uFF09", required: true },
|
|
3732
|
+
{ name: "repo", type: "string", valueHint: "<owner/name>", description: "\u4ED3\u5E93\u5168\u540D\uFF08\u7F3A\u7701 = \u7A7A\u95F4\u4E3B\u4ED3\u5E93\uFF09" },
|
|
3733
|
+
{ name: "path", type: "string", valueHint: "<path>", description: "\u76EE\u5F55\u8DEF\u5F84\uFF08\u7F3A\u7701 = \u4ED3\u5E93\u6839\uFF09" },
|
|
3734
|
+
{ name: "ref", type: "string", valueHint: "<branch|sha>", description: "\u5206\u652F / tag / commit\uFF08\u7F3A\u7701 = \u9ED8\u8BA4\u5206\u652F\uFF09" }
|
|
3735
|
+
],
|
|
3736
|
+
examples: ["morula repo files --space <id>", "morula repo files --space <id> --path src"],
|
|
3737
|
+
writes: "none",
|
|
3738
|
+
idempotent: true
|
|
3739
|
+
},
|
|
3740
|
+
{
|
|
3741
|
+
action: "read",
|
|
3742
|
+
summary: "read a single file from a space repo via the server (read-only, non-task)",
|
|
3743
|
+
flags: [
|
|
3744
|
+
{ name: "space", type: "string", valueHint: "<id>", description: "\u7A7A\u95F4 ID\uFF08\u5FC5\u586B\uFF09", required: true },
|
|
3745
|
+
{ name: "path", type: "string", valueHint: "<path>", description: "\u6587\u4EF6\u8DEF\u5F84\uFF08\u5FC5\u586B\uFF09", required: true },
|
|
3746
|
+
{ name: "repo", type: "string", valueHint: "<owner/name>", description: "\u4ED3\u5E93\u5168\u540D\uFF08\u7F3A\u7701 = \u7A7A\u95F4\u4E3B\u4ED3\u5E93\uFF09" },
|
|
3747
|
+
{ name: "ref", type: "string", valueHint: "<branch|sha>", description: "\u5206\u652F / tag / commit\uFF08\u7F3A\u7701 = \u9ED8\u8BA4\u5206\u652F\uFF09" }
|
|
3748
|
+
],
|
|
3749
|
+
examples: ["morula repo read --space <id> --path src/index.ts"],
|
|
3750
|
+
writes: "none",
|
|
3751
|
+
idempotent: true
|
|
3752
|
+
},
|
|
3753
|
+
{
|
|
3754
|
+
action: "mr create",
|
|
3755
|
+
summary: "create a GitLab MR for the task via the server channel (target project forced to the bound repo, PR linked immediately; push the branch first)",
|
|
3756
|
+
args: [{ name: "repoFullName", required: true, description: "\u4ED3\u5E93\u5168\u540D\uFF08owner/name\uFF09" }],
|
|
3757
|
+
flags: [
|
|
3758
|
+
{ name: "branch", type: "string", valueHint: "<branch>", description: "\u6E90\u5206\u652F\uFF08\u5FC5\u586B\uFF09", required: true },
|
|
3759
|
+
{ name: "base", type: "string", valueHint: "<base>", description: "\u76EE\u6807\u5206\u652F\uFF08\u7F3A\u7701 MORULA_BASE_BRANCH / main\uFF09" },
|
|
3760
|
+
{ name: "task-code", type: "string", valueHint: "<code>", description: "\u4EFB\u52A1\u7F16\u53F7\uFF08MR \u6807\u9898/\u6B63\u6587\u56DE\u94FE\uFF09" }
|
|
3761
|
+
],
|
|
3762
|
+
examples: ["morula repo mr create <owner/name> --branch <b> --task-code <code>"],
|
|
3763
|
+
writes: "remote"
|
|
3764
|
+
},
|
|
3765
|
+
{
|
|
3766
|
+
action: "mr list",
|
|
3767
|
+
summary: "list the task-space repos' merge requests (read-only; includes createdAt/updatedAt/author; never approves/merges)",
|
|
3768
|
+
args: [{ name: "taskId", required: true, description: "\u672C\u4EFB\u52A1 AgentTask UUID" }],
|
|
3769
|
+
flags: [
|
|
3770
|
+
{ name: "state", type: "string", valueHint: "<opened|closed|merged>", enum: ["opened", "closed", "merged"], description: "MR \u72B6\u6001\u8FC7\u6EE4\uFF08\u7F3A\u7701 opened\uFF09" },
|
|
3771
|
+
{ name: "limit", type: "number", valueHint: "<n>", description: "\u6761\u6570\u4E0A\u9650" },
|
|
3772
|
+
{ name: "author", type: "string", valueHint: "<username>", description: "\u6309\u4F5C\u8005\u8FC7\u6EE4" },
|
|
3773
|
+
{ name: "repo", type: "string", valueHint: "<owner/name>", description: "\u591A\u4ED3\u5E93\u7A7A\u95F4\uFF1A\u76EE\u6807\u4ED3\u5E93\uFF08\u7F3A\u7701\u4E3B\u4ED3\u5E93\uFF09" }
|
|
3774
|
+
],
|
|
3775
|
+
examples: ["morula repo mr list <taskId> --state opened"],
|
|
3776
|
+
writes: "none",
|
|
3777
|
+
idempotent: true
|
|
3778
|
+
},
|
|
3779
|
+
{
|
|
3780
|
+
action: "mr comment",
|
|
3781
|
+
summary: "write a review comment on an MR/PR (write-only: never approves or merges). \u5199\u4E4B\u524D\u5FC5\u987B\u5148 `morula repo mr get <taskId> --mr <iid> --notes` \u8BFB\u5DF2\u6709\u8BA8\u8BBA\uFF1A\u82E5\u672C\u81EA\u52A8\u5316\u5DF2\u5C31\u540C\u4E00\u95EE\u9898\u7559\u8FC7\u7ED3\u8BBA\u4E14\u7ED3\u8BBA\u672A\u53D8\uFF0C\u4E0D\u8981\u518D\u8BC4\u8BBA\u3002\u5185\u5BB9\u4E3A\u7ED3\u8BBA + \u5173\u952E\u95EE\u9898\uFF08\u6587\u4EF6:\u884C + \u5EFA\u8BAE\uFF09\uFF0C\u672B\u5C3E\u52A0\u7F72\u540D\u884C\uFF1B\u957F\u5185\u5BB9\u5199\u6210\u62A5\u544A\u540E\u7528\u6458\u8981\u5F15\u7528\uFF08morula report create \u2192 \u8BC4\u8BBA\u91CC\u7ED9\u8981\u70B9\uFF09",
|
|
3782
|
+
args: [{ name: "taskId", required: true, description: "\u672C\u4EFB\u52A1 AgentTask UUID" }],
|
|
3783
|
+
flags: [
|
|
3784
|
+
{ name: "mr", type: "number", valueHint: "<iid>", description: "MR \u7F16\u53F7\uFF08\u5FC5\u586B\uFF09", required: true },
|
|
3785
|
+
{ name: "repo", type: "string", valueHint: "<owner/name>", description: "\u591A\u4ED3\u5E93\u7A7A\u95F4\uFF1A\u76EE\u6807\u4ED3\u5E93\uFF08\u7F3A\u7701\u4E3B\u4ED3\u5E93\uFF09" },
|
|
3786
|
+
{ name: "connection", type: "string", valueHint: "<id>", description: "\u8FDE\u63A5 ID\uFF08\u591A\u8FDE\u63A5\u573A\u666F\uFF09" },
|
|
3787
|
+
{ name: "content", type: "string", valueHint: "<text>", description: "\u8BC4\u8BBA\u6B63\u6587\uFF08\u4E0E --content-file \u4E8C\u9009\u4E00\uFF09" },
|
|
3788
|
+
{ name: "content-file", type: "string", valueHint: "<path>", description: "\u8BC4\u8BBA\u6B63\u6587\u6587\u4EF6\uFF08\u4E0E --content \u4E8C\u9009\u4E00\uFF09" }
|
|
3789
|
+
],
|
|
3790
|
+
examples: ["morula repo mr comment <taskId> --mr <iid> --content-file <path>"],
|
|
3791
|
+
writes: "remote"
|
|
3792
|
+
},
|
|
3793
|
+
{
|
|
3794
|
+
action: "mr get",
|
|
3795
|
+
summary: "get a single MR detail (read-only; --ci attaches pipeline status where none = no pipeline, not an error; --notes attaches existing comments \u2014 read this before writing a comment to avoid duplicates)",
|
|
3796
|
+
args: [{ name: "taskId", required: true, description: "\u672C\u4EFB\u52A1 AgentTask UUID" }],
|
|
3797
|
+
flags: [
|
|
3798
|
+
{ name: "mr", type: "number", valueHint: "<iid>", description: "MR \u7F16\u53F7\uFF08\u5FC5\u586B\uFF09", required: true },
|
|
3799
|
+
{ name: "repo", type: "string", valueHint: "<owner/name>", description: "\u591A\u4ED3\u5E93\u7A7A\u95F4\uFF1A\u76EE\u6807\u4ED3\u5E93\uFF08\u7F3A\u7701\u4E3B\u4ED3\u5E93\uFF09" },
|
|
3800
|
+
{ name: "ci", type: "boolean", description: "\u9644\u5E26 pipeline \u72B6\u6001" },
|
|
3801
|
+
{ name: "notes", type: "boolean", description: "\u9644\u5E26\u5DF2\u6709\u8BC4\u8BBA\uFF08\u5199\u8BC4\u8BBA\u524D\u5148\u8BFB\uFF0C\u9632\u91CD\u590D\uFF09" }
|
|
3802
|
+
],
|
|
3803
|
+
examples: ["morula repo mr get <taskId> --mr <iid> --notes"],
|
|
3804
|
+
writes: "none",
|
|
3805
|
+
idempotent: true
|
|
3806
|
+
},
|
|
3807
|
+
{
|
|
3808
|
+
action: "mr diff",
|
|
3809
|
+
summary: "read an MR diff via the server (read-only; works without a local checkout; truncated flag is set when output was capped)",
|
|
3810
|
+
args: [{ name: "taskId", required: true, description: "\u672C\u4EFB\u52A1 AgentTask UUID" }],
|
|
3811
|
+
flags: [
|
|
3812
|
+
{ name: "mr", type: "number", valueHint: "<iid>", description: "MR \u7F16\u53F7\uFF08\u5FC5\u586B\uFF09", required: true },
|
|
3813
|
+
{ name: "repo", type: "string", valueHint: "<owner/name>", description: "\u591A\u4ED3\u5E93\u7A7A\u95F4\uFF1A\u76EE\u6807\u4ED3\u5E93\uFF08\u7F3A\u7701\u4E3B\u4ED3\u5E93\uFF09" },
|
|
3814
|
+
{ name: "max-files", type: "number", valueHint: "<n>", description: "\u6587\u4EF6\u6570\u4E0A\u9650" },
|
|
3815
|
+
{ name: "max-chars", type: "number", valueHint: "<n>", description: "\u5B57\u7B26\u6570\u4E0A\u9650" }
|
|
3816
|
+
],
|
|
3817
|
+
examples: ["morula repo mr diff <taskId> --mr <iid>"],
|
|
3818
|
+
writes: "none",
|
|
3819
|
+
idempotent: true
|
|
3820
|
+
}
|
|
3821
|
+
],
|
|
3822
|
+
notes: [
|
|
3823
|
+
"mr \u662F\u591A\u7EA7\u5B50\u547D\u4EE4\u5F62\u6001\uFF08action=mr\u3001\u5B50\u547D\u4EE4\u4F4D\u5728 positionals[0]\uFF09\uFF1A\u5951\u7EA6\u6309\u5B50\u547D\u4EE4\u62C6\u5206\u58F0\u660E\uFF08mr create / mr list / ...\uFF09\uFF0C\u4E25\u683C\u6821\u9A8C\u53EA\u5BF9\u5355\u7EA7 action \u751F\u6548"
|
|
3824
|
+
]
|
|
3825
|
+
},
|
|
3826
|
+
{
|
|
3827
|
+
resource: "ci",
|
|
3828
|
+
summary: "CI/CD pipeline facts and pipeline operations: pipeline runs / job logs / deployments / failed test cases (read-only) plus retry of a failed pipeline or job (Phase 3 write, space face only). Read faces share one command surface \u2014 task face `<taskId>` (AgentTask credential, self-check your MR pipeline) vs space face `--space <spaceId>` (steward/session credential, space-wide inspection); the two are mutually exclusive. Retry is space-face ONLY (person + steward); trigger-deploy (play a manual job) stays person-only and is intentionally absent from the CLI",
|
|
3829
|
+
actions: [
|
|
3830
|
+
{
|
|
3831
|
+
action: "status",
|
|
3832
|
+
summary: "pipeline runs + deployments for a task (or a space); hasCiConfig:false comes with a notice explaining the repo has no CI config (not an error); on the task face --repo filters runs client-side by repoFullName and echoes repoFilter (the server does NOT support repo filtering)",
|
|
3833
|
+
args: [{ name: "taskId", description: "\u672C\u4EFB\u52A1 AgentTask UUID\uFF08\u4E0E --space \u4E92\u65A5\uFF09" }],
|
|
3834
|
+
flags: [
|
|
3835
|
+
{ name: "space", type: "string", valueHint: "<id>", description: "\u7A7A\u95F4 ID\uFF08\u7BA1\u5BB6/\u7A7A\u95F4\u9762\uFF1B\u4E0E <taskId> \u4E92\u65A5\uFF09" },
|
|
3836
|
+
{ name: "repo", type: "string", valueHint: "<owner/name>", description: "\u591A\u4ED3\u5E93\u7A7A\u95F4\uFF1A\u53EA\u770B\u8BE5\u4ED3\u5E93\u7684\u8FD0\u884C\uFF08\u4EFB\u52A1\u9762\u4E13\u7528\uFF0C\u5BA2\u6237\u7AEF\u8FC7\u6EE4\uFF09" },
|
|
3837
|
+
{ name: "ref", type: "string", valueHint: "<branch>", description: "\u6309\u5206\u652F/tag \u8FC7\u6EE4\uFF08\u7A7A\u95F4\u9762\u4E13\u7528\uFF09" },
|
|
3838
|
+
{ name: "failed", type: "boolean", description: "\u53EA\u770B\u5931\u8D25\u7684\u8FD0\u884C\uFF08\u7A7A\u95F4\u9762\u4E13\u7528\uFF09" },
|
|
3839
|
+
{ name: "limit", type: "number", valueHint: "<n>", description: "\u8FD0\u884C\u6761\u6570\u4E0A\u9650\uFF08\u670D\u52A1\u7AEF\u9ED8\u8BA4 20\uFF0C\u4E0A\u9650 100\uFF09" }
|
|
3840
|
+
],
|
|
3841
|
+
examples: ["morula ci status <taskId>", "morula ci status --space <id> --failed"],
|
|
3842
|
+
writes: "none",
|
|
3843
|
+
idempotent: true,
|
|
3844
|
+
emits: ["ok", "taskId", "spaceId", "runs", "deployments", "hasCiConfig", "notice", "repoFilter"]
|
|
3845
|
+
},
|
|
3846
|
+
{
|
|
3847
|
+
action: "log",
|
|
3848
|
+
summary: "job log by job id (the server resolves the owning run; both faces use this same endpoint \u2014 the task/space flag only declares which face you are calling from). `truncated:true` means the log was tail-cut, not complete",
|
|
3849
|
+
args: [{ name: "taskId", description: "\u672C\u4EFB\u52A1 AgentTask UUID\uFF08\u4E0E --space \u4E92\u65A5\uFF09" }],
|
|
3850
|
+
flags: [
|
|
3851
|
+
{ name: "space", type: "string", valueHint: "<id>", description: "\u7A7A\u95F4 ID\uFF08\u7BA1\u5BB6/\u7A7A\u95F4\u9762\uFF1B\u4E0E <taskId> \u4E92\u65A5\uFF09" },
|
|
3852
|
+
{ name: "job", type: "string", valueHint: "<jobId>", description: "job ID\uFF08\u5FC5\u586B\uFF1B\u6765\u81EA ci status \u7684 jobs[].id\uFF09", required: true },
|
|
3853
|
+
{ name: "tail", type: "number", valueHint: "<n>", description: "\u4FDD\u7559\u7684\u65E5\u5FD7\u5C3E\u90E8\u5B57\u8282\u6570\uFF08\u670D\u52A1\u7AEF\u9ED8\u8BA4 64KB\uFF09" }
|
|
3854
|
+
],
|
|
3855
|
+
examples: ["morula ci log <taskId> --job <jobId> --tail 20000"],
|
|
3856
|
+
writes: "none",
|
|
3857
|
+
idempotent: true,
|
|
3858
|
+
emits: ["ok", "runId", "jobId", "log", "truncated"]
|
|
3859
|
+
},
|
|
3860
|
+
{
|
|
3861
|
+
action: "deployments",
|
|
3862
|
+
summary: "deployment records for a task (or a space) \u2014 display only: deployments do NOT drive lifecycle state (released is driven solely by a successful production-branch pipeline run)",
|
|
3863
|
+
args: [{ name: "taskId", description: "\u672C\u4EFB\u52A1 AgentTask UUID\uFF08\u4E0E --space \u4E92\u65A5\uFF09" }],
|
|
3864
|
+
flags: [
|
|
3865
|
+
{ name: "space", type: "string", valueHint: "<id>", description: "\u7A7A\u95F4 ID\uFF08\u7BA1\u5BB6/\u7A7A\u95F4\u9762\uFF1B\u4E0E <taskId> \u4E92\u65A5\uFF09" }
|
|
3866
|
+
],
|
|
3867
|
+
examples: ["morula ci deployments <taskId>"],
|
|
3868
|
+
writes: "none",
|
|
3869
|
+
idempotent: true,
|
|
3870
|
+
emits: ["ok", "spaceId", "deployments"]
|
|
3871
|
+
},
|
|
3872
|
+
{
|
|
3873
|
+
action: "test-report",
|
|
3874
|
+
summary: "failed test cases of a run; --run omitted resolves to the newest run in the CI view \u2014 no run at all is CI_RUN_NOT_FOUND (exit 3), never an empty report; provider without this capability (GitHub) returns CAPABILITY_UNSUPPORTED",
|
|
3875
|
+
args: [{ name: "taskId", description: "\u672C\u4EFB\u52A1 AgentTask UUID\uFF08\u4E0E --space \u4E92\u65A5\uFF09" }],
|
|
3876
|
+
flags: [
|
|
3877
|
+
{ name: "space", type: "string", valueHint: "<id>", description: "\u7A7A\u95F4 ID\uFF08\u7BA1\u5BB6/\u7A7A\u95F4\u9762\uFF1B\u4E0E <taskId> \u4E92\u65A5\uFF09" },
|
|
3878
|
+
{ name: "run", type: "string", valueHint: "<runId>", description: "\u8FD0\u884C ID\uFF08\u7F3A\u7701 = CI \u89C6\u56FE\u91CC\u6700\u65B0\u4E00\u6761\u8FD0\u884C\uFF09" }
|
|
3879
|
+
],
|
|
3880
|
+
examples: ["morula ci test-report <taskId>"],
|
|
3881
|
+
writes: "none",
|
|
3882
|
+
idempotent: true,
|
|
3883
|
+
emits: ["ok", "runId", "report"]
|
|
3884
|
+
},
|
|
3885
|
+
{
|
|
3886
|
+
action: "retry",
|
|
3887
|
+
summary: "re-run a failed pipeline (Phase 3; space face ONLY \u2014 a positional <taskId> is a usage error, retry is not open to the task face; person + steward, and a steward must go through an elicitation confirm card). Omit both --run and --job to retry the newest FAILED run of the space (no failed run at all \u2192 CI_RUN_NOT_FOUND exit 3). Only failure/cancelled runs or jobs can be retried (CI_RETRY_NOT_ALLOWED exit 6). NOT idempotent: every call starts another platform re-run",
|
|
3888
|
+
flags: [
|
|
3889
|
+
{ name: "space", type: "string", valueHint: "<id>", description: "\u7A7A\u95F4 ID\uFF08\u5FC5\u586B\uFF1Bretry \u53EA\u6709\u7A7A\u95F4\u9762\uFF0C\u4EFB\u52A1\u9762\u4E0D\u5F00\u653E\uFF09", required: true },
|
|
3890
|
+
{ name: "run", type: "string", valueHint: "<runId>", description: "\u8981\u91CD\u8DD1\u7684\u8FD0\u884C ID\uFF08\u4E0E --job \u4E92\u65A5\uFF1B\u7F3A\u7701 = \u8BE5\u7A7A\u95F4\u6700\u65B0\u4E00\u6761\u5931\u8D25\u8FD0\u884C\uFF09" },
|
|
3891
|
+
{ name: "job", type: "string", valueHint: "<jobId>", description: "\u8981\u91CD\u8DD1\u7684\u5355\u4E2A job ID\uFF08\u4E0E --run \u4E92\u65A5\uFF1B\u6765\u81EA ci status \u7684 jobs[].id\uFF09" }
|
|
3892
|
+
],
|
|
3893
|
+
examples: ["morula ci retry --space <id>", "morula ci retry --space <id> --job <jobId>"],
|
|
3894
|
+
writes: "remote",
|
|
3895
|
+
idempotent: false,
|
|
3896
|
+
emits: ["ok", "action", "runId", "jobId", "externalId", "ref", "acceptedAt"]
|
|
3897
|
+
}
|
|
3898
|
+
],
|
|
3899
|
+
notes: [
|
|
3900
|
+
"\u4E24\u4E2A\u9762\uFF08\u4EFB\u52A1\u9762 <taskId> / \u7A7A\u95F4\u9762 --space <spaceId>\uFF09\u4E92\u65A5\uFF1A\u540C\u65F6\u7ED9 \u2192 usage error(2)\uFF0C\u90FD\u4E0D\u7ED9\u540C\u6837 usage error\u3002\u51ED\u8BC1\u4E0E\u4F5C\u7528\u57DF\u4E0D\u540C\uFF0C\u731C\u9519\u4F1A\u53D8\u6210\u9759\u9ED8\u8D8A\u6743\u6216\u9759\u9ED8\u5931\u8D25",
|
|
3901
|
+
"\u53EA\u8BFB\u9762\uFF1Astatus / log / deployments / test-report \u53EA\u8BFB\uFF08writes: none\uFF09\uFF1Bretry \u662F Phase 3 \u7684\u552F\u4E00\u5199\u9762\uFF08writes: remote\uFF0C\u975E\u5E42\u7B49\uFF09\uFF0C\u4E14**\u53EA\u6709\u7A7A\u95F4\u9762**\u2014\u2014\u7ED9\u4F4D\u7F6E\u53C2\u6570 <taskId> \u2192 usage error(2)",
|
|
3902
|
+
"\u89E6\u53D1\u624B\u52A8 job\uFF08play\uFF0C\u90E8\u7F72\uFF09\u4E0D\u8FDB CLI\uFF1A\u4EC5\u4EBA\u9762\uFF08D5/D6\uFF09\uFF0C\u5165\u53E3\u53EA\u5728 web \u786E\u8BA4\u5F39\u7A97",
|
|
3903
|
+
"\u670D\u52A1\u7AEF\u4E1A\u52A1\u5931\u8D25\u662F HTTP 200 + `{ ok:false, code, message }`\uFF1ACI_JOB_NOT_FOUND / CI_RUN_NOT_FOUND / TASK_NOT_FOUND / OBJECT_NOT_FOUND \u2192 exit 3\uFF1BCI_RETRY_NOT_ALLOWED / CI_JOB_NOT_MANUAL \u2192 exit 6\uFF1BCAPABILITY_UNSUPPORTED / NO_CONNECTION / \u5176\u4F59 \u2192 exit 1"
|
|
3904
|
+
]
|
|
3905
|
+
},
|
|
3906
|
+
{
|
|
3907
|
+
resource: "attachment",
|
|
3908
|
+
summary: "file attachments for objects / comments / chat messages (local file upload)",
|
|
3909
|
+
actions: [
|
|
3910
|
+
{
|
|
3911
|
+
action: "upload",
|
|
3912
|
+
summary: "upload a local file and attach it to a task (--object) / comment (--comment) / chat message (--ag-message); for pure chat tasks pass --task <agentTaskId> to attach to the chat session; omit target to auto-merge (object if bound, else chat message)",
|
|
3913
|
+
args: [{ name: "file", required: true, description: "\u672C\u5730\u6587\u4EF6\u8DEF\u5F84" }],
|
|
3914
|
+
flags: [
|
|
3915
|
+
{ name: "object", type: "string", valueHint: "<id>", description: "\u6302\u5230\u5BF9\u8C61" },
|
|
3916
|
+
{ name: "comment", type: "string", valueHint: "<id>", description: "\u6302\u5230\u8BC4\u8BBA" },
|
|
3917
|
+
{ name: "ag-message", type: "boolean", description: "\u6302\u5230 Chat \u4F1A\u8BDD\u6700\u65B0\u6D88\u606F" },
|
|
3918
|
+
{ name: "task", type: "string", valueHint: "<agentTaskId>", description: "\u7EAF Chat \u4EFB\u52A1\u5F52\u5E76\u5230\u4F1A\u8BDD\u6D88\u606F" },
|
|
3919
|
+
{ name: "inline", type: "boolean", description: "\u5185\u8054\u9644\u4EF6" }
|
|
3920
|
+
],
|
|
3921
|
+
examples: ["morula attachment upload <file> --object <id>"],
|
|
3922
|
+
writes: "remote"
|
|
3923
|
+
},
|
|
3924
|
+
{
|
|
3925
|
+
action: "list",
|
|
3926
|
+
summary: "list attachments for an object",
|
|
3927
|
+
flags: [{ name: "object", type: "string", valueHint: "<id>", description: "\u5BF9\u8C61 ID\uFF08\u5FC5\u586B\uFF09", required: true }],
|
|
3928
|
+
examples: ["morula attachment list --object <id>"],
|
|
3929
|
+
writes: "none",
|
|
3930
|
+
idempotent: true
|
|
3931
|
+
},
|
|
3932
|
+
{
|
|
3933
|
+
action: "get",
|
|
3934
|
+
summary: "get attachment details",
|
|
3935
|
+
args: [{ name: "id", required: true, description: "\u9644\u4EF6 ID" }],
|
|
3936
|
+
flags: [],
|
|
3937
|
+
examples: ["morula attachment get <id>"],
|
|
3938
|
+
writes: "none",
|
|
3939
|
+
idempotent: true
|
|
3940
|
+
},
|
|
3941
|
+
{
|
|
3942
|
+
action: "content",
|
|
3943
|
+
summary: "read the parsed text content (MinerU markdown) of an attachment; unparsed/parsing/failed is reported in the body, not as an HTTP error",
|
|
3944
|
+
args: [{ name: "id", required: true, description: "\u9644\u4EF6 ID" }],
|
|
3945
|
+
flags: [{ name: "max-chars", type: "number", valueHint: "<n>", description: "\u6700\u5927\u8FD4\u56DE\u5B57\u7B26\u6570\uFF08\u670D\u52A1\u7AEF\u7F3A\u7701 8000\uFF09" }],
|
|
3946
|
+
examples: ["morula attachment content <id>", "morula attachment content <id> --max-chars 20000"],
|
|
3947
|
+
writes: "none",
|
|
3948
|
+
idempotent: true
|
|
3949
|
+
},
|
|
3950
|
+
{
|
|
3951
|
+
action: "download-url",
|
|
3952
|
+
summary: "get signed download URL for an attachment",
|
|
3953
|
+
args: [{ name: "id", required: true, description: "\u9644\u4EF6 ID" }],
|
|
3954
|
+
flags: [],
|
|
3955
|
+
examples: ["morula attachment download-url <id>"],
|
|
3956
|
+
writes: "none",
|
|
3957
|
+
idempotent: true
|
|
3958
|
+
},
|
|
3959
|
+
{
|
|
3960
|
+
action: "delete",
|
|
3961
|
+
summary: "delete attachment",
|
|
3962
|
+
args: [{ name: "id", required: true, description: "\u9644\u4EF6 ID" }],
|
|
3963
|
+
flags: [],
|
|
3964
|
+
examples: ["morula attachment delete <id>"],
|
|
3965
|
+
writes: "remote"
|
|
3966
|
+
}
|
|
3967
|
+
]
|
|
3968
|
+
}
|
|
3969
|
+
]
|
|
3970
|
+
};
|
|
3971
|
+
|
|
3972
|
+
// ../morula-cli/src/commands/steward.ts
|
|
3973
|
+
async function stewardCommand(context) {
|
|
3974
|
+
if (!context.runtime.token)
|
|
3975
|
+
throw new CliError("UNAUTHENTICATED", EXIT.UNAUTHENTICATED, "\u8BF7\u5148\u8FD0\u884C morula auth login");
|
|
3976
|
+
const { action, flags } = context.parsed;
|
|
3977
|
+
if (action === "get") {
|
|
3978
|
+
rejectUnknownFlags(flags, ["space"]);
|
|
3979
|
+
return context.client.stewards.get(requireFlag(flags, "space"));
|
|
3980
|
+
}
|
|
3981
|
+
if (action === "dispatch") {
|
|
3982
|
+
rejectUnknownFlags(flags, ["space", "title", "description", "state", "assignee", "repo", "client-message-id"]);
|
|
3983
|
+
const projectId = requireFlag(flags, "space");
|
|
3984
|
+
const title = requireFlag(flags, "title");
|
|
3985
|
+
const state = flagString(flags, "state");
|
|
3986
|
+
const description = flagString(flags, "description");
|
|
3987
|
+
const assigneePrincipalId = flagString(flags, "assignee");
|
|
3988
|
+
const repoFullName = flagString(flags, "repo");
|
|
3989
|
+
const clientMessageId = flagString(flags, "client-message-id");
|
|
3990
|
+
return context.client.stewards.dispatch(projectId, {
|
|
3991
|
+
title,
|
|
3992
|
+
...description !== void 0 ? { description } : {},
|
|
3993
|
+
...state !== void 0 ? { state } : {},
|
|
3994
|
+
...assigneePrincipalId !== void 0 ? { assigneePrincipalId } : {},
|
|
3995
|
+
...repoFullName !== void 0 ? { repoFullName } : {},
|
|
3996
|
+
...clientMessageId !== void 0 ? { clientMessageId } : {}
|
|
3997
|
+
});
|
|
3998
|
+
}
|
|
3999
|
+
throw usage("usage: morula steward <get|dispatch>");
|
|
2503
4000
|
}
|
|
2504
4001
|
|
|
2505
4002
|
// ../morula-cli/src/commands/task.ts
|
|
@@ -2598,7 +4095,7 @@ async function taskCommand(context) {
|
|
|
2598
4095
|
morula task get <objectId> # \u4E1A\u52A1\u4EFB\u52A1\uFF08Object\uFF09\u8BE6\u60C5\uFF08\u542B\u81EA\u5B9A\u4E49\u5B57\u6BB5\u503C\uFF09`);
|
|
2599
4096
|
return context.client.http.get(`/agent-tasks/${encodeURIComponent(taskId)}`);
|
|
2600
4097
|
}
|
|
2601
|
-
const id =
|
|
4098
|
+
const id = requireId4(positionals, "task get");
|
|
2602
4099
|
const task = await context.client.tasks.get(id);
|
|
2603
4100
|
if (!task)
|
|
2604
4101
|
return null;
|
|
@@ -2633,7 +4130,7 @@ async function taskCommand(context) {
|
|
|
2633
4130
|
}
|
|
2634
4131
|
if (action === "update") {
|
|
2635
4132
|
rejectUnknownFlags(flags, WRITE_FLAGS.filter((flag) => flag !== "space" && flag !== "owner"));
|
|
2636
|
-
const id =
|
|
4133
|
+
const id = requireId4(positionals, "task update");
|
|
2637
4134
|
const input = taskInput(flags, false);
|
|
2638
4135
|
const fieldSpecs = parseFieldFlags(flagString(flags, "field"));
|
|
2639
4136
|
if (!Object.keys(input).length && !flagString(flags, "field"))
|
|
@@ -2664,12 +4161,12 @@ async function taskCommand(context) {
|
|
|
2664
4161
|
}
|
|
2665
4162
|
if (action === "delete") {
|
|
2666
4163
|
rejectUnknownFlags(flags, []);
|
|
2667
|
-
const id =
|
|
4164
|
+
const id = requireId4(positionals, "task delete");
|
|
2668
4165
|
return context.client.tasks.delete(id);
|
|
2669
4166
|
}
|
|
2670
4167
|
if (action === "branch") {
|
|
2671
4168
|
rejectUnknownFlags(flags, ["name", "repo"]);
|
|
2672
|
-
const id =
|
|
4169
|
+
const id = requireId4(positionals, "task branch");
|
|
2673
4170
|
const branchName = requireFlag(flags, "name");
|
|
2674
4171
|
const runtimeId = context.env.MORULA_RUNTIME_ID;
|
|
2675
4172
|
if (!runtimeId)
|
|
@@ -2683,7 +4180,7 @@ async function taskCommand(context) {
|
|
|
2683
4180
|
}
|
|
2684
4181
|
if (action === "state") {
|
|
2685
4182
|
rejectUnknownFlags(flags, ["state"]);
|
|
2686
|
-
const id =
|
|
4183
|
+
const id = requireId4(positionals, "task state");
|
|
2687
4184
|
const stateCode = requireFlag(flags, "state");
|
|
2688
4185
|
const runtimeId = context.env.MORULA_RUNTIME_ID;
|
|
2689
4186
|
if (!runtimeId)
|
|
@@ -2695,7 +4192,7 @@ async function taskCommand(context) {
|
|
|
2695
4192
|
}
|
|
2696
4193
|
if (action === "analysis-verdict") {
|
|
2697
4194
|
rejectUnknownFlags(flags, ["verdict", "reason"]);
|
|
2698
|
-
const id =
|
|
4195
|
+
const id = requireId4(positionals, "task analysis-verdict");
|
|
2699
4196
|
const verdict = requireFlag(flags, "verdict");
|
|
2700
4197
|
if (verdict !== "ready" && verdict !== "blocked")
|
|
2701
4198
|
throw usage(`--verdict \u5FC5\u987B\u662F ready / blocked
|
|
@@ -2758,7 +4255,37 @@ async function taskCommand(context) {
|
|
|
2758
4255
|
...messages.length === 0 ? { hint: "\u672C\u7EBF\u7A0B\u6CA1\u6709\u65B0\u6D88\u606F\uFF1A\u6309\u539F\u8BA1\u5212\u7EE7\u7EED\uFF0C\u4E0D\u8981\u5C55\u5F00\u8BA8\u8BBA\u3002" } : {}
|
|
2759
4256
|
};
|
|
2760
4257
|
}
|
|
2761
|
-
|
|
4258
|
+
if (action === "agent-tasks") {
|
|
4259
|
+
rejectUnknownFlags(flags, ["object", "status", "page", "page-size"]);
|
|
4260
|
+
const objectId = requireFlag(flags, "object");
|
|
4261
|
+
return context.client.agentTasks.list(compact3({
|
|
4262
|
+
objectId,
|
|
4263
|
+
status: flagString(flags, "status"),
|
|
4264
|
+
page: flagNumber(flags, "page"),
|
|
4265
|
+
pageSize: flagNumber(flags, "page-size")
|
|
4266
|
+
}));
|
|
4267
|
+
}
|
|
4268
|
+
if (action === "cancel") {
|
|
4269
|
+
rejectUnknownFlags(flags, []);
|
|
4270
|
+
const id = requireId4(positionals, "task cancel");
|
|
4271
|
+
return context.client.agentTasks.cancel(id);
|
|
4272
|
+
}
|
|
4273
|
+
if (action === "rerun") {
|
|
4274
|
+
rejectUnknownFlags(flags, []);
|
|
4275
|
+
const id = requireId4(positionals, "task rerun");
|
|
4276
|
+
const result = await context.client.agentTasks.rerun(id);
|
|
4277
|
+
if (result?.ok === false)
|
|
4278
|
+
throw new CliError(result.code ?? "RERUN_FAILED", rerunExitCode(result.code), `\u91CD\u8DD1\u5931\u8D25: ${result.message ?? result.code ?? "\u672A\u77E5\u539F\u56E0"}`);
|
|
4279
|
+
return result;
|
|
4280
|
+
}
|
|
4281
|
+
throw usage("usage: morula task <list|create|get|update|delete|branch|state|analysis-verdict|inbox|agent-tasks|cancel|rerun>");
|
|
4282
|
+
}
|
|
4283
|
+
function rerunExitCode(code) {
|
|
4284
|
+
if (code === "NOT_FOUND")
|
|
4285
|
+
return EXIT.NOT_FOUND;
|
|
4286
|
+
if (code === "CONFLICT" || code === "ALREADY_QUEUED")
|
|
4287
|
+
return EXIT.CONFLICT;
|
|
4288
|
+
return EXIT.OTHER;
|
|
2762
4289
|
}
|
|
2763
4290
|
function taskInput(flags, create) {
|
|
2764
4291
|
const description = flagString(flags, "description");
|
|
@@ -2782,7 +4309,7 @@ function taskInput(flags, create) {
|
|
|
2782
4309
|
}
|
|
2783
4310
|
return values;
|
|
2784
4311
|
}
|
|
2785
|
-
function
|
|
4312
|
+
function requireId4(positionals, command) {
|
|
2786
4313
|
const id = positionals[0]?.trim();
|
|
2787
4314
|
if (!id)
|
|
2788
4315
|
throw usage(`usage: morula ${command} <id>`);
|
|
@@ -2799,13 +4326,19 @@ function unauthenticated() {
|
|
|
2799
4326
|
var COMMANDS = {
|
|
2800
4327
|
"attachment": attachmentCommand,
|
|
2801
4328
|
"auth": authCommand,
|
|
4329
|
+
"autopilot": autopilotCommand,
|
|
4330
|
+
"ci": ciCommand,
|
|
2802
4331
|
"comment": commentCommand,
|
|
4332
|
+
"dashboard": dashboardCommand,
|
|
4333
|
+
"document": documentCommand,
|
|
4334
|
+
"object-meta": objectMetaCommand,
|
|
2803
4335
|
"report": reportCommand,
|
|
2804
4336
|
"repo": repoCommand,
|
|
2805
4337
|
"review": reviewCommand,
|
|
2806
4338
|
"task": taskCommand,
|
|
2807
4339
|
"space": spaceCommand,
|
|
2808
|
-
"space-member": spaceMemberCommand
|
|
4340
|
+
"space-member": spaceMemberCommand,
|
|
4341
|
+
"steward": stewardCommand
|
|
2809
4342
|
};
|
|
2810
4343
|
var HELP = {
|
|
2811
4344
|
name: "morula",
|
|
@@ -2813,70 +4346,12 @@ var HELP = {
|
|
|
2813
4346
|
build: BUILD_ID,
|
|
2814
4347
|
summary: "Agent-first CLI for Morula task management. Success output is JSON on stdout; errors are JSON on stderr.",
|
|
2815
4348
|
usage: "morula <resource> <action> [id] [--flags]",
|
|
2816
|
-
commands:
|
|
2817
|
-
"auth": {
|
|
2818
|
-
login: "browser SkyDoor SSO using PKCE and loopback callback",
|
|
2819
|
-
logout: "remove the current context token",
|
|
2820
|
-
status: "show context, endpoint, and authentication state"
|
|
2821
|
-
},
|
|
2822
|
-
"task": {
|
|
2823
|
-
"list [--space <id>] [--mine] [--assignee <id>] [--page <n>] [--page-size <n>] [--search <text>] [--priority <low|medium|high|urgent>] [--state <id>]": "list tasks (--mine: \u4EC5\u6211\u8D1F\u8D23\u7684)",
|
|
2824
|
-
"create --space <id> --title <text> [--priority <value>] [--assignee <id>]": "create task",
|
|
2825
|
-
"get [id]": "get task details. No argument = the current AgentTask (id resolved from MORULA_TASK_ID / .morula/checkout.json). With an id = the business Object (title/description)",
|
|
2826
|
-
"update <id> [--title <text>] [--state <id>] [--priority <value>] [--sort-order <n>]": "update task (--state here is the business Object state id, NOT the AgentTask state code \u2014 see `task state`)",
|
|
2827
|
-
"delete <id>": "hard delete task",
|
|
2828
|
-
"branch <id> --name <name> [--repo <owner/name>]": "report the final branch name for an agent task (machine protocol; agent naming, runtimeId from env; --repo: secondary repo in a multi-repo task)",
|
|
2829
|
-
"state <id> --state <code>": "self-transition task state (machine protocol; agent drives todo\u2192in_progress\u2192review, runtimeId from env)",
|
|
2830
|
-
"analysis-verdict <taskId> --verdict <ready|blocked> [--reason <text>]": "report the task-analysis verdict (machine protocol; ready \u2192 platform auto-starts development, blocked \u2192 task stays in analysis)",
|
|
2831
|
-
"inbox [--peek]": "checkpoint: pull this thread's unconsumed messages into the current turn (machine protocol; --peek reads without marking them consumed)"
|
|
2832
|
-
},
|
|
2833
|
-
"space": {
|
|
2834
|
-
"list [--page <n>] [--page-size <n>] [--keyword <text>]": "list visible spaces",
|
|
2835
|
-
"get <id>": "get space details"
|
|
2836
|
-
},
|
|
2837
|
-
"space-member": {
|
|
2838
|
-
"list --space <id>": "list space members",
|
|
2839
|
-
"add --space <id> --principal <id> [--role <admin|member>]": "add member to space",
|
|
2840
|
-
"update <member-id> --role <admin|member>": "update member role",
|
|
2841
|
-
"remove <member-id>": "remove member from space"
|
|
2842
|
-
},
|
|
2843
|
-
"comment": {
|
|
2844
|
-
"list --object <id>": "list comments for an object",
|
|
2845
|
-
"get <id>": "get comment details",
|
|
2846
|
-
"add --object <id> --content <text> [--parent <id>] [--format markdown|plain|richtext]": "add comment (format auto-detected; use markdown for agent final summaries)",
|
|
2847
|
-
"update <id> --content <text>": "update comment",
|
|
2848
|
-
"delete <id>": "hard delete comment"
|
|
2849
|
-
},
|
|
2850
|
-
"review": {
|
|
2851
|
-
"submit <objectId> --verdict <approved|changes_requested|commented> [--details <text>] [--pr-number <n>]": "submit Code Review verdict (machine protocol; review task token)"
|
|
2852
|
-
},
|
|
2853
|
-
"report": {
|
|
2854
|
-
"create --title <text> [--content <markdown> | --content-file <path>] [--space <id>] [--autopilot <id>]": "create an autopilot report (\u6B63\u6587\u4E8C\u9009\u4E00\uFF1A--content \u77ED\u6B63\u6587 / --content-file \u957F Markdown\uFF1B--autopilot \u7701\u7565\u65F6\u6309\u5F53\u524D\u4EFB\u52A1\u53CD\u67E5\u6240\u5C5E\u81EA\u52A8\u5316)",
|
|
2855
|
-
"get <id>": "get report details (\u542B Markdown \u6B63\u6587)",
|
|
2856
|
-
"list --autopilot <id> [--page <n>] [--page-size <n>]": "list reports of an autopilot"
|
|
2857
|
-
},
|
|
2858
|
-
"repo": {
|
|
2859
|
-
"list --space <id>": "list task-space VCS connections (available repos; note: the system prompt already lists them for a task \u2014 you rarely need this)",
|
|
2860
|
-
"checkout <taskId> <repoFullName> [--ref <branch|sha>]": "materialize a repo into the task workdir (local daemon endpoint preferred, works same-turn; falls back to server machine protocol which resolves scope + workContext)",
|
|
2861
|
-
"prepare <taskId> <repoFullName>": "materialize a secondary repo into the task workdir (same level as the primary repo dir)",
|
|
2862
|
-
"mr create <repoFullName> --branch <branch> [--base <base>] [--task-code <code>]": "create a GitLab MR for the task via the server channel (target project forced to the bound repo, PR linked immediately; push the branch first)",
|
|
2863
|
-
"mr list <taskId> [--state opened|closed|merged] [--limit <n>] [--author <username>] [--repo <owner/name>]": "list the task-space repos' merge requests (read-only; includes createdAt/updatedAt/author; never approves/merges)",
|
|
2864
|
-
"mr comment <taskId> --mr <iid> [--repo <owner/name>] (--content <text> | --content-file <path>)": "write a review comment on an MR/PR (write-only: never approves or merges). \u5199\u4E4B\u524D\u5FC5\u987B\u5148 `morula repo mr get <taskId> --mr <iid> --notes` \u8BFB\u5DF2\u6709\u8BA8\u8BBA\uFF1A\u82E5\u672C\u81EA\u52A8\u5316\u5DF2\u5C31\u540C\u4E00\u95EE\u9898\u7559\u8FC7\u7ED3\u8BBA\u4E14\u7ED3\u8BBA\u672A\u53D8\uFF0C\u4E0D\u8981\u518D\u8BC4\u8BBA\u3002\u5185\u5BB9\u4E3A\u7ED3\u8BBA + \u5173\u952E\u95EE\u9898\uFF08\u6587\u4EF6:\u884C + \u5EFA\u8BAE\uFF09\uFF0C\u672B\u5C3E\u52A0\u7F72\u540D\u884C\u300C> \u7531\u81EA\u52A8\u5316\u300C<\u540D\u79F0>\u300D\u4E8E <\u65E5\u671F> \u751F\u6210\u300D\uFF1B\u4E0D\u8981\u8D34\u5927\u6BB5\u65E5\u5FD7\u6216\u590D\u8FF0 diff\uFF1B\u957F\u5185\u5BB9\u5199\u6210\u62A5\u544A\u540E\u7528\u6458\u8981\u5F15\u7528\uFF08morula report create \u2192 \u8BC4\u8BBA\u91CC\u7ED9\u8981\u70B9\uFF09",
|
|
2865
|
-
"mr get <taskId> --mr <iid> [--repo <owner/name>] [--ci] [--notes]": "get a single MR detail (read-only; --ci attaches pipeline status where none = no pipeline, not an error; --notes attaches existing comments \u2014 read this before writing a comment to avoid duplicates)",
|
|
2866
|
-
"mr diff <taskId> --mr <iid> [--repo <owner/name>] [--max-files <n>] [--max-chars <n>]": "read an MR diff via the server (read-only; works without a local checkout; truncated flag is set when output was capped)"
|
|
2867
|
-
},
|
|
2868
|
-
"attachment": {
|
|
2869
|
-
"upload <file> [--object <id>] [--comment <id>] [--ag-message] [--task <agentTaskId>] [--inline]": "upload a local file and attach it to a task (--object) / comment (--comment) / chat message (--ag-message); for pure chat tasks pass --task <agentTaskId> to attach to the chat session; omit target to auto-merge (object if bound, else chat message)",
|
|
2870
|
-
"list --object <id>": "list attachments for an object",
|
|
2871
|
-
"get <id>": "get attachment details",
|
|
2872
|
-
"download-url <id>": "get signed download URL for an attachment",
|
|
2873
|
-
"delete <id>": "delete attachment"
|
|
2874
|
-
}
|
|
2875
|
-
},
|
|
4349
|
+
commands: renderTopLevelCommands(SPEC),
|
|
2876
4350
|
globalFlags: {
|
|
2877
4351
|
"--env <context>": "select test or a saved context",
|
|
2878
4352
|
"--url <baseUrl>": "override API base URL",
|
|
2879
4353
|
"--token <token>": "override token for this invocation (not persisted)",
|
|
4354
|
+
"--json": "no-op; output is always JSON (accepted for familiarity)",
|
|
2880
4355
|
"--help": "print this machine-readable command surface",
|
|
2881
4356
|
"--version": "print version JSON"
|
|
2882
4357
|
},
|
|
@@ -2893,4 +4368,4 @@ var HELP = {
|
|
|
2893
4368
|
};
|
|
2894
4369
|
|
|
2895
4370
|
// ../morula-cli/src/index.ts
|
|
2896
|
-
runEntry({ commands: COMMANDS, help: HELP });
|
|
4371
|
+
runEntry({ commands: COMMANDS, help: HELP, spec: SPEC });
|