@arcships/morula-runtime 0.1.0-alpha.8 → 0.1.0-alpha.9
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 +294 -162
- package/dist/morula.js +27 -5
- package/dist/plugin/plugin.json +1 -1
- package/dist/plugin/skills/morula-cli/references/commands.md +2 -2
- package/dist/plugin/skills/morula-working-on-issues/SKILL.md +10 -0
- package/dist/plugin/skills/morula-working-on-issues/references/working-on-issues-source-map.md +1 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -740,7 +740,7 @@ var BUILD_ID, BUILD_CONTEXTS, BUILD_DEFAULT_CONTEXT;
|
|
|
740
740
|
var init_build_env = __esm({
|
|
741
741
|
"../morula-cli-core/dist/build-env.js"() {
|
|
742
742
|
"use strict";
|
|
743
|
-
BUILD_ID = "
|
|
743
|
+
BUILD_ID = "20260921135326.48e72dd8";
|
|
744
744
|
BUILD_CONTEXTS = {
|
|
745
745
|
"local": "http://localhost:8080/api",
|
|
746
746
|
"test": "https://morula.basecastle.com/api",
|
|
@@ -974,6 +974,27 @@ var init_ci = __esm({
|
|
|
974
974
|
});
|
|
975
975
|
|
|
976
976
|
// ../morula-api-client/dist/client.js
|
|
977
|
+
function describeFetchFailure(error) {
|
|
978
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
979
|
+
const detail = formatFetchCause(error?.cause);
|
|
980
|
+
return detail ? `${message} (cause: ${detail})` : message;
|
|
981
|
+
}
|
|
982
|
+
function formatFetchCause(cause) {
|
|
983
|
+
if (cause === void 0 || cause === null)
|
|
984
|
+
return "";
|
|
985
|
+
if (cause instanceof Error) {
|
|
986
|
+
const detail = cause;
|
|
987
|
+
const parts = [
|
|
988
|
+
typeof detail.code === "string" ? detail.code : "",
|
|
989
|
+
typeof detail.errno === "number" || typeof detail.errno === "string" ? `errno=${detail.errno}` : "",
|
|
990
|
+
typeof detail.syscall === "string" ? `syscall=${detail.syscall}` : "",
|
|
991
|
+
// cause 的 message 常与外层重复('fetch failed'),只有不同才带
|
|
992
|
+
detail.message && detail.message !== "fetch failed" ? detail.message : ""
|
|
993
|
+
].filter(Boolean);
|
|
994
|
+
return parts.join(" ").slice(0, CAUSE_DETAIL_MAX_LENGTH);
|
|
995
|
+
}
|
|
996
|
+
return String(cause).slice(0, CAUSE_DETAIL_MAX_LENGTH);
|
|
997
|
+
}
|
|
977
998
|
function sanitizeHeaderValue(raw, maxLength) {
|
|
978
999
|
if (!raw)
|
|
979
1000
|
return void 0;
|
|
@@ -1061,7 +1082,7 @@ function extractMessage(parsed, raw, status3) {
|
|
|
1061
1082
|
return raw.slice(0, 500);
|
|
1062
1083
|
return `HTTP ${status3}`;
|
|
1063
1084
|
}
|
|
1064
|
-
var EXIT_CODE, MorulaApiError, CLI_BUILD_HEADER, CLI_CAPS_HEADER, CLI_BUILD_MAX_LENGTH, CLI_CAPS_MAX_LENGTH, DEFAULT_TIMEOUT_MS, MorulaApiClient;
|
|
1085
|
+
var EXIT_CODE, MorulaApiError, CLI_BUILD_HEADER, CLI_CAPS_HEADER, CLI_BUILD_MAX_LENGTH, CLI_CAPS_MAX_LENGTH, DEFAULT_TIMEOUT_MS, CAUSE_DETAIL_MAX_LENGTH, MorulaApiClient;
|
|
1065
1086
|
var init_client = __esm({
|
|
1066
1087
|
"../morula-api-client/dist/client.js"() {
|
|
1067
1088
|
"use strict";
|
|
@@ -1098,6 +1119,7 @@ var init_client = __esm({
|
|
|
1098
1119
|
CLI_BUILD_MAX_LENGTH = 64;
|
|
1099
1120
|
CLI_CAPS_MAX_LENGTH = 255;
|
|
1100
1121
|
DEFAULT_TIMEOUT_MS = 3e4;
|
|
1122
|
+
CAUSE_DETAIL_MAX_LENGTH = 200;
|
|
1101
1123
|
MorulaApiClient = class {
|
|
1102
1124
|
baseUrl;
|
|
1103
1125
|
token;
|
|
@@ -1195,7 +1217,7 @@ var init_client = __esm({
|
|
|
1195
1217
|
if (controller.signal.aborted) {
|
|
1196
1218
|
throw new MorulaApiError("TIMEOUT", `request timed out after ${timeoutMs}ms`, EXIT_CODE.UPSTREAM, void 0, true);
|
|
1197
1219
|
}
|
|
1198
|
-
throw new MorulaApiError("NETWORK", `request failed: ${
|
|
1220
|
+
throw new MorulaApiError("NETWORK", `request failed: ${describeFetchFailure(error)}`, EXIT_CODE.UPSTREAM, void 0, true);
|
|
1199
1221
|
} finally {
|
|
1200
1222
|
clearTimeout(timer);
|
|
1201
1223
|
}
|
|
@@ -4125,7 +4147,7 @@ init_dist2();
|
|
|
4125
4147
|
init_dist2();
|
|
4126
4148
|
|
|
4127
4149
|
// src/build-env.ts
|
|
4128
|
-
var BUILD_VERSION2 = "0.1.0-alpha.
|
|
4150
|
+
var BUILD_VERSION2 = "0.1.0-alpha.9";
|
|
4129
4151
|
|
|
4130
4152
|
// src/commands/daemon.ts
|
|
4131
4153
|
init_dist();
|
|
@@ -4374,6 +4396,17 @@ var DaemonApi = class {
|
|
|
4374
4396
|
...token ? { token } : {}
|
|
4375
4397
|
});
|
|
4376
4398
|
}
|
|
4399
|
+
/**
|
|
4400
|
+
* 终态结果回传(§6.2-⑤)。
|
|
4401
|
+
*
|
|
4402
|
+
* `runtimeId` **必传**:服务端按它校验任务归属(不匹配 → `RUNTIME_MISMATCH`,不落终态),
|
|
4403
|
+
* 缺失同样被拒(P1-a 定案「立即拒绝」——旧版 daemon 的任务会全部失败,升级期须先升执行设备,
|
|
4404
|
+
* 见 issues/agent-task-false-failure-on-daemon-fetch-error.md)。
|
|
4405
|
+
*
|
|
4406
|
+
* `cancelled: true`(取消留痕,issues/daemon-stream-events-silently-stop-mid-run.md 未实施项 5):
|
|
4407
|
+
* 本轮**被人取消**时只补记已产出内容(`result.text` → 服务端 `agent_tasks.result.cancelled.lastOutput`),
|
|
4408
|
+
* **不改任务状态**、不触发生命周期。旧服务端经 `whitelist` 剥离该字段 → 退化为原「终态回传被幂等丢弃」。
|
|
4409
|
+
*/
|
|
4377
4410
|
submitResult(taskId, body) {
|
|
4378
4411
|
return this.taskRequest(taskId, `/agent-tasks/${taskId}/result`, { body });
|
|
4379
4412
|
}
|
|
@@ -4782,6 +4815,11 @@ var COLLABORATION_SKILL_BODY = `# Working on Morula issues\uFF08\u534F\u4F5C\u59
|
|
|
4782
4815
|
- **\u7A7A\u95F4\u4ED3\u5E93\u6E05\u5355**\uFF08\u591A\u4ED3\u5E93\u4EFB\u52A1\u5224\u65AD\u4F9D\u636E\uFF09\uFF1A\`morula repo list --space <spaceId>\`\u2014\u2014\u63D0\u793A\u8BCD\u4E0D\u5217\u4ED3\u5E93\uFF0C\u9700\u8981\u65F6\u81EA\u5DF1\u67E5\u3002
|
|
4783
4816
|
- **\u300C\u4F60\u7684\u76EE\u6807\u300D**\uFF1A\u7CFB\u7EDF\u63D0\u793A\u300C\u4F60\u7684\u76EE\u6807\u300D\u6BB5 = \u672C\u6B21\u4EFB\u52A1\u7684\u539F\u59CB\u8BC9\u6C42\uFF0C\u636E\u6B64\u5224\u65AD\u8981\u505A\u4EC0\u4E48\u3002
|
|
4784
4817
|
|
|
4818
|
+
> **\u8C03 CLI \u4E00\u5F8B\u7528 \`$MORULA_CLI\`**\uFF08daemon \u6CE8\u5165\u7684\u7EDD\u5BF9\u8DEF\u5F84\uFF0C\u6307\u5411\u4E0E\u672C\u6B21\u8FD0\u884C\u540C\u6E90\u7684\u6784\u5EFA\uFF1B\u4E0B\u6587\u6240\u6709 \`morula xxx\`
|
|
4819
|
+
> \u90FD\u6309 \`$MORULA_CLI xxx\` \u6267\u884C\uFF09\u3002PATH \u4E0A\u7684\u88F8 \`morula\` \u53EF\u80FD\u662F\u5BBF\u4E3B\u81EA\u5E26\u7684\u65E7\u7248\u672C\uFF08\u7F3A\u547D\u4EE4\u9762\u3001\u4E14\u4E0D\u8BA4\u4F1A\u8BDD/\u4EFB\u52A1
|
|
4820
|
+
> \u51ED\u8BC1 \u2192 \u5199\u64CD\u4F5C\u7F72\u540D\u9519\u8BEF\uFF09\uFF0C\u4E0D\u8981\u7528\u5B83\uFF1B\`env VAR=... $MORULA_CLI xxx\` \u8FD9\u7C7B env \u5305\u88C5\u4E0B\u540C\u6837\u53EF\u7528\u3002
|
|
4821
|
+
> \u4EC5\u5F53 \`$MORULA_CLI\` \u4E3A\u7A7A\u65F6\u624D\u9000\u56DE\u88F8 \`morula\`\u3002
|
|
4822
|
+
|
|
4785
4823
|
> **\u5DE5\u4F5C\u76EE\u5F55 = \u4EFB\u52A1\u5DE5\u4F5C\u533A\u6839**\uFF1A\u6839\u4E0B\u653E \`AGENTS.md\`\uFF08\u7A7A\u95F4\u9879\u76EE\u8BF4\u660E\uFF0C\u5DF2\u4F5C\u4E3A project.instructions \u81EA\u52A8\u52A0\u8F7D\uFF09\u3001
|
|
4786
4824
|
> \`.agents/\`\u3001\`.agent_context/\`\u3001\`.morula/\`\uFF1B**\u5404\u4ED3\u5E93\u662F\u5DE5\u4F5C\u533A\u6839\u4E0B\u7684\u5B50\u76EE\u5F55**\uFF08\u89C1 0.5\uFF09\u3002
|
|
4787
4825
|
> \u4E0B\u6587\u7684 \`AGENTS.md\`/\`.agents/\`/\`.agent_context/\` \u8DEF\u5F84\u90FD\u76F8\u5BF9\u8FD9\u4E2A\u5DE5\u4F5C\u533A\u6839\u3002
|
|
@@ -4789,6 +4827,11 @@ var COLLABORATION_SKILL_BODY = `# Working on Morula issues\uFF08\u534F\u4F5C\u59
|
|
|
4789
4827
|
> **\u4EFB\u52A1\u4E0A\u4E0B\u6587\u6587\u4EF6**\uFF1A\u540C\u4E00\u5957\u4E0A\u4E0B\u6587\u4E5F\u5199\u5728\u5DE5\u4F5C\u76EE\u5F55 \`.agent_context/task-context.md\`\uFF08\u4E0E\u9996\u6761\u7CFB\u7EDF\u63D0\u793A\u540C\u6E90\uFF09\u3002
|
|
4790
4828
|
> \u9700\u8981\u518D\u6B21\u786E\u8BA4\u4EFB\u52A1\u8FB9\u754C\u65F6**\u8BFB\u53D6\u8BE5\u6587\u4EF6**\uFF08\`cat .agent_context/task-context.md\`\uFF09\uFF0C\u4E0D\u8981\u51ED\u8BB0\u5FC6\u63A8\u65AD\u3002
|
|
4791
4829
|
|
|
4830
|
+
> **\u672C\u5951\u7EA6\u81EA\u8EAB\u7684\u8BFB\u53D6\u65B9\u5F0F**\uFF1A\u5951\u7EA6\u4EE5\u9879\u76EE\u7EA7 skill \u5F62\u5F0F\u6CE8\u5165\u5728 \`.agents/skills/morula-working-on-issues/SKILL.md\`\u3002
|
|
4831
|
+
> \u7528 \`skill\` \u5DE5\u5177\u6309\u540D\u52A0\u8F7D**\u53EF\u80FD\u62A5 \`Unknown skill\`**\uFF08\u8BE5\u5DE5\u5177\u7684\u53D1\u73B0\u8303\u56F4\u4E0D\u542B\u9879\u76EE\u7EA7\u76EE\u5F55\uFF09\u2014\u2014\u6B64\u65F6
|
|
4832
|
+
> **\u76F4\u63A5\u8BFB\u6587\u4EF6**\uFF08\`cat .agents/skills/morula-working-on-issues/SKILL.md\` \u6216 read \u5DE5\u5177\uFF09\uFF0C
|
|
4833
|
+
> **\u4E0D\u8981\u56E0\u4E3A\u52A0\u8F7D\u5931\u8D25\u5C31\u8DF3\u8FC7\u5951\u7EA6**\uFF08issues/injected-contract-skill-not-loadable-by-skill-tool.md\uFF09\u3002
|
|
4834
|
+
|
|
4792
4835
|
\u8BE6\u60C5\u89C1\u4E0B\u6587\u5404\u8282\u5BF9 TaskID / \u5BF9\u5916\u7F16\u53F7\u7684\u5177\u4F53\u7528\u6CD5\u3002
|
|
4793
4836
|
|
|
4794
4837
|
## 0.1 \u901A\u7528\u884C\u4E3A\u7EA6\u675F
|
|
@@ -5145,6 +5188,7 @@ var COLLABORATION_SKILL_SOURCE_MAP = `# morula-working-on-issues \u2014 \u5951\u
|
|
|
5145
5188
|
| CLI \u5199\u8BC4\u8BBA\uFF08**\u5951\u7EA6\u7981\u6B62 agent \u81EA\u884C\u8C03\u7528**\uFF1A\u5B8C\u6210\u8BC4\u8BBA\u7531\u670D\u52A1\u7AEF\u7EDF\u4E00\u53D1\u9001\uFF0C\u89C1\u672C\u6587\u4EF6\u7B2C 5 \u6761\uFF09 | \`morula comment add\`\uFF08\u547D\u4EE4\u5B58\u5728\uFF0C\u4F46\u672C\u5951\u7EA6\u8981\u6C42\u4E0D\u8C03\u7528\uFF09 | \`packages/morula-cli/src/commands/comment.ts\` |
|
|
5146
5189
|
| CLI \u4EFB\u52A1\u8BE6\u60C5\uFF08**\u65E0\u53C2**\u53D6\u672C\u4EFB\u52A1\uFF1B\u5E26\u53C2\u53D6\u4E1A\u52A1\u5BF9\u8C61\uFF09 | \`morula task get\` \u2192 \`GET /agent-tasks/:id\`\uFF1B\`morula task get <objectId>\` \u2192 \`GET /objects/:id\` | \`packages/morula-cli/src/commands/task.ts\` |
|
|
5147
5190
|
| daemon \u6CE8\u5165\u51ED\u636E\uFF08agent \u65E0\u9700\u81EA\u884C\u767B\u5F55\uFF09 | runner \u6CE8\u5165 \`env\` \u7ED9 Provider \u5B50\u8FDB\u7A0B | \`packages/runtime/src/daemon/runner.ts\` |
|
|
5191
|
+
| \u8C03 CLI \u7528 \`$MORULA_CLI\`\uFF08\u7EDD\u5BF9\u8DEF\u5F84\uFF0C\u4E0E\u5F53\u524D daemon \u540C\u6E90\uFF1BPATH \u4E0A\u7684\u88F8 \`morula\` \u53EF\u80FD\u662F\u5BBF\u4E3B\u81EA\u5E26\u7684\u65E7\u7248\uFF09 | \`resolveAgentCliPath\`\uFF08\u4F18\u5148\u672C\u5305 \`dist/morula.js\`\uFF0C\u4EA7\u7269\u7F3A\u5931\u56DE\u9000\u63D2\u4EF6\u542F\u52A8\u5668\uFF09\uFF1B\u6CE8\u5165\u70B9\uFF1A\u4EFB\u52A1\u94FE\u8DEF \`env\`\u3001\u4F1A\u8BDD\u94FE\u8DEF \`env\` | \`packages/runtime/src/daemon/plugin-register.ts\`\u3001\`runner.ts\`\u3001\`session-host.ts\` |
|
|
5148
5192
|
| \u7CFB\u7EDF\u63D0\u793A\u6CE8\u5165\uFF08\u8EAB\u4EFD\u4E0E\u8FB9\u754C = \u9636\u6BB5\u804C\u8D23 / \u76EE\u6807 / \u94A5\u5319 taskId+spaceId / \u5DE5\u5177\u5165\u53E3\u6307\u5F15\uFF09\uFF1B\u4EFB\u52A1\u8BE6\u60C5\u4E0E\u4ED3\u5E93\u6E05\u5355\u7531 \`morula task get\`\uFF08\u65E0\u53C2\uFF09\u3001\`morula repo list --space\` \u83B7\u53D6 | \`buildTaskPromptWithContract\`\uFF08\`runner.ts\`\uFF0C\u552F\u4E00\u8FDB dim \u7684 messages[0]\uFF09\uFF1BCLI \`packages/morula-cli/src/commands/task.ts\`\uFF08resolveTaskId \u2192 \`GET /agent-tasks/:id\`\uFF09 | \`packages/runtime/src/daemon/runner.ts\` |
|
|
5149
5193
|
| \u8FD0\u884C\u4E2D\u68C0\u67E5\u70B9\uFF08\u672C\u56DE\u5408\u5185\u53D6\u7528\u6237\u610F\u89C1\uFF09 | CLI \`morula task inbox [--peek]\` \u2192 \`GET /agent-tasks/:id/thread/inbox\`\uFF08\u673A\u5668\u534F\u8BAE\uFF1B\u9ED8\u8BA4\u53D6\u8D70\u5373\u6D88\u8D39\uFF0C\u843D \`consumed\` + \u5F53\u56DE\u5408\u53F7\uFF09\uFF1B\u5951\u7EA6\u65F6\u673A\u89C1\u672C SKILL 1.3 | \`packages/morula-cli/src/commands/task.ts\`\u3001\`src/modules/agent-task/chat/object-agent-chat.controller.ts\`\u3001\`object-agent-message.service.ts\`\uFF08\`getThreadInbox\`\uFF09 |
|
|
5150
5194
|
| \u8FD0\u884C\u4E2D\u6253\u65AD\uFF08\u540C\u4E00\u4F1A\u8BDD\u91CD\u5F00\u4E00\u8F6E\uFF09 | daemon \u5728\u5B89\u5168\u70B9\uFF08\`inFlightTools === 0\`\uFF09\`session/cancel\` \u2192 \`session/resume\` \u2192 \u7528\u65B0\u610F\u89C1\u91CD\u5F00 prompt\uFF1B\u56DE\u5408\u53F7\u4E0E\u4E2D\u65AD\u70B9\u4E0A\u62A5\u4E3A \`turn_started\` / \`turn_interrupted\` \u4E8B\u4EF6 | \`packages/runtime/src/daemon/acp/dim-acp-executor.ts\`\uFF08\u56DE\u5408\u5FAA\u73AF\uFF09\u3001\`runner.ts\`\uFF08\`buildSteerPort\`\uFF09\u3001\`src/modules/agent-task/chat/object-agent-message.service.ts\`\uFF08\`steerDeliveryStrategy\`\uFF09 |
|
|
@@ -5490,6 +5534,13 @@ function pluginBinDir(env = process.env, home = homedir10()) {
|
|
|
5490
5534
|
function pluginBinPath(env = process.env, home = homedir10()) {
|
|
5491
5535
|
return join13(pluginBinDir(env, home), "morula");
|
|
5492
5536
|
}
|
|
5537
|
+
function ownCliEntryPath(moduleUrl = import.meta.url) {
|
|
5538
|
+
const entry = join13(resolvePackagePaths(moduleUrl).packageRoot, "dist", "morula.js");
|
|
5539
|
+
return existsSync9(entry) ? entry : null;
|
|
5540
|
+
}
|
|
5541
|
+
function resolveAgentCliPath(moduleUrl = import.meta.url, env = process.env, home = homedir10()) {
|
|
5542
|
+
return ownCliEntryPath(moduleUrl) ?? pluginBinPath(env, home);
|
|
5543
|
+
}
|
|
5493
5544
|
function prependPluginBinToPath(currentPath, env = process.env, home = homedir10()) {
|
|
5494
5545
|
const binDir = pluginBinDir(env, home);
|
|
5495
5546
|
const segments = (currentPath ?? "").split(":").filter(Boolean);
|
|
@@ -6782,11 +6833,18 @@ function ownerOf(repoFullName) {
|
|
|
6782
6833
|
const idx = repoFullName.indexOf("/");
|
|
6783
6834
|
return idx > 0 ? repoFullName.slice(0, idx) : "_default";
|
|
6784
6835
|
}
|
|
6785
|
-
function
|
|
6786
|
-
return
|
|
6836
|
+
function runtimePathSegment(runtimeId) {
|
|
6837
|
+
return runtimeId.slice(0, 8);
|
|
6787
6838
|
}
|
|
6788
|
-
function
|
|
6789
|
-
const
|
|
6839
|
+
function buildRepoCachePath(workdir, tenantId, runtimeId, repoFullName) {
|
|
6840
|
+
const runtimeSegment = runtimePathSegment(runtimeId);
|
|
6841
|
+
if (!runtimeSegment) {
|
|
6842
|
+
throw new Error("REPO_CACHE_RUNTIME_ID_MISSING: \u7F3A\u5C11 runtimeId\uFF0C\u65E0\u6CD5\u6784\u9020\u6309\u6267\u884C\u8005\u9694\u79BB\u7684 repo cache \u8DEF\u5F84");
|
|
6843
|
+
}
|
|
6844
|
+
return join15(workdir, "repos", tenantId, runtimeSegment, ownerOf(repoFullName), repoFullName);
|
|
6845
|
+
}
|
|
6846
|
+
function openRepoCache(workdir, tenantId, runtimeId, repoFullName, env, agentRemoteUrl, daemonRemoteUrl) {
|
|
6847
|
+
const repoCachePath = buildRepoCachePath(workdir, tenantId, runtimeId, repoFullName);
|
|
6790
6848
|
const currentOrigin = () => {
|
|
6791
6849
|
if (!existsSync11(join15(repoCachePath, ".git")))
|
|
6792
6850
|
return null;
|
|
@@ -6885,7 +6943,7 @@ function safeDirName(name) {
|
|
|
6885
6943
|
return safe || "task";
|
|
6886
6944
|
}
|
|
6887
6945
|
function buildTaskRootPath(workdir, tenantId, runtimeId, workContextId, code) {
|
|
6888
|
-
const runtimeSegment = runtimeId
|
|
6946
|
+
const runtimeSegment = runtimePathSegment(runtimeId);
|
|
6889
6947
|
if (!runtimeSegment) {
|
|
6890
6948
|
throw new Error("WORKTREE_RUNTIME_ID_MISSING: \u7F3A\u5C11 runtimeId\uFF0C\u65E0\u6CD5\u6784\u9020\u6309\u6267\u884C\u8005\u9694\u79BB\u7684 worktree \u8DEF\u5F84");
|
|
6891
6949
|
}
|
|
@@ -7120,7 +7178,7 @@ function reportForeignResidue(worktreePath, forensics, cleaned) {
|
|
|
7120
7178
|
console.warn(`[daemon] ${detail}`);
|
|
7121
7179
|
}
|
|
7122
7180
|
function prepareWorktree(input) {
|
|
7123
|
-
const cache = openRepoCache(input.workdir, input.tenantId, input.repoFullName, input.env, input.remoteUrl, input.daemonRemoteUrl);
|
|
7181
|
+
const cache = openRepoCache(input.workdir, input.tenantId, input.runtimeId, input.repoFullName, input.env, input.remoteUrl, input.daemonRemoteUrl);
|
|
7124
7182
|
cache.ensure();
|
|
7125
7183
|
cache.fetch();
|
|
7126
7184
|
const requestedBase = input.baseBranch?.trim();
|
|
@@ -7603,6 +7661,7 @@ var LocalRepoCheckoutService = class {
|
|
|
7603
7661
|
const cache = openRepoCache(
|
|
7604
7662
|
this.opts.cfg.workdir,
|
|
7605
7663
|
this.opts.tenantId,
|
|
7664
|
+
this.runtimeId,
|
|
7606
7665
|
repoFullName,
|
|
7607
7666
|
env,
|
|
7608
7667
|
baseUrl ? buildGitlabSshRemote(repoFullName, baseUrl) : void 0,
|
|
@@ -7667,6 +7726,7 @@ var LocalRepoCheckoutService = class {
|
|
|
7667
7726
|
const cache = openRepoCache(
|
|
7668
7727
|
this.opts.cfg.workdir,
|
|
7669
7728
|
this.opts.tenantId,
|
|
7729
|
+
this.runtimeId,
|
|
7670
7730
|
repoFullName,
|
|
7671
7731
|
env,
|
|
7672
7732
|
baseUrl ? buildGitlabSshRemote(repoFullName, baseUrl) : void 0,
|
|
@@ -7921,144 +7981,6 @@ function materializeAdditionalRepo(input) {
|
|
|
7921
7981
|
return input.targetPath;
|
|
7922
7982
|
}
|
|
7923
7983
|
|
|
7924
|
-
// src/daemon/task-messages.ts
|
|
7925
|
-
var TASK_MESSAGE_QUEUE_MAX = 200;
|
|
7926
|
-
function asRecord(value) {
|
|
7927
|
-
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
7928
|
-
}
|
|
7929
|
-
function asNonEmptyString(value) {
|
|
7930
|
-
return typeof value === "string" && value.length > 0 ? value : null;
|
|
7931
|
-
}
|
|
7932
|
-
function normalizeAgentMessage(value) {
|
|
7933
|
-
const row = asRecord(value);
|
|
7934
|
-
if (!row)
|
|
7935
|
-
return null;
|
|
7936
|
-
const id = asNonEmptyString(row.id);
|
|
7937
|
-
if (!id)
|
|
7938
|
-
return null;
|
|
7939
|
-
const seq = row.seq;
|
|
7940
|
-
if (typeof seq !== "number" || !Number.isFinite(seq))
|
|
7941
|
-
return null;
|
|
7942
|
-
return {
|
|
7943
|
-
id,
|
|
7944
|
-
seq,
|
|
7945
|
-
authorType: typeof row.authorType === "string" ? row.authorType : "unknown",
|
|
7946
|
-
authorPrincipalId: asNonEmptyString(row.authorPrincipalId),
|
|
7947
|
-
authorName: asNonEmptyString(row.authorName),
|
|
7948
|
-
content: typeof row.content === "string" ? row.content : "",
|
|
7949
|
-
mode: typeof row.mode === "string" ? row.mode : "queue",
|
|
7950
|
-
deliveryState: typeof row.deliveryState === "string" ? row.deliveryState : "pending",
|
|
7951
|
-
deliveryError: asNonEmptyString(row.deliveryError),
|
|
7952
|
-
targetTaskId: asNonEmptyString(row.targetTaskId),
|
|
7953
|
-
anchorEventSeq: typeof row.anchorEventSeq === "number" ? row.anchorEventSeq : null,
|
|
7954
|
-
turnNo: typeof row.turnNo === "number" ? row.turnNo : null,
|
|
7955
|
-
createdAt: typeof row.createdAt === "string" ? row.createdAt : ""
|
|
7956
|
-
};
|
|
7957
|
-
}
|
|
7958
|
-
function parseTaskMessageFrame(value) {
|
|
7959
|
-
const frame = asRecord(value);
|
|
7960
|
-
if (!frame)
|
|
7961
|
-
return null;
|
|
7962
|
-
const taskId = asNonEmptyString(frame.taskId);
|
|
7963
|
-
if (!taskId || !Array.isArray(frame.messages))
|
|
7964
|
-
return null;
|
|
7965
|
-
const messages = frame.messages.map(normalizeAgentMessage).filter((message) => message !== null);
|
|
7966
|
-
if (messages.length === 0)
|
|
7967
|
-
return null;
|
|
7968
|
-
return {
|
|
7969
|
-
type: "agent-task:message",
|
|
7970
|
-
taskId,
|
|
7971
|
-
objectId: asNonEmptyString(frame.objectId),
|
|
7972
|
-
anchorKey: typeof frame.anchorKey === "string" ? frame.anchorKey : "",
|
|
7973
|
-
messages
|
|
7974
|
-
};
|
|
7975
|
-
}
|
|
7976
|
-
function upsertTaskMessages(existing, incoming, max = TASK_MESSAGE_QUEUE_MAX) {
|
|
7977
|
-
const byId = /* @__PURE__ */ new Map();
|
|
7978
|
-
for (const message of existing)
|
|
7979
|
-
byId.set(message.id, message);
|
|
7980
|
-
for (const message of incoming)
|
|
7981
|
-
byId.set(message.id, message);
|
|
7982
|
-
const merged = [...byId.values()].sort((a, b) => a.seq - b.seq || a.id.localeCompare(b.id));
|
|
7983
|
-
const dropped = Math.max(0, merged.length - max);
|
|
7984
|
-
return { messages: dropped > 0 ? merged.slice(dropped) : merged, dropped };
|
|
7985
|
-
}
|
|
7986
|
-
function selectConsumedMessages(messages, taskId) {
|
|
7987
|
-
return messages.filter((message) => message.targetTaskId === taskId);
|
|
7988
|
-
}
|
|
7989
|
-
function selectSteerMessages(messages, taskId) {
|
|
7990
|
-
return messages.filter((message) => message.mode === "steer").filter((message) => message.deliveryState !== "consumed" && message.deliveryState !== "withdrawn").filter((message) => message.targetTaskId === taskId).sort((a, b) => a.seq - b.seq);
|
|
7991
|
-
}
|
|
7992
|
-
function renderMessageList(messages) {
|
|
7993
|
-
return messages.map((message) => `${message.seq}. \u3010${message.authorType === "user" ? "\u4EBA" : message.authorType === "system" ? "\u5E73\u53F0" : "\u8FD0\u884C\u65F6"}\u3011${message.content}`).join("\n\n");
|
|
7994
|
-
}
|
|
7995
|
-
function buildSteerPrompt(input) {
|
|
7996
|
-
const opinions = input.messages.length > 0 ? renderMessageList(input.messages) : "\uFF08\u6253\u65AD\u8BF7\u6C42\u672A\u88AB\u53D6\u5230\uFF0C\u8BF7\u6309\u539F\u59CB\u9700\u6C42\u7EE7\u7EED\uFF09";
|
|
7997
|
-
const resetNote = input.sessionReset ? "\n- \u26A0\uFE0F \u4F1A\u8BDD\u5DF2\u91CD\u5EFA\uFF1A\u4E0A\u4E00\u56DE\u5408\u7684\u5BF9\u8BDD\u4E0A\u4E0B\u6587**\u672A\u4FDD\u7559**\uFF0C\u8BF7\u4EE5\u672C\u56DE\u5408\u7ED9\u51FA\u7684\u4FE1\u606F\u4E3A\u51C6\uFF08\u5DE5\u4F5C\u533A\u6587\u4EF6\u4E0E git \u72B6\u6001\u4ECD\u5728\uFF09\u3002" : "";
|
|
7998
|
-
const originalPrompt = input.taskPrompt?.trim() ? `
|
|
7999
|
-
|
|
8000
|
-
\u3010\u539F\u59CB\u4EFB\u52A1\u9700\u6C42\uFF08\u672C\u8F6E\u662F\u540C\u4E00\u6B21\u5DE5\u4F5C\u7684\u5EF6\u7EED\uFF09\u3011
|
|
8001
|
-
${input.taskPrompt.trim()}` : "";
|
|
8002
|
-
return `\u3010\u8FD0\u884C\u4E2D\u6253\u65AD \xB7 \u8BF7\u5148\u6309\u8FD9\u4E9B\u610F\u89C1\u8C03\u6574\uFF0C\u518D\u7EE7\u7EED\u3011
|
|
8003
|
-
\u4F60\u6B63\u5728\u6267\u884C\u7B2C ${input.turnNo - 1} \u56DE\u5408\uFF0C\u4EBA\u5728\u8FD0\u884C\u8FC7\u7A0B\u4E2D\u63D0\u51FA\u4E86\u4EE5\u4E0B\u610F\u89C1\uFF08\u6309\u63D0\u51FA\u987A\u5E8F\uFF09\uFF1A
|
|
8004
|
-
|
|
8005
|
-
${opinions}
|
|
8006
|
-
|
|
8007
|
-
\u8981\u6C42\uFF1A
|
|
8008
|
-
1. \u5148\u9010\u6761\u5904\u7406\u4E0A\u8FF0\u610F\u89C1\uFF0C\u518D\u7EE7\u7EED\u5B8C\u6210\u672C\u4EFB\u52A1\uFF1B\u610F\u89C1\u4E0E\u539F\u59CB\u9700\u6C42\u51B2\u7A81\u65F6**\u4EE5\u610F\u89C1\u4E3A\u51C6**\uFF0C\u5E76\u5728\u6700\u7EC8\u603B\u7ED3\u91CC\u8BF4\u660E\u5DEE\u5F02\u3002
|
|
8009
|
-
2. \u4E0D\u8981\u63A8\u7FFB\u4E0A\u8FF0\u610F\u89C1\u672A\u6D89\u53CA\u7684\u90E8\u5206\uFF1B\u5DF2\u7ECF\u5B8C\u6210\u4E14\u4E0D\u5728\u610F\u89C1\u8303\u56F4\u5185\u7684\u6539\u52A8\u4FDD\u7559\u3002
|
|
8010
|
-
3. \u4E0A\u4E00\u56DE\u5408\u5728\u5B89\u5168\u70B9\u88AB\u4E2D\u65AD\uFF0C\u5176\u4E2D\u7684\u5DE5\u5177\u8FDB\u5EA6\u5DF2\u4E22\u5F03\u3001\u88AB\u4E2D\u65AD\u7684\u8C03\u7528**\u6CA1\u6709\u7ED3\u679C**\uFF08\u65F6\u95F4\u7EBF\u4E0A\u6807\u4E3A\u5DF2\u4E2D\u65AD\uFF09\u2014\u2014\u9700\u8981\u65F6\u91CD\u65B0\u6267\u884C\uFF0C\u4E0D\u8981\u5047\u5B9A\u5B83\u5DF2\u6210\u529F\u3002${resetNote}${originalPrompt}`;
|
|
8011
|
-
}
|
|
8012
|
-
|
|
8013
|
-
// src/daemon/stage-contracts.ts
|
|
8014
|
-
var STAGE_CONTRACTS = {
|
|
8015
|
-
todo: `## \u672C\u4EFB\u52A1\u9636\u6BB5\uFF1A\u5F85\u5206\u6790\uFF08\u9700\u6C42\u5206\u6790\uFF09
|
|
8016
|
-
|
|
8017
|
-
\u53EA\u505A\u9700\u6C42\u5206\u6790\uFF0C\u4E0D\u5199\u4EE3\u7801\uFF1A\u5224\u65AD\u9700\u6C42\u662F\u5426\u6E05\u6670\u53EF\u5F00\u53D1\uFF0C\u4EA7\u51FA\u53EF\u6267\u884C\u7684\u65B9\u6848\u3001\u8303\u56F4\u4E0E\u98CE\u9669\u3001\u9A8C\u6536\u70B9\uFF0C\u4E3A\u5F00\u53D1\u63D0\u4F9B\u8F93\u5165\u3002\u4E0D\u5EFA\u5206\u652F\u3001\u4E0D\u63D0 PR\u3002
|
|
8018
|
-
|
|
8019
|
-
\u7ED3\u8BBA\u5FC5\u987B\u4EE5\u673A\u5668\u534F\u8BAE\u4E0A\u62A5\uFF08\u547D\u4EE4\u7528\u6CD5\u89C1 \`morula-working-on-issues\` skill \u4E0E \`morula task --help\`\uFF09\uFF0C\u5426\u5219\u4EFB\u52A1\u4F1A\u505C\u5728\u300C\u5F85\u5206\u6790\u300D\u3002`,
|
|
8020
|
-
in_progress: `## \u672C\u4EFB\u52A1\u9636\u6BB5\uFF1A\u5F00\u53D1\u5B9E\u73B0
|
|
8021
|
-
|
|
8022
|
-
\u6309\u4EFB\u52A1\u63CF\u8FF0\u4E0E\u5206\u6790\u7ED3\u8BBA\u5B8C\u6210\u4EE3\u7801\u6539\u52A8\uFF0C\u672C\u5730\u81EA\u9A8C\u8BC1\uFF08\u6784\u5EFA/\u6D4B\u8BD5\uFF09\u901A\u8FC7\u540E\u63D0\u4EA4 MR\u3002\u53EA\u505A\u6700\u5C0F\u5FC5\u8981\u6539\u52A8\uFF0C\u4E0D\u505A\u65E0\u5173\u91CD\u6784\uFF1B\u4E0D\u5408\u5E76 MR\u3001\u4E0D\u505A\u8BC4\u5BA1\u7ED3\u8BBA\u3002
|
|
8023
|
-
|
|
8024
|
-
\u63D0\u4EA4 MR \u5FC5\u987B\u8D70\u5E73\u53F0\u901A\u9053\uFF08\u7528\u6CD5\u89C1 \`morula-working-on-issues\` skill \u4E0E \`morula repo --help\`\uFF09\uFF1B\u88AB\u73AF\u5883\u963B\u65AD\u65F6\u5982\u5B9E\u62A5\u544A\u963B\u585E\u539F\u56E0\uFF08PR_BLOCKED + \u539F\u56E0\uFF09\uFF0C\u4E0D\u8981\u5047\u88C5\u5B8C\u6210\u3002`,
|
|
8025
|
-
review: `## \u672C\u4EFB\u52A1\u9636\u6BB5\uFF1ACode Review
|
|
8026
|
-
|
|
8027
|
-
\u53EA\u8BFB\u8BC4\u5BA1\uFF0C\u4E0D\u4FEE\u6539\u4EE3\u7801\uFF1A\u57FA\u4E8E**\u771F\u5B9E diff**\uFF08PR \u5206\u652F\u76F8\u5BF9\u76EE\u6807\u5206\u652F\uFF09\u8BC4\u4F30\u6B63\u786E\u6027 / \u5B89\u5168\u6027 / \u98CE\u683C / \u6D4B\u8BD5\u8986\u76D6 / \u662F\u5426\u7B26\u5408\u539F\u59CB\u9700\u6C42\uFF0C\u7ED9\u51FA\u660E\u786E\u7ED3\u8BBA\u4E0E\u5177\u4F53\u610F\u89C1\u3002\u4E0D\u5EFA\u5206\u652F\u3001\u4E0D\u5408\u5E76 MR\u3001\u4E0D\u8BC4\u5BA1\u81EA\u5DF1\u5F00\u53D1\u7684\u4EFB\u52A1\u3002
|
|
8028
|
-
|
|
8029
|
-
\u7ED3\u8BBA\u5FC5\u987B\u4EE5\u673A\u5668\u534F\u8BAE\u4E0A\u62A5\uFF08\u547D\u4EE4\u7528\u6CD5\u89C1 \`morula-working-on-issues\` skill \u4E0E \`morula review --help\`\uFF09\uFF0C\u672A\u4E0A\u62A5\u5219\u4EFB\u52A1\u505C\u5728\u300C\u5F85\u8BC4\u5BA1\u300D\u3002`
|
|
8030
|
-
};
|
|
8031
|
-
var AUTOPILOT_CONTRACT = `## \u672C\u4EFB\u52A1\uFF1A\u81EA\u52A8\u5316\u5DE1\u68C0\uFF08\u7531\u300C\u81EA\u52A8\u5316\u300D\u7684\u5B9A\u65F6 / Webhook / \u624B\u52A8\u89E6\u53D1\uFF09
|
|
8032
|
-
|
|
8033
|
-
\u6309\u4EFB\u52A1\u8BF4\u660E\uFF08runbook\uFF09\u6267\u884C\uFF0C\u4EA7\u51FA**\u62A5\u544A**\uFF1A\`morula report create --title <\u6807\u9898> --content-file <md>\`
|
|
8034
|
-
\uFF08\u7701\u7565 --autopilot \u65F6\u670D\u52A1\u7AEF\u81EA\u52A8\u5F52\u5C5E\u672C\u81EA\u52A8\u5316\uFF1B\u957F\u5185\u5BB9\u4E00\u5F8B\u7528 --content-file\uFF09\u3002
|
|
8035
|
-
|
|
8036
|
-
- \u53EA\u8BFB\u4E3A\u4E3B\uFF1A\u4E0D\u6539\u4E1A\u52A1\u6570\u636E\u3001\u4E0D\u5EFA\u5206\u652F\u3001\u4E0D\u63D0 PR\uFF08\u9664\u975E\u4EFB\u52A1\u8BF4\u660E\u660E\u786E\u8981\u6C42\uFF09\u3002
|
|
8037
|
-
- \u7ED3\u8BBA\u5199\u8FDB\u6700\u7EC8\u8F93\u51FA\uFF0C\u5E76\u540C\u6B65\u843D\u4E00\u4EFD\u62A5\u544A\uFF1B\u62A5\u544A\u91CC\u7ED9\u300C\u6587\u4EF6:\u884C + \u4E25\u91CD\u5EA6 + \u5EFA\u8BAE\u300D\u8FD9\u7C7B\u53EF\u6267\u884C\u4FE1\u606F\u3002
|
|
8038
|
-
- \u4E0D\u8981\u8C03\u7528 \`morula task state\` / \`morula task analysis-verdict\` / \`morula review submit\`\uFF1A
|
|
8039
|
-
\u672C\u4EFB\u52A1\u6CA1\u6709\u5173\u8054\u4E1A\u52A1\u4EFB\u52A1\uFF0C\u8FD9\u4E9B\u8C03\u7528\u4F1A\u88AB\u5E73\u53F0\u62D2\u7EDD\u3002
|
|
8040
|
-
- \u9700\u8981\u5728 MR \u4E0A\u7559\u8BC4\u5BA1\u610F\u89C1\u65F6\u7528 \`morula repo mr comment\`\uFF08\u53EA\u5199\u8BC4\u8BBA\uFF0C\u4E0D approve\u3001\u4E0D merge\uFF09\u3002
|
|
8041
|
-
**\u5199\u4E4B\u524D\u5FC5\u987B\u5148 \`morula repo mr get <taskId> --mr <iid> --notes\` \u8BFB\u5DF2\u6709\u8BA8\u8BBA**\uFF1A
|
|
8042
|
-
\u5982\u679C\u672C\u81EA\u52A8\u5316\u5DF2\u5C31\u540C\u4E00\u95EE\u9898\u7559\u8FC7\u8BC4\u8BBA\u3001\u7ED3\u8BBA\u4E0E\u8FD9\u6B21\u4E00\u81F4\uFF0C\u5C31\u4E0D\u8981\u518D\u8BC4\u8BBA\uFF08\u5E73\u53F0\u4E0D\u505A\u53BB\u91CD\uFF0C\u91CD\u590D\u7531\u4F60\u907F\u514D\uFF09\uFF1B
|
|
8043
|
-
\u53EA\u6709\u51FA\u73B0\u65B0\u95EE\u9898\u6216\u7ED3\u8BBA\u53D8\u5316\u65F6\u624D\u5199\u65B0\u8BC4\u8BBA\u3002\u8BC4\u8BBA\u672B\u5C3E\u5E26\u7F72\u540D\u884C \`> \u7531\u81EA\u52A8\u5316\u300C<\u540D\u79F0>\u300D\u4E8E <\u65E5\u671F> \u751F\u6210\`\uFF0C
|
|
8044
|
-
\u4F9B\u4F60\u81EA\u5DF1\u5728\u4E0B\u4E00\u8F6E\u8BC6\u522B\u5386\u53F2\u8BC4\u8BBA\u3002
|
|
8045
|
-
|
|
8046
|
-
## \u80FD\u529B\u5165\u53E3\uFF08\u6267\u884C\u65B9\u5F0F\u7531\u5E73\u53F0\u8D1F\u8D23\uFF0C\u4EFB\u52A1\u8BF4\u660E\u91CC\u4E0D\u4F1A\u5199\u8FD9\u4E9B\uFF09
|
|
8047
|
-
|
|
8048
|
-
- \u672C\u4EFB\u52A1\u4E0E\u5E73\u53F0\u4EA4\u4E92**\u53EA\u80FD**\u901A\u8FC7 \`morula\` CLI\uFF1A\u672C\u4EFB\u52A1**\u6CA1\u6709**\u5E73\u53F0\u5DE5\u5177 / MCP \u8C03\u7528\u9762
|
|
8049
|
-
\uFF08\`create_object\`\u3001\`create_report\` \u8FD9\u7C7B\u5DE5\u5177\u5728\u672C\u4EFB\u52A1\u5185\u4E0D\u53EF\u7528\uFF09\uFF1B\u547D\u4EE4\u53C2\u6570\u4EE5 \`morula <resource> --help\` \u4E3A\u51C6\u3002
|
|
8050
|
-
- \u4ED3\u5E93\u8BFB\u53D6\u4E0E\u6539\u52A8\u3001\u5DE5\u4F5C\u533A\u5E03\u5C40\u3001\u5206\u652F\u4E0E MR \u89C4\u5219\u89C1\u5DF2\u6CE8\u5165\u7684\u534F\u4F5C\u5951\u7EA6 skill\uFF08\xA70.5 \u4ED3\u5E93\u4E0E\u5DE5\u4F5C\u76EE\u5F55\uFF09\u3002
|
|
8051
|
-
- \u8981\u7ED9\u4EBA\u751F\u6210\u5F85\u8DDF\u8FDB\u7684\u4EFB\u52A1\uFF1A\`morula task create --space <spaceId> --title <\u6807\u9898> --description <\u5185\u5BB9>\`
|
|
8052
|
-
\uFF08\`<spaceId>\` \u53D6 \`morula task get\` \u8FD4\u56DE\u7684 \`contextSnapshot\`\uFF09\uFF1B\u65B0\u5EFA\u4EFB\u52A1\u9ED8\u8BA4\u843D\u300C\u5F85\u89C4\u5212\u300D\uFF0C
|
|
8053
|
-
\u7531\u4EBA\u786E\u8BA4\u540E\u518D\u6D3E\u53D1\u4FEE\u590D\u3002\u62A5\u544A\u4E0E\u4EFB\u52A1\u662F\u4E24\u4E2A\u57DF\uFF0C\u4E0D\u8981\u628A\u5F85\u529E\u4E8B\u9879\u5199\u8FDB\u62A5\u544A\u6B63\u6587\u5F53\u4EFB\u52A1\u7528\u3002`;
|
|
8054
|
-
function buildStageContract(stageCode, source) {
|
|
8055
|
-
if (source === "autopilot")
|
|
8056
|
-
return AUTOPILOT_CONTRACT;
|
|
8057
|
-
if (!stageCode)
|
|
8058
|
-
return "";
|
|
8059
|
-
return STAGE_CONTRACTS[stageCode] ?? "";
|
|
8060
|
-
}
|
|
8061
|
-
|
|
8062
7984
|
// src/daemon/session-host.ts
|
|
8063
7985
|
init_dist2();
|
|
8064
7986
|
init_acp_connection();
|
|
@@ -8142,6 +8064,7 @@ var STEWARD_SKILL_BODY = `# \u7A7A\u95F4\u7BA1\u5BB6\u5951\u7EA6\uFF08Morula\uFF
|
|
|
8142
8064
|
- **\u6240\u6709\u67E5\u8BE2\u90FD\u8981\u663E\u5F0F\u5E26 \`--space\`**\uFF08= \u5F53\u524D\u7A7A\u95F4 ID\uFF0C\u89C1 \`.agent_context/steward-context.md\`\uFF09\u3002
|
|
8143
8065
|
- \u65B0\u9700\u6C42**\u4E00\u5F8B\u8D70\u6D3E\u5355**\uFF0C\u4E0D\u8981\u81EA\u5DF1\u52A8\u624B\u5B9E\u73B0\uFF0C\u4E5F\u4E0D\u8981\u7528\u300C\u59D4\u6258\u5B50\u4EE3\u7406\u300D\u7C7B\u624B\u6BB5\u7ED5\u5F00\u6D3E\u5355\u94FE\u8DEF\u3002
|
|
8144
8066
|
- **\u7834\u574F\u6027\u52A8\u4F5C\u5FC5\u987B\u5148\u8981\u4EBA\u786E\u8BA4**\uFF1A\u5220\u9664\u4EFB\u52A1\u3001\u53D6\u6D88\u6B63\u5728\u8DD1\u7684\u6267\u884C\u3001\u91CD\u8DD1\u5931\u8D25\u4EFB\u52A1\u3001**\u91CD\u8DD1\u5931\u8D25\u7684 CI \u6D41\u6C34\u7EBF / job**\u3001\u628A\u72B6\u6001\u63A8\u8FDB\u5230\u300C\u5DF2\u5408\u5E76 / \u5DF2\u53D1\u5E03 / \u5DF2\u5173\u95ED\u300D\u2014\u2014\u7528**\u7ED3\u6784\u5316\u63D0\u95EE\u5DE5\u5177**\u53D1\u786E\u8BA4\u8868\u5355\uFF0C\u62FF\u5230\u7528\u6237\u7B54\u590D\u540E\u518D\u6267\u884C\u3002\u53EF\u9006\u7684\u8BB0\u5F55\u4E0E\u6D41\u8F6C\uFF08\u6539\u5C5E\u6027\u3001\u6539\u8D1F\u8D23\u4EBA\u3001\`backlog \u21C4 todo\` \u63A8\u8FDB\uFF09\u4E0D\u9700\u8981\u786E\u8BA4\u3002
|
|
8067
|
+
- **\u63A2\u67E5\u547D\u4EE4\u9762\u53EA\u7528 \`--help\`\uFF0C\u4E0D\u8981\u62FF\u771F\u5B9E\u5199\u547D\u4EE4\u8BD5\u8DD1**\uFF1A\u60F3\u786E\u8BA4\u67D0\u6761\u547D\u4EE4\u6216\u53C2\u6570\u5B58\u4E0D\u5B58\u5728\u3001\u5F62\u6001\u5BF9\u4E0D\u5BF9\uFF0C\u5C31\u770B \`$MORULA_CLI <cmd> --help\`\uFF08\u4F8B\u5982 \`$MORULA_CLI ci retry --help\`\uFF09\u3002\u5199\u547D\u4EE4**\u6267\u884C\u5373\u751F\u6548**\uFF08\`morula ci retry\` \u6267\u884C\u5373\u91CD\u8DD1\u3001\`morula task delete\` \u6267\u884C\u5373\u5220\u9664\uFF09\uFF0C\u6CA1\u6709\u300C\u53EA\u8BFB\u63A2\u67E5\u300D\u5F62\u6001\u2014\u2014\u4E3A\u300C\u770B\u770B\u8FD9\u6761\u547D\u4EE4\u5728\u4E0D\u5728\u300D\u800C\u771F\u8DD1\u4E00\u6B21\u5199\u547D\u4EE4\uFF0C\u5C31\u662F\u4E00\u6B21\u672A\u7ECF\u786E\u8BA4\u7684\u4E0D\u53EF\u9006\u64CD\u4F5C\uFF08\u771F\u673A\u4E8B\u6545\uFF1A\u7BA1\u5BB6\u786E\u8BA4 \`ci retry\` \u662F\u5426\u5B58\u5728\u65F6\u771F\u7684\u91CD\u8DD1\u4E86\u4E00\u6761\u6D41\u6C34\u7EBF\uFF09\u3002
|
|
8145
8068
|
|
|
8146
8069
|
## 1. \u5E38\u7528\u547D\u4EE4\uFF08\u5168\u90E8\u663E\u5F0F\u53C2\u6570\uFF09
|
|
8147
8070
|
|
|
@@ -8172,6 +8095,8 @@ morula ci retry --space <spaceId> [--run <runId>] [--job <jobId>] #
|
|
|
8172
8095
|
**\u4E0D\u80FD\u89E6\u53D1\u90E8\u7F72**\uFF08\u89E6\u53D1\u624B\u52A8 job \u6C38\u8FDC\u7531\u4EBA\u505A\uFF1A\u4F60\u6CA1\u6709\u8BE5\u547D\u4EE4\uFF0C\u4E5F\u4E0D\u8981\u8BD5\u56FE\u7ED5\u8FC7\uFF09\u3002
|
|
8173
8096
|
- **\u91CD\u8DD1\u5FC5\u987B\u5148\u8981\u4EBA\u786E\u8BA4**\uFF1A\u7528**\u7ED3\u6784\u5316\u63D0\u95EE\u5DE5\u5177**\u53D1\u786E\u8BA4\u5361\uFF08\u5199\u6E05\u54EA\u6761\u6D41\u6C34\u7EBF / \u54EA\u4E2A job\u3001\u5931\u8D25\u539F\u56E0\u3001\u4E3A\u4EC0\u4E48\u5EFA\u8BAE\u91CD\u8DD1\uFF09\uFF0C
|
|
8174
8097
|
\u62FF\u5230\u7528\u6237\u7B54\u590D\u540E\u518D\u6267\u884C \`morula ci retry\`\u3002\u5B83\u4E0E \`morula task rerun\` \u540C\u6863\uFF08\u300C\u9700\u4EBA\u786E\u8BA4\u300D\uFF09\u3002
|
|
8098
|
+
- **\u786E\u8BA4\u547D\u4EE4\u9762\u7528 \`$MORULA_CLI ci --help\`\uFF08\u6216 \`ci retry --help\`\uFF09\uFF0C\u4E0D\u8981\u7528\u771F\u5B9E\u5199\u547D\u4EE4\u8BD5\u8DD1**\uFF1A
|
|
8099
|
+
\`morula ci retry\` \u6CA1\u6709\u53EA\u8BFB\u9884\u6F14\u5F62\u6001\uFF0C\u6267\u884C\u5C31\u662F\u4E00\u6B21\u771F\u5B9E\u91CD\u8DD1\uFF1B\u53C2\u6570\u5F62\u6001\u4E0D\u786E\u5B9A\u5C31\u770B \`--help\` \u8F93\u51FA\uFF0C\u4E0D\u8981\u62FF\u771F\u5B9E\u8FD0\u884C\u53BB\u8BD5\u3002
|
|
8175
8100
|
- \u91CD\u8DD1\u53EA\u5BF9**\u5931\u8D25\u6216\u5DF2\u53D6\u6D88**\u7684\u8FD0\u884C / job \u6709\u6548\uFF1B\u72B6\u6001\u4E0D\u7B26\u4F1A\u660E\u786E\u62A5\u9519\uFF08\`CI_RETRY_NOT_ALLOWED\`\uFF09\uFF0C\u4E0D\u8981\u53CD\u590D\u91CD\u8BD5\u540C\u6837\u7684\u8C03\u7528\u3002
|
|
8176
8101
|
- \u91CD\u8DD1\u540E**\u56DE\u8BFB\u4E00\u6B21**\uFF08\`morula ci status --space <id>\`\uFF09\u518D\u6C47\u62A5\u2014\u2014\u300C\u5DF2\u91CD\u8DD1\u300D\u8981\u7528\u72B6\u6001\u8BF4\u8BDD\uFF0C\u4E0D\u80FD\u53EA\u770B\u9000\u51FA\u7801\u3002
|
|
8177
8102
|
- \u6D41\u6C34\u7EBF\u72B6\u6001\u662F**\u5E73\u53F0\u4E8B\u5B9E**\uFF08\u6765\u81EA VCS \u5E73\u53F0\u4E8B\u4EF6\uFF09\uFF0C\u4E0D\u662F\u67D0\u4E2A agent \u7684\u81EA\u8FF0\uFF1B\u88C1\u5B9A\u4E0E\u6C47\u62A5\u4EE5\u5B83\u4E3A\u51C6\u3002
|
|
@@ -8211,7 +8136,7 @@ morula steward dispatch --space <spaceId> --title "<\u4E00\u53E5\u8BDD\u76EE\u68
|
|
|
8211
8136
|
### \u591A\u4ED3\u5E93\u7A7A\u95F4\uFF08\u7A7A\u95F4\u7ED1\u5B9A\u4E86\u591A\u4E2A\u4ED3\u5E93\u65F6\uFF09
|
|
8212
8137
|
|
|
8213
8138
|
- \u88C1\u5B9A\u65F6\u53EF\u7ED3\u5408\u4ED3\u5E93\u6E05\u5355\u7ED9\u51FA**\u65B9\u5411\u7EA7**\u5224\u65AD\uFF08\u8FD9\u4E2A\u9700\u6C42\u5927\u6982\u6D89\u53CA\u54EA\u4E9B\u4ED3\u5E93\uFF09\uFF0C\u4F46\u300C\u6BCF\u4E2A\u4ED3\u5E93\u5177\u4F53\u6539\u4EC0\u4E48\u300D\u7531\u5F85\u5206\u6790\u8FD0\u884C\u65F6\u5728\u5206\u6790\u4EFB\u52A1\u4E2D\u4EA7\u51FA\uFF1B\u4E0D\u786E\u5B9A\u5C31\u5199\u300C\u5177\u4F53\u6D89\u53CA\u4ED3\u5E93\u4EE5\u5206\u6790\u7ED3\u8BBA\u4E3A\u51C6\u300D\uFF0C\u4E0D\u8981\u51ED\u7A7A\u65AD\u8A00\u3002
|
|
8214
|
-
- **\u6D3E\u5355\u65F6\u5FC5\u987B\u628A\u6D89\u53CA\u4ED3\u5E93\u4F20\u7ED9 \`--repo\`**\uFF08\u5199\u4ED3\u5E93\u540D\uFF0C\u5982
|
|
8139
|
+
- **\u6D3E\u5355\u65F6\u5FC5\u987B\u628A\u6D89\u53CA\u4ED3\u5E93\u4F20\u7ED9 \`--repo\`**\uFF08\u5199\u4ED3\u5E93\u540D\uFF0C\u5982 \`<owner>/<repo>\`\uFF1B**\u540D\u5B57\u53EA\u80FD\u53D6\u81EA\u672C\u7A7A\u95F4\u4ED3\u5E93\u6E05\u5355\u91CC\u5B9E\u9645\u51FA\u73B0\u8FC7\u7684\u4ED3\u5E93\uFF0C\u4E0D\u5F97\u7167\u6284\u793A\u4F8B**\uFF09\uFF1A\u591A\u4ED3\u5E93\u7A7A\u95F4\u91CC\u5B83\u662F\u4EFB\u52A1\u300C\u5173\u8054\u4ED3\u5E93\u300D\u7684\u552F\u4E00\u786E\u5B9A\u6027\u6765\u6E90\uFF0C\u7F3A\u5931\u4F1A\u5BFC\u81F4\u8BE5\u4EFB\u52A1\u4E0D\u521B\u5EFA\u5BF9\u5E94 Issue\u3001\u4E5F\u65E0\u6CD5\u5728\u4EFB\u52A1\u91CC\u770B\u51FA\u8BE5\u6539\u54EA\u4E2A\u4ED3\u5E93\u3002\u5224\u65AD\u4E0D\u51FA\u552F\u4E00\u4ED3\u5E93\u65F6**\u7559\u7A7A**\uFF0C\u4E0D\u8981\u778E\u586B\u3002
|
|
8215
8140
|
|
|
8216
8141
|
### \u7BA1\u7406\u4EFB\u52A1\uFF08\u6539\u5C5E\u6027 / \u63A8\u8FDB\u72B6\u6001 / \u5EFA\u5355 / \u5220\u5355\uFF09
|
|
8217
8142
|
\`\`\`bash
|
|
@@ -8358,9 +8283,10 @@ var SessionHost = class {
|
|
|
8358
8283
|
// 新命令不存在,且旧 CLI 不认 MORULA_SESSION_TOKEN(回落用户凭证)→ 写操作署名错、
|
|
8359
8284
|
// 写面作用域校验被绕过。PATH 只是第一道保险(dim 会重写 agent shell 的 PATH),
|
|
8360
8285
|
// 可靠的是 `MORULA_CLI` 绝对路径(契约要求 agent 用它)。
|
|
8361
|
-
//
|
|
8286
|
+
// MORULA_CLI 优先本包自带入口(与当前会话同源),产物缺失才回退插件启动器。
|
|
8287
|
+
// 见 issues/steward-cli-resolves-stale-bundled-morula.md、issues/agent-cli-stale-build-missing-steward-commands.md。
|
|
8362
8288
|
PATH: prependPluginBinToPath(process.env.PATH),
|
|
8363
|
-
MORULA_CLI:
|
|
8289
|
+
MORULA_CLI: resolveAgentCliPath(),
|
|
8364
8290
|
...this.options.isolatedDimEnv ?? {}
|
|
8365
8291
|
};
|
|
8366
8292
|
const onExit = (code) => {
|
|
@@ -8864,6 +8790,144 @@ ${fileRefs.join("\n")}` : text }];
|
|
|
8864
8790
|
}
|
|
8865
8791
|
};
|
|
8866
8792
|
|
|
8793
|
+
// src/daemon/stage-contracts.ts
|
|
8794
|
+
var STAGE_CONTRACTS = {
|
|
8795
|
+
todo: `## \u672C\u4EFB\u52A1\u9636\u6BB5\uFF1A\u5F85\u5206\u6790\uFF08\u9700\u6C42\u5206\u6790\uFF09
|
|
8796
|
+
|
|
8797
|
+
\u53EA\u505A\u9700\u6C42\u5206\u6790\uFF0C\u4E0D\u5199\u4EE3\u7801\uFF1A\u5224\u65AD\u9700\u6C42\u662F\u5426\u6E05\u6670\u53EF\u5F00\u53D1\uFF0C\u4EA7\u51FA\u53EF\u6267\u884C\u7684\u65B9\u6848\u3001\u8303\u56F4\u4E0E\u98CE\u9669\u3001\u9A8C\u6536\u70B9\uFF0C\u4E3A\u5F00\u53D1\u63D0\u4F9B\u8F93\u5165\u3002\u4E0D\u5EFA\u5206\u652F\u3001\u4E0D\u63D0 PR\u3002
|
|
8798
|
+
|
|
8799
|
+
\u7ED3\u8BBA\u5FC5\u987B\u4EE5\u673A\u5668\u534F\u8BAE\u4E0A\u62A5\uFF08\u547D\u4EE4\u7528\u6CD5\u89C1 \`morula-working-on-issues\` skill \u4E0E \`morula task --help\`\uFF09\uFF0C\u5426\u5219\u4EFB\u52A1\u4F1A\u505C\u5728\u300C\u5F85\u5206\u6790\u300D\u3002`,
|
|
8800
|
+
in_progress: `## \u672C\u4EFB\u52A1\u9636\u6BB5\uFF1A\u5F00\u53D1\u5B9E\u73B0
|
|
8801
|
+
|
|
8802
|
+
\u6309\u4EFB\u52A1\u63CF\u8FF0\u4E0E\u5206\u6790\u7ED3\u8BBA\u5B8C\u6210\u4EE3\u7801\u6539\u52A8\uFF0C\u672C\u5730\u81EA\u9A8C\u8BC1\uFF08\u6784\u5EFA/\u6D4B\u8BD5\uFF09\u901A\u8FC7\u540E\u63D0\u4EA4 MR\u3002\u53EA\u505A\u6700\u5C0F\u5FC5\u8981\u6539\u52A8\uFF0C\u4E0D\u505A\u65E0\u5173\u91CD\u6784\uFF1B\u4E0D\u5408\u5E76 MR\u3001\u4E0D\u505A\u8BC4\u5BA1\u7ED3\u8BBA\u3002
|
|
8803
|
+
|
|
8804
|
+
\u63D0\u4EA4 MR \u5FC5\u987B\u8D70\u5E73\u53F0\u901A\u9053\uFF08\u7528\u6CD5\u89C1 \`morula-working-on-issues\` skill \u4E0E \`morula repo --help\`\uFF09\uFF1B\u88AB\u73AF\u5883\u963B\u65AD\u65F6\u5982\u5B9E\u62A5\u544A\u963B\u585E\u539F\u56E0\uFF08PR_BLOCKED + \u539F\u56E0\uFF09\uFF0C\u4E0D\u8981\u5047\u88C5\u5B8C\u6210\u3002`,
|
|
8805
|
+
review: `## \u672C\u4EFB\u52A1\u9636\u6BB5\uFF1ACode Review
|
|
8806
|
+
|
|
8807
|
+
\u53EA\u8BFB\u8BC4\u5BA1\uFF0C\u4E0D\u4FEE\u6539\u4EE3\u7801\uFF1A\u57FA\u4E8E**\u771F\u5B9E diff**\uFF08PR \u5206\u652F\u76F8\u5BF9\u76EE\u6807\u5206\u652F\uFF09\u8BC4\u4F30\u6B63\u786E\u6027 / \u5B89\u5168\u6027 / \u98CE\u683C / \u6D4B\u8BD5\u8986\u76D6 / \u662F\u5426\u7B26\u5408\u539F\u59CB\u9700\u6C42\uFF0C\u7ED9\u51FA\u660E\u786E\u7ED3\u8BBA\u4E0E\u5177\u4F53\u610F\u89C1\u3002\u4E0D\u5EFA\u5206\u652F\u3001\u4E0D\u5408\u5E76 MR\u3001\u4E0D\u8BC4\u5BA1\u81EA\u5DF1\u5F00\u53D1\u7684\u4EFB\u52A1\u3002
|
|
8808
|
+
|
|
8809
|
+
\u7ED3\u8BBA\u5FC5\u987B\u4EE5\u673A\u5668\u534F\u8BAE\u4E0A\u62A5\uFF08\u547D\u4EE4\u7528\u6CD5\u89C1 \`morula-working-on-issues\` skill \u4E0E \`morula review --help\`\uFF09\uFF0C\u672A\u4E0A\u62A5\u5219\u4EFB\u52A1\u505C\u5728\u300C\u5F85\u8BC4\u5BA1\u300D\u3002`
|
|
8810
|
+
};
|
|
8811
|
+
var AUTOPILOT_CONTRACT = `## \u672C\u4EFB\u52A1\uFF1A\u81EA\u52A8\u5316\u5DE1\u68C0\uFF08\u7531\u300C\u81EA\u52A8\u5316\u300D\u7684\u5B9A\u65F6 / Webhook / \u624B\u52A8\u89E6\u53D1\uFF09
|
|
8812
|
+
|
|
8813
|
+
\u6309\u4EFB\u52A1\u8BF4\u660E\uFF08runbook\uFF09\u6267\u884C\uFF0C\u4EA7\u51FA**\u62A5\u544A**\uFF1A\`morula report create --title <\u6807\u9898> --content-file <md>\`
|
|
8814
|
+
\uFF08\u7701\u7565 --autopilot \u65F6\u670D\u52A1\u7AEF\u81EA\u52A8\u5F52\u5C5E\u672C\u81EA\u52A8\u5316\uFF1B\u957F\u5185\u5BB9\u4E00\u5F8B\u7528 --content-file\uFF09\u3002
|
|
8815
|
+
|
|
8816
|
+
- \u53EA\u8BFB\u4E3A\u4E3B\uFF1A\u4E0D\u6539\u4E1A\u52A1\u6570\u636E\u3001\u4E0D\u5EFA\u5206\u652F\u3001\u4E0D\u63D0 PR\uFF08\u9664\u975E\u4EFB\u52A1\u8BF4\u660E\u660E\u786E\u8981\u6C42\uFF09\u3002
|
|
8817
|
+
- \u7ED3\u8BBA\u5199\u8FDB\u6700\u7EC8\u8F93\u51FA\uFF0C\u5E76\u540C\u6B65\u843D\u4E00\u4EFD\u62A5\u544A\uFF1B\u62A5\u544A\u91CC\u7ED9\u300C\u6587\u4EF6:\u884C + \u4E25\u91CD\u5EA6 + \u5EFA\u8BAE\u300D\u8FD9\u7C7B\u53EF\u6267\u884C\u4FE1\u606F\u3002
|
|
8818
|
+
- \u4E0D\u8981\u8C03\u7528 \`morula task state\` / \`morula task analysis-verdict\` / \`morula review submit\`\uFF1A
|
|
8819
|
+
\u672C\u4EFB\u52A1\u6CA1\u6709\u5173\u8054\u4E1A\u52A1\u4EFB\u52A1\uFF0C\u8FD9\u4E9B\u8C03\u7528\u4F1A\u88AB\u5E73\u53F0\u62D2\u7EDD\u3002
|
|
8820
|
+
- \u9700\u8981\u5728 MR \u4E0A\u7559\u8BC4\u5BA1\u610F\u89C1\u65F6\u7528 \`morula repo mr comment\`\uFF08\u53EA\u5199\u8BC4\u8BBA\uFF0C\u4E0D approve\u3001\u4E0D merge\uFF09\u3002
|
|
8821
|
+
**\u5199\u4E4B\u524D\u5FC5\u987B\u5148 \`morula repo mr get <taskId> --mr <iid> --notes\` \u8BFB\u5DF2\u6709\u8BA8\u8BBA**\uFF1A
|
|
8822
|
+
\u5982\u679C\u672C\u81EA\u52A8\u5316\u5DF2\u5C31\u540C\u4E00\u95EE\u9898\u7559\u8FC7\u8BC4\u8BBA\u3001\u7ED3\u8BBA\u4E0E\u8FD9\u6B21\u4E00\u81F4\uFF0C\u5C31\u4E0D\u8981\u518D\u8BC4\u8BBA\uFF08\u5E73\u53F0\u4E0D\u505A\u53BB\u91CD\uFF0C\u91CD\u590D\u7531\u4F60\u907F\u514D\uFF09\uFF1B
|
|
8823
|
+
\u53EA\u6709\u51FA\u73B0\u65B0\u95EE\u9898\u6216\u7ED3\u8BBA\u53D8\u5316\u65F6\u624D\u5199\u65B0\u8BC4\u8BBA\u3002\u8BC4\u8BBA\u672B\u5C3E\u5E26\u7F72\u540D\u884C \`> \u7531\u81EA\u52A8\u5316\u300C<\u540D\u79F0>\u300D\u4E8E <\u65E5\u671F> \u751F\u6210\`\uFF0C
|
|
8824
|
+
\u4F9B\u4F60\u81EA\u5DF1\u5728\u4E0B\u4E00\u8F6E\u8BC6\u522B\u5386\u53F2\u8BC4\u8BBA\u3002
|
|
8825
|
+
|
|
8826
|
+
## \u80FD\u529B\u5165\u53E3\uFF08\u6267\u884C\u65B9\u5F0F\u7531\u5E73\u53F0\u8D1F\u8D23\uFF0C\u4EFB\u52A1\u8BF4\u660E\u91CC\u4E0D\u4F1A\u5199\u8FD9\u4E9B\uFF09
|
|
8827
|
+
|
|
8828
|
+
- \u672C\u4EFB\u52A1\u4E0E\u5E73\u53F0\u4EA4\u4E92**\u53EA\u80FD**\u901A\u8FC7 \`morula\` CLI\uFF1A\u672C\u4EFB\u52A1**\u6CA1\u6709**\u5E73\u53F0\u5DE5\u5177 / MCP \u8C03\u7528\u9762
|
|
8829
|
+
\uFF08\`create_object\`\u3001\`create_report\` \u8FD9\u7C7B\u5DE5\u5177\u5728\u672C\u4EFB\u52A1\u5185\u4E0D\u53EF\u7528\uFF09\uFF1B\u547D\u4EE4\u53C2\u6570\u4EE5 \`morula <resource> --help\` \u4E3A\u51C6\u3002
|
|
8830
|
+
- \u4ED3\u5E93\u8BFB\u53D6\u4E0E\u6539\u52A8\u3001\u5DE5\u4F5C\u533A\u5E03\u5C40\u3001\u5206\u652F\u4E0E MR \u89C4\u5219\u89C1\u5DF2\u6CE8\u5165\u7684\u534F\u4F5C\u5951\u7EA6 skill\uFF08\xA70.5 \u4ED3\u5E93\u4E0E\u5DE5\u4F5C\u76EE\u5F55\uFF09\u3002
|
|
8831
|
+
- \u8981\u7ED9\u4EBA\u751F\u6210\u5F85\u8DDF\u8FDB\u7684\u4EFB\u52A1\uFF1A\`morula task create --space <spaceId> --title <\u6807\u9898> --description <\u5185\u5BB9>\`
|
|
8832
|
+
\uFF08\`<spaceId>\` \u53D6 \`morula task get\` \u8FD4\u56DE\u7684 \`contextSnapshot\`\uFF09\uFF1B\u65B0\u5EFA\u4EFB\u52A1\u9ED8\u8BA4\u843D\u300C\u5F85\u89C4\u5212\u300D\uFF0C
|
|
8833
|
+
\u7531\u4EBA\u786E\u8BA4\u540E\u518D\u6D3E\u53D1\u4FEE\u590D\u3002\u62A5\u544A\u4E0E\u4EFB\u52A1\u662F\u4E24\u4E2A\u57DF\uFF0C\u4E0D\u8981\u628A\u5F85\u529E\u4E8B\u9879\u5199\u8FDB\u62A5\u544A\u6B63\u6587\u5F53\u4EFB\u52A1\u7528\u3002`;
|
|
8834
|
+
function buildStageContract(stageCode, source) {
|
|
8835
|
+
if (source === "autopilot")
|
|
8836
|
+
return AUTOPILOT_CONTRACT;
|
|
8837
|
+
if (!stageCode)
|
|
8838
|
+
return "";
|
|
8839
|
+
return STAGE_CONTRACTS[stageCode] ?? "";
|
|
8840
|
+
}
|
|
8841
|
+
|
|
8842
|
+
// src/daemon/task-messages.ts
|
|
8843
|
+
var TASK_MESSAGE_QUEUE_MAX = 200;
|
|
8844
|
+
function asRecord(value) {
|
|
8845
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
8846
|
+
}
|
|
8847
|
+
function asNonEmptyString(value) {
|
|
8848
|
+
return typeof value === "string" && value.length > 0 ? value : null;
|
|
8849
|
+
}
|
|
8850
|
+
function normalizeAgentMessage(value) {
|
|
8851
|
+
const row = asRecord(value);
|
|
8852
|
+
if (!row)
|
|
8853
|
+
return null;
|
|
8854
|
+
const id = asNonEmptyString(row.id);
|
|
8855
|
+
if (!id)
|
|
8856
|
+
return null;
|
|
8857
|
+
const seq = row.seq;
|
|
8858
|
+
if (typeof seq !== "number" || !Number.isFinite(seq))
|
|
8859
|
+
return null;
|
|
8860
|
+
return {
|
|
8861
|
+
id,
|
|
8862
|
+
seq,
|
|
8863
|
+
authorType: typeof row.authorType === "string" ? row.authorType : "unknown",
|
|
8864
|
+
authorPrincipalId: asNonEmptyString(row.authorPrincipalId),
|
|
8865
|
+
authorName: asNonEmptyString(row.authorName),
|
|
8866
|
+
content: typeof row.content === "string" ? row.content : "",
|
|
8867
|
+
mode: typeof row.mode === "string" ? row.mode : "queue",
|
|
8868
|
+
deliveryState: typeof row.deliveryState === "string" ? row.deliveryState : "pending",
|
|
8869
|
+
deliveryError: asNonEmptyString(row.deliveryError),
|
|
8870
|
+
targetTaskId: asNonEmptyString(row.targetTaskId),
|
|
8871
|
+
anchorEventSeq: typeof row.anchorEventSeq === "number" ? row.anchorEventSeq : null,
|
|
8872
|
+
turnNo: typeof row.turnNo === "number" ? row.turnNo : null,
|
|
8873
|
+
createdAt: typeof row.createdAt === "string" ? row.createdAt : ""
|
|
8874
|
+
};
|
|
8875
|
+
}
|
|
8876
|
+
function parseTaskMessageFrame(value) {
|
|
8877
|
+
const frame = asRecord(value);
|
|
8878
|
+
if (!frame)
|
|
8879
|
+
return null;
|
|
8880
|
+
const taskId = asNonEmptyString(frame.taskId);
|
|
8881
|
+
if (!taskId || !Array.isArray(frame.messages))
|
|
8882
|
+
return null;
|
|
8883
|
+
const messages = frame.messages.map(normalizeAgentMessage).filter((message) => message !== null);
|
|
8884
|
+
if (messages.length === 0)
|
|
8885
|
+
return null;
|
|
8886
|
+
return {
|
|
8887
|
+
type: "agent-task:message",
|
|
8888
|
+
taskId,
|
|
8889
|
+
objectId: asNonEmptyString(frame.objectId),
|
|
8890
|
+
anchorKey: typeof frame.anchorKey === "string" ? frame.anchorKey : "",
|
|
8891
|
+
messages
|
|
8892
|
+
};
|
|
8893
|
+
}
|
|
8894
|
+
function upsertTaskMessages(existing, incoming, max = TASK_MESSAGE_QUEUE_MAX) {
|
|
8895
|
+
const byId = /* @__PURE__ */ new Map();
|
|
8896
|
+
for (const message of existing)
|
|
8897
|
+
byId.set(message.id, message);
|
|
8898
|
+
for (const message of incoming)
|
|
8899
|
+
byId.set(message.id, message);
|
|
8900
|
+
const merged = [...byId.values()].sort((a, b) => a.seq - b.seq || a.id.localeCompare(b.id));
|
|
8901
|
+
const dropped = Math.max(0, merged.length - max);
|
|
8902
|
+
return { messages: dropped > 0 ? merged.slice(dropped) : merged, dropped };
|
|
8903
|
+
}
|
|
8904
|
+
function selectConsumedMessages(messages, taskId) {
|
|
8905
|
+
return messages.filter((message) => message.targetTaskId === taskId);
|
|
8906
|
+
}
|
|
8907
|
+
function selectSteerMessages(messages, taskId) {
|
|
8908
|
+
return messages.filter((message) => message.mode === "steer").filter((message) => message.deliveryState !== "consumed" && message.deliveryState !== "withdrawn").filter((message) => message.targetTaskId === taskId).sort((a, b) => a.seq - b.seq);
|
|
8909
|
+
}
|
|
8910
|
+
function renderMessageList(messages) {
|
|
8911
|
+
return messages.map((message) => `${message.seq}. \u3010${message.authorType === "user" ? "\u4EBA" : message.authorType === "system" ? "\u5E73\u53F0" : "\u8FD0\u884C\u65F6"}\u3011${message.content}`).join("\n\n");
|
|
8912
|
+
}
|
|
8913
|
+
function buildSteerPrompt(input) {
|
|
8914
|
+
const opinions = input.messages.length > 0 ? renderMessageList(input.messages) : "\uFF08\u6253\u65AD\u8BF7\u6C42\u672A\u88AB\u53D6\u5230\uFF0C\u8BF7\u6309\u539F\u59CB\u9700\u6C42\u7EE7\u7EED\uFF09";
|
|
8915
|
+
const resetNote = input.sessionReset ? "\n- \u26A0\uFE0F \u4F1A\u8BDD\u5DF2\u91CD\u5EFA\uFF1A\u4E0A\u4E00\u56DE\u5408\u7684\u5BF9\u8BDD\u4E0A\u4E0B\u6587**\u672A\u4FDD\u7559**\uFF0C\u8BF7\u4EE5\u672C\u56DE\u5408\u7ED9\u51FA\u7684\u4FE1\u606F\u4E3A\u51C6\uFF08\u5DE5\u4F5C\u533A\u6587\u4EF6\u4E0E git \u72B6\u6001\u4ECD\u5728\uFF09\u3002" : "";
|
|
8916
|
+
const originalPrompt = input.taskPrompt?.trim() ? `
|
|
8917
|
+
|
|
8918
|
+
\u3010\u539F\u59CB\u4EFB\u52A1\u9700\u6C42\uFF08\u672C\u8F6E\u662F\u540C\u4E00\u6B21\u5DE5\u4F5C\u7684\u5EF6\u7EED\uFF09\u3011
|
|
8919
|
+
${input.taskPrompt.trim()}` : "";
|
|
8920
|
+
return `\u3010\u8FD0\u884C\u4E2D\u6253\u65AD \xB7 \u8BF7\u5148\u6309\u8FD9\u4E9B\u610F\u89C1\u8C03\u6574\uFF0C\u518D\u7EE7\u7EED\u3011
|
|
8921
|
+
\u4F60\u6B63\u5728\u6267\u884C\u7B2C ${input.turnNo - 1} \u56DE\u5408\uFF0C\u4EBA\u5728\u8FD0\u884C\u8FC7\u7A0B\u4E2D\u63D0\u51FA\u4E86\u4EE5\u4E0B\u610F\u89C1\uFF08\u6309\u63D0\u51FA\u987A\u5E8F\uFF09\uFF1A
|
|
8922
|
+
|
|
8923
|
+
${opinions}
|
|
8924
|
+
|
|
8925
|
+
\u8981\u6C42\uFF1A
|
|
8926
|
+
1. \u5148\u9010\u6761\u5904\u7406\u4E0A\u8FF0\u610F\u89C1\uFF0C\u518D\u7EE7\u7EED\u5B8C\u6210\u672C\u4EFB\u52A1\uFF1B\u610F\u89C1\u4E0E\u539F\u59CB\u9700\u6C42\u51B2\u7A81\u65F6**\u4EE5\u610F\u89C1\u4E3A\u51C6**\uFF0C\u5E76\u5728\u6700\u7EC8\u603B\u7ED3\u91CC\u8BF4\u660E\u5DEE\u5F02\u3002
|
|
8927
|
+
2. \u4E0D\u8981\u63A8\u7FFB\u4E0A\u8FF0\u610F\u89C1\u672A\u6D89\u53CA\u7684\u90E8\u5206\uFF1B\u5DF2\u7ECF\u5B8C\u6210\u4E14\u4E0D\u5728\u610F\u89C1\u8303\u56F4\u5185\u7684\u6539\u52A8\u4FDD\u7559\u3002
|
|
8928
|
+
3. \u4E0A\u4E00\u56DE\u5408\u5728\u5B89\u5168\u70B9\u88AB\u4E2D\u65AD\uFF0C\u5176\u4E2D\u7684\u5DE5\u5177\u8FDB\u5EA6\u5DF2\u4E22\u5F03\u3001\u88AB\u4E2D\u65AD\u7684\u8C03\u7528**\u6CA1\u6709\u7ED3\u679C**\uFF08\u65F6\u95F4\u7EBF\u4E0A\u6807\u4E3A\u5DF2\u4E2D\u65AD\uFF09\u2014\u2014\u9700\u8981\u65F6\u91CD\u65B0\u6267\u884C\uFF0C\u4E0D\u8981\u5047\u5B9A\u5B83\u5DF2\u6210\u529F\u3002${resetNote}${originalPrompt}`;
|
|
8929
|
+
}
|
|
8930
|
+
|
|
8867
8931
|
// src/daemon/ws-client.ts
|
|
8868
8932
|
import { createHash as createHash2 } from "node:crypto";
|
|
8869
8933
|
import { io } from "socket.io-client";
|
|
@@ -8979,7 +9043,7 @@ var DaemonWsClient = class {
|
|
|
8979
9043
|
handlers.onTaskResubscribed?.(taskId);
|
|
8980
9044
|
});
|
|
8981
9045
|
socket.on("agent-task:dispatched", (payload) => {
|
|
8982
|
-
handlers.onTaskDispatched(payload.taskId, payload.runtimeId);
|
|
9046
|
+
handlers.onTaskDispatched(payload.taskId, payload.runtimeId, payload.daemonId);
|
|
8983
9047
|
});
|
|
8984
9048
|
socket.on("agent-task:status-changed", (payload) => {
|
|
8985
9049
|
if (payload?.status === "cancelled" && payload.taskId) {
|
|
@@ -9113,6 +9177,7 @@ var OUTBOX_MAX_ATTEMPTS_PER_ROUND = 2;
|
|
|
9113
9177
|
var PROGRESS_BATCH_MAX = 500;
|
|
9114
9178
|
var OBSERVATION_WARN_INTERVAL_MS = 3e4;
|
|
9115
9179
|
var TERMINAL_OBSERVATION_DRAIN_BUDGET_MS = Number(process.env.MORULA_TERMINAL_DRAIN_BUDGET_MS ?? 2e3);
|
|
9180
|
+
var CANCEL_TRACE_TEXT_MAX = 4e3;
|
|
9116
9181
|
async function drainObservationTail(args) {
|
|
9117
9182
|
const startedAt = Date.now();
|
|
9118
9183
|
const progressDrained = await waitWithin(args.progress, args.budgetMs);
|
|
@@ -9134,7 +9199,7 @@ async function waitWithin(promise, ms) {
|
|
|
9134
9199
|
clearTimeout(timer);
|
|
9135
9200
|
return done;
|
|
9136
9201
|
}
|
|
9137
|
-
var OUTBOX_PERMANENT_CODES = ["NOT_FOUND", "CONFLICT"];
|
|
9202
|
+
var OUTBOX_PERMANENT_CODES = ["NOT_FOUND", "CONFLICT", "RUNTIME_MISMATCH"];
|
|
9138
9203
|
var DEFAULT_MODEL = "deepseek-v4-flash";
|
|
9139
9204
|
var DaemonRunner = class {
|
|
9140
9205
|
constructor(client, token, store, tenantId, options = {}) {
|
|
@@ -9156,6 +9221,12 @@ var DaemonRunner = class {
|
|
|
9156
9221
|
ws;
|
|
9157
9222
|
log;
|
|
9158
9223
|
runtimeId = null;
|
|
9224
|
+
/**
|
|
9225
|
+
* 本进程的**实例标识**(`daemonId`,config dir 内持久化):同机多实例注册时会复用同一行
|
|
9226
|
+
* `AgentRuntime`(同一 runtimeId),下行命令靠 `runtimeId` + `daemonId` 双重过滤才能定向到实例
|
|
9227
|
+
* (issues/duplicate-daemon-same-runtime-double-execution.md)。
|
|
9228
|
+
*/
|
|
9229
|
+
daemonId = null;
|
|
9159
9230
|
running = false;
|
|
9160
9231
|
/** D1:心跳定时器(独立于 tick)与单飞标志——上一拍未返回则跳过本拍,避免慢请求堆积 */
|
|
9161
9232
|
heartbeatTimer = null;
|
|
@@ -9293,6 +9364,7 @@ var DaemonRunner = class {
|
|
|
9293
9364
|
providers: inventory
|
|
9294
9365
|
});
|
|
9295
9366
|
this.runtimeId = registered.id;
|
|
9367
|
+
this.daemonId = cfg.daemonId;
|
|
9296
9368
|
if (cfg.runtimeId !== registered.id) {
|
|
9297
9369
|
saveDaemonConfig(this.store, { runtimeId: registered.id });
|
|
9298
9370
|
}
|
|
@@ -9443,6 +9515,41 @@ var DaemonRunner = class {
|
|
|
9443
9515
|
this.log(`[daemon] cleanup poll \u5F02\u5E38: ${error instanceof Error ? error.message : String(error)}`);
|
|
9444
9516
|
}
|
|
9445
9517
|
}
|
|
9518
|
+
/**
|
|
9519
|
+
* 取消留痕(issues/daemon-stream-events-silently-stop-mid-run.md 未实施项 5;用户 2026-09-21 定案「取消也留痕」)。
|
|
9520
|
+
*
|
|
9521
|
+
* 取消路径原本直接 `return`:这一轮**已产出**的内容(dim 已写完的回答、中断前的部分回答)在平台侧
|
|
9522
|
+
* 零留存(唯一痕迹是 `agent_failed{status:cancelled}`)→「取消 = 这轮白跑且无法追溯」。
|
|
9523
|
+
*
|
|
9524
|
+
* 契约(定案):**不得**把任务状态改回 completed —— 服务端只把 `result.text` 合并进
|
|
9525
|
+
* `agent_tasks.result.cancelled.lastOutput`(既有列,与取消时的 who/when/step 同一条记录)。
|
|
9526
|
+
*
|
|
9527
|
+
* best-effort 边界:**不走 outbox、不重试、失败只 log** —— 留痕不得让取消流程变慢或失败;
|
|
9528
|
+
* 无已产出内容时不发请求(不制造空留痕噪声)。旧服务端不认识 `cancelled` 字段(whitelist 剥离)
|
|
9529
|
+
* → 行为退化为原样,不会报错。
|
|
9530
|
+
*/
|
|
9531
|
+
async reportCancelTrace(taskId, text, reason) {
|
|
9532
|
+
const produced = (text ?? "").trim();
|
|
9533
|
+
if (!produced) {
|
|
9534
|
+
this.log(`[daemon] \u4EFB\u52A1 ${taskId} \u88AB\u53D6\u6D88\uFF0C\u672C\u8F6E\u65E0\u5DF2\u4EA7\u51FA\u5185\u5BB9\uFF0C\u4E0D\u5199\u53D6\u6D88\u7559\u75D5\uFF08${reason}\uFF09`);
|
|
9535
|
+
return;
|
|
9536
|
+
}
|
|
9537
|
+
try {
|
|
9538
|
+
const res = await this.api.submitResult(taskId, {
|
|
9539
|
+
runtimeId: this.runtimeId ?? "",
|
|
9540
|
+
ok: true,
|
|
9541
|
+
cancelled: true,
|
|
9542
|
+
// 与服务端 `result.text` 的 4000 上限同口径:够追溯「这轮产出了什么」
|
|
9543
|
+
result: { text: produced.slice(0, CANCEL_TRACE_TEXT_MAX) }
|
|
9544
|
+
});
|
|
9545
|
+
if (res?.ok)
|
|
9546
|
+
this.log(`[daemon] \u4EFB\u52A1 ${taskId} \u88AB\u53D6\u6D88\uFF1A\u5DF2\u8865\u8BB0\u672C\u8F6E\u4EA7\u51FA ${produced.length} \u5B57\uFF08\u670D\u52A1\u7AEF\u53EA\u7559\u75D5\uFF0C\u4E0D\u6539\u4EFB\u52A1\u72B6\u6001\uFF09`);
|
|
9547
|
+
else
|
|
9548
|
+
this.log(`[daemon] \u4EFB\u52A1 ${taskId} \u53D6\u6D88\u7559\u75D5\u672A\u843D\u5E93\uFF08${res?.code ?? "unknown"}\uFF09\u2014\u2014 \u4E0D\u5F71\u54CD\u53D6\u6D88\u672C\u8EAB`);
|
|
9549
|
+
} catch (error) {
|
|
9550
|
+
this.log(`[daemon] \u4EFB\u52A1 ${taskId} \u53D6\u6D88\u7559\u75D5\u4E0A\u62A5\u5931\u8D25: ${error instanceof Error ? error.message : String(error)}`);
|
|
9551
|
+
}
|
|
9552
|
+
}
|
|
9446
9553
|
/**
|
|
9447
9554
|
* M1-A2:终态结果可靠回传——先写盘 → 单次尝试 → 成功删盘(顺序语义不变)。
|
|
9448
9555
|
*
|
|
@@ -9481,7 +9588,7 @@ var DaemonRunner = class {
|
|
|
9481
9588
|
let res = null;
|
|
9482
9589
|
let transportError = null;
|
|
9483
9590
|
try {
|
|
9484
|
-
res = await this.api.submitResult(taskId, body);
|
|
9591
|
+
res = await this.api.submitResult(taskId, { ...body, runtimeId: this.runtimeId ?? "" });
|
|
9485
9592
|
} catch (err) {
|
|
9486
9593
|
transportError = err?.message ?? String(err);
|
|
9487
9594
|
}
|
|
@@ -9632,8 +9739,8 @@ var DaemonRunner = class {
|
|
|
9632
9739
|
*/
|
|
9633
9740
|
buildWsHandlers() {
|
|
9634
9741
|
return {
|
|
9635
|
-
onTaskDispatched: (taskId, runtimeId) => {
|
|
9636
|
-
this.onTaskDispatched(taskId, runtimeId);
|
|
9742
|
+
onTaskDispatched: (taskId, runtimeId, daemonId) => {
|
|
9743
|
+
this.onTaskDispatched(taskId, runtimeId, daemonId);
|
|
9637
9744
|
},
|
|
9638
9745
|
// M1-A1:取消信号 → 中断执行中的 dim 进程
|
|
9639
9746
|
onTaskCancelled: (taskId) => {
|
|
@@ -9666,7 +9773,7 @@ var DaemonRunner = class {
|
|
|
9666
9773
|
},
|
|
9667
9774
|
// 会话宿主命令(steward-core-acp-migration §4.4,P1-5):转发给 SessionHost。
|
|
9668
9775
|
// 服务端发到 **tenant 房间**(同租户每台 daemon 都收到,WS 无 per-runtime 房间),
|
|
9669
|
-
// 故与 `agent-task:dispatched` 同口径按 `runtimeId` 自过滤。
|
|
9776
|
+
// 故与 `agent-task:dispatched` 同口径按 `runtimeId` + `daemonId` 自过滤。
|
|
9670
9777
|
onSessionCommand: (kind, payload) => {
|
|
9671
9778
|
void this.handleSessionCommand(kind, payload);
|
|
9672
9779
|
}
|
|
@@ -9676,7 +9783,10 @@ var DaemonRunner = class {
|
|
|
9676
9783
|
* 会话宿主命令分发。
|
|
9677
9784
|
*
|
|
9678
9785
|
* 两道闸:
|
|
9679
|
-
* ① **runtimeId 自过滤**(tenant 广播 →
|
|
9786
|
+
* ① **runtimeId + daemonId 自过滤**(tenant 广播 → 只有归属设备处理;字段缺失时不过滤,兼容旧服务端)。
|
|
9787
|
+
* daemonId 是**实例**维度(issues/duplicate-daemon-same-runtime-double-execution.md):同机多实例
|
|
9788
|
+
* 注册时会复用同一行 AgentRuntime(同一 runtimeId),缺了它两个实例会各自 `open` 同一 sessionId
|
|
9789
|
+
* 并各跑一轮 prompt(实测:同一轮两份正文事件、两个 daemon 都「会话已打开」);
|
|
9680
9790
|
* ② **按会话串行**:服务端每轮 prompt 前会补发 `open` 做兜底,而 socket.io 只保证「送达有序」,
|
|
9681
9791
|
* 不保证「异步处理有序」——`void handleSessionCommand()` 会让 open/prompt 交错执行,
|
|
9682
9792
|
* prompt 可能先于 open 完成而拿到 SESSION_NOT_OPEN。故按 sessionId 串成一条 promise 链。
|
|
@@ -9686,6 +9796,9 @@ var DaemonRunner = class {
|
|
|
9686
9796
|
const runtimeId = typeof payload.runtimeId === "string" ? payload.runtimeId : void 0;
|
|
9687
9797
|
if (runtimeId && this.runtimeId && runtimeId !== this.runtimeId)
|
|
9688
9798
|
return Promise.resolve();
|
|
9799
|
+
const daemonId = typeof payload.daemonId === "string" ? payload.daemonId : void 0;
|
|
9800
|
+
if (daemonId && this.daemonId && daemonId !== this.daemonId)
|
|
9801
|
+
return Promise.resolve();
|
|
9689
9802
|
const sessionId = typeof payload.sessionId === "string" ? payload.sessionId : "";
|
|
9690
9803
|
if (!sessionId) {
|
|
9691
9804
|
this.log(`[daemon] \u4F1A\u8BDD\u547D\u4EE4 ${kind} \u7F3A\u5C11 sessionId\uFF08\u5FFD\u7565\uFF09`);
|
|
@@ -9733,10 +9846,17 @@ var DaemonRunner = class {
|
|
|
9733
9846
|
* 不校验任务归属,见同 issue 根因 ③ / ④)。
|
|
9734
9847
|
*
|
|
9735
9848
|
* `runtimeId` 缺失(旧服务端)→ 保持旧行为不过滤;poll 兜底本就按 runtimeId 查询,不受影响。
|
|
9849
|
+
*
|
|
9850
|
+
* `daemonId`(issues/duplicate-daemon-same-runtime-double-execution.md):同机多实例注册时会复用
|
|
9851
|
+
* 同一行 `AgentRuntime`(同一 runtimeId,服务端按设备收敛重复行)→ 单靠 runtimeId 两个实例都会处理。
|
|
9852
|
+
* 故服务端下行带**实例标识**,两个字段都匹配才处理;`daemonId` 缺失(旧服务端)→ 退回只按 runtimeId
|
|
9853
|
+
* 过滤,否则新 daemon 接旧服务端会全丢事件。
|
|
9736
9854
|
*/
|
|
9737
|
-
onTaskDispatched(taskId, runtimeId) {
|
|
9855
|
+
onTaskDispatched(taskId, runtimeId, daemonId) {
|
|
9738
9856
|
if (runtimeId && this.runtimeId && runtimeId !== this.runtimeId)
|
|
9739
9857
|
return;
|
|
9858
|
+
if (daemonId && this.daemonId && daemonId !== this.daemonId)
|
|
9859
|
+
return;
|
|
9740
9860
|
void this.handleTask(taskId);
|
|
9741
9861
|
}
|
|
9742
9862
|
/** 任务处理(幂等:已在处理中则跳过) */
|
|
@@ -9955,9 +10075,10 @@ var DaemonRunner = class {
|
|
|
9955
10075
|
// 插件 bin 前置 + 显式 CLI 路径(与会话链路同源):任务里的 agent 也必须用本包物化的 `morula`,
|
|
9956
10076
|
// 而不是宿主/桌面应用自带的旧版(旧版不认任务/会话凭证,且缺部分命令旗标 → 契约指令直接失败)。
|
|
9957
10077
|
// PATH 只是第一道保险(dim 会重写 agent shell 的 PATH),可靠的是 `MORULA_CLI` 绝对路径。
|
|
9958
|
-
//
|
|
10078
|
+
// MORULA_CLI 优先本包自带入口(与当前 daemon 同源),产物缺失才回退插件启动器。
|
|
10079
|
+
// 见 issues/steward-cli-resolves-stale-bundled-morula.md、issues/agent-cli-stale-build-missing-steward-commands.md。
|
|
9959
10080
|
PATH: prependPluginBinToPath(process.env.PATH),
|
|
9960
|
-
MORULA_CLI:
|
|
10081
|
+
MORULA_CLI: resolveAgentCliPath()
|
|
9961
10082
|
};
|
|
9962
10083
|
let repoDir = cfg.workdir;
|
|
9963
10084
|
let taskRoot = cfg.workdir;
|
|
@@ -10118,6 +10239,8 @@ var DaemonRunner = class {
|
|
|
10118
10239
|
dimWorkDir: taskRoot
|
|
10119
10240
|
});
|
|
10120
10241
|
this.log(`[daemon] \u4EFB\u52A1 ${taskId} \u5B8C\u6210`);
|
|
10242
|
+
if (signal?.aborted)
|
|
10243
|
+
await this.reportCancelTrace(taskId, result.finalText, "\u6536\u5C3E\u9636\u6BB5\u88AB\u53D6\u6D88");
|
|
10121
10244
|
const isReviewTask = detail.kind === "review";
|
|
10122
10245
|
const isAnalysisTask = detail.stageCode === "todo";
|
|
10123
10246
|
if (!isReviewTask && !isAnalysisTask && isFlagEnabled("MORULA_LOCAL_AGENT_DELIVERY_V1", true))
|
|
@@ -10126,6 +10249,7 @@ var DaemonRunner = class {
|
|
|
10126
10249
|
const error = result.error?.message ?? "dim \u6267\u884C\u5931\u8D25";
|
|
10127
10250
|
if (signal?.aborted) {
|
|
10128
10251
|
this.log(`[daemon] \u4EFB\u52A1 ${taskId} \u5DF2\u53D6\u6D88\uFF0C\u8DF3\u8FC7\u7ED3\u679C\u56DE\u4F20: ${error}`);
|
|
10252
|
+
await this.reportCancelTrace(taskId, result.finalText, error);
|
|
10129
10253
|
return;
|
|
10130
10254
|
}
|
|
10131
10255
|
await this.submitResultReliable(taskId, { ok: false, error });
|
|
@@ -10591,7 +10715,7 @@ var DaemonRunner = class {
|
|
|
10591
10715
|
repoFullName: wc.repoFullName,
|
|
10592
10716
|
branchName: wc.branchName
|
|
10593
10717
|
};
|
|
10594
|
-
const repoCachePath = buildRepoCachePath(cfg.workdir, this.tenantId, wc.repoFullName);
|
|
10718
|
+
const repoCachePath = buildRepoCachePath(cfg.workdir, this.tenantId, this.runtimeId, wc.repoFullName);
|
|
10595
10719
|
const errorCode = validateRemovable(wc.worktreePath, expected, repoCachePath);
|
|
10596
10720
|
if (errorCode) {
|
|
10597
10721
|
this.log(`[daemon] cleanup ${item.id} \u62D2\u7EDD\u5220\u9664: ${errorCode}`);
|
|
@@ -10688,6 +10812,7 @@ function writeTaskContextBrief(targetDir, taskId, detail, repo, log) {
|
|
|
10688
10812
|
|
|
10689
10813
|
- \u672C AgentTask \u4EFB\u52A1 ID\uFF1A\`${taskId}\`
|
|
10690
10814
|
- \u5DE5\u4F5C\u76EE\u5F55\uFF1A\u672C\u6587\u4EF6\u6240\u5728\u76EE\u5F55\uFF08\u4EFB\u52A1\u5DE5\u4F5C\u533A\u6839\uFF1B\u4ED3\u5E93\u662F\u5B83\u4E0B\u9762\u7684\u5B50\u76EE\u5F55\uFF0Cgit \u64CD\u4F5C\u5728\u4ED3\u5E93\u5B50\u76EE\u5F55\u5185\uFF09
|
|
10815
|
+
- \u534F\u4F5C\u5951\u7EA6\uFF08\u5FC5\u8BFB\uFF09\uFF1A\`.agents/skills/morula-working-on-issues/SKILL.md\`\uFF08\u76F8\u5BF9\u672C\u76EE\u5F55\uFF09\u3002\u82E5 \`skill\` \u5DE5\u5177\u62A5 \`Unknown skill\`\uFF0C**\u76F4\u63A5\u8BFB\u8BE5\u6587\u4EF6**\uFF08read/cat\uFF09\uFF0C\u4E0D\u8981\u56E0\u4E3A\u52A0\u8F7D\u5931\u8D25\u5C31\u8DF3\u8FC7\u5951\u7EA6\u3002
|
|
10691
10816
|
|
|
10692
10817
|
---
|
|
10693
10818
|
|
|
@@ -11152,6 +11277,7 @@ function daemonDir(configPath) {
|
|
|
11152
11277
|
}
|
|
11153
11278
|
var PID_FILE = DAEMON_PID_FILE;
|
|
11154
11279
|
var LOG_FILE = "daemon.log";
|
|
11280
|
+
var DAEMON_EXIT_FALLBACK_MS = 3e3;
|
|
11155
11281
|
async function daemonCommand(context) {
|
|
11156
11282
|
const { action } = context.parsed;
|
|
11157
11283
|
if (action === "run")
|
|
@@ -11334,6 +11460,9 @@ async function models(context) {
|
|
|
11334
11460
|
}
|
|
11335
11461
|
async function run2(context) {
|
|
11336
11462
|
rejectUnknownFlags(context.parsed.flags, ["name", "workdir", "max-concurrent"]);
|
|
11463
|
+
const armBoundedExit = () => {
|
|
11464
|
+
setTimeout(() => process.exit(0), DAEMON_EXIT_FALLBACK_MS).unref();
|
|
11465
|
+
};
|
|
11337
11466
|
const name = flagString(context.parsed.flags, "name") ?? void 0;
|
|
11338
11467
|
const workdir = flagString(context.parsed.flags, "workdir") ?? void 0;
|
|
11339
11468
|
const maxConcurrent = parseMaxConcurrent(context);
|
|
@@ -11349,6 +11478,7 @@ async function run2(context) {
|
|
|
11349
11478
|
const pid = acquired.existing?.pid;
|
|
11350
11479
|
if (context.env.MORULA_DAEMON_SUPERVISED === "1") {
|
|
11351
11480
|
context.err(`[daemon] \u5DF2\u6709\u5B9E\u4F8B\u5728\u8FD0\u884C\uFF08pid=${pid ?? "\u672A\u77E5"}\uFF09\uFF0C\u81EA\u542F\u5B9E\u4F8B\u793C\u8BA9\u9000\u51FA`);
|
|
11481
|
+
armBoundedExit();
|
|
11352
11482
|
return { running: false, yieldedTo: pid ?? null };
|
|
11353
11483
|
}
|
|
11354
11484
|
throw new CliError(
|
|
@@ -11389,12 +11519,14 @@ async function run2(context) {
|
|
|
11389
11519
|
if (isAuthRejected(error)) {
|
|
11390
11520
|
context.err(`[daemon] \u6CE8\u518C\u88AB\u62D2\uFF08\u767B\u5F55\u6001\u5931\u6548\uFF09\uFF1A${error instanceof Error ? error.message : String(error)}`);
|
|
11391
11521
|
context.err("[daemon] \u8BF7\u91CD\u65B0\u767B\u5F55\u540E\u518D\u6B21\u542F\u52A8\uFF1Amorula-runtime auth login && morula-runtime daemon start");
|
|
11522
|
+
armBoundedExit();
|
|
11392
11523
|
return { running: false, stoppedReason: "auth" };
|
|
11393
11524
|
}
|
|
11394
11525
|
throw error;
|
|
11395
11526
|
} finally {
|
|
11396
11527
|
releaseLock();
|
|
11397
11528
|
}
|
|
11529
|
+
armBoundedExit();
|
|
11398
11530
|
return { running: false };
|
|
11399
11531
|
}
|
|
11400
11532
|
function isAuthRejected(error) {
|
package/dist/morula.js
CHANGED
|
@@ -704,8 +704,8 @@ function page(ok, message) {
|
|
|
704
704
|
}
|
|
705
705
|
|
|
706
706
|
// ../morula-cli-core/dist/build-env.js
|
|
707
|
-
var BUILD_VERSION = "0.1.0-alpha.
|
|
708
|
-
var BUILD_ID = "
|
|
707
|
+
var BUILD_VERSION = "0.1.0-alpha.9";
|
|
708
|
+
var BUILD_ID = "20260921135326.48e72dd8";
|
|
709
709
|
var BUILD_CONTEXTS = {
|
|
710
710
|
"local": "http://localhost:8080/api",
|
|
711
711
|
"test": "https://morula.basecastle.com/api",
|
|
@@ -940,6 +940,28 @@ var CLI_CAPS_HEADER = "X-Morula-Cli-Caps";
|
|
|
940
940
|
var CLI_BUILD_MAX_LENGTH = 64;
|
|
941
941
|
var CLI_CAPS_MAX_LENGTH = 255;
|
|
942
942
|
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
943
|
+
var CAUSE_DETAIL_MAX_LENGTH = 200;
|
|
944
|
+
function describeFetchFailure(error) {
|
|
945
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
946
|
+
const detail = formatFetchCause(error?.cause);
|
|
947
|
+
return detail ? `${message} (cause: ${detail})` : message;
|
|
948
|
+
}
|
|
949
|
+
function formatFetchCause(cause) {
|
|
950
|
+
if (cause === void 0 || cause === null)
|
|
951
|
+
return "";
|
|
952
|
+
if (cause instanceof Error) {
|
|
953
|
+
const detail = cause;
|
|
954
|
+
const parts = [
|
|
955
|
+
typeof detail.code === "string" ? detail.code : "",
|
|
956
|
+
typeof detail.errno === "number" || typeof detail.errno === "string" ? `errno=${detail.errno}` : "",
|
|
957
|
+
typeof detail.syscall === "string" ? `syscall=${detail.syscall}` : "",
|
|
958
|
+
// cause 的 message 常与外层重复('fetch failed'),只有不同才带
|
|
959
|
+
detail.message && detail.message !== "fetch failed" ? detail.message : ""
|
|
960
|
+
].filter(Boolean);
|
|
961
|
+
return parts.join(" ").slice(0, CAUSE_DETAIL_MAX_LENGTH);
|
|
962
|
+
}
|
|
963
|
+
return String(cause).slice(0, CAUSE_DETAIL_MAX_LENGTH);
|
|
964
|
+
}
|
|
943
965
|
var MorulaApiClient = class {
|
|
944
966
|
baseUrl;
|
|
945
967
|
token;
|
|
@@ -1037,7 +1059,7 @@ var MorulaApiClient = class {
|
|
|
1037
1059
|
if (controller.signal.aborted) {
|
|
1038
1060
|
throw new MorulaApiError("TIMEOUT", `request timed out after ${timeoutMs}ms`, EXIT_CODE.UPSTREAM, void 0, true);
|
|
1039
1061
|
}
|
|
1040
|
-
throw new MorulaApiError("NETWORK", `request failed: ${
|
|
1062
|
+
throw new MorulaApiError("NETWORK", `request failed: ${describeFetchFailure(error)}`, EXIT_CODE.UPSTREAM, void 0, true);
|
|
1041
1063
|
} finally {
|
|
1042
1064
|
clearTimeout(timer);
|
|
1043
1065
|
}
|
|
@@ -3829,7 +3851,7 @@ var SPEC = {
|
|
|
3829
3851
|
actions: [
|
|
3830
3852
|
{
|
|
3831
3853
|
action: "status",
|
|
3832
|
-
summary:
|
|
3854
|
+
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 space face repos[] answers per repo (a multi-repo space never answers hasCiConfig for "the space" \u2014 it is null there); on the task face --repo filters runs client-side by repoFullName and echoes repoFilter (the server does NOT support repo filtering)',
|
|
3833
3855
|
args: [{ name: "taskId", description: "\u672C\u4EFB\u52A1 AgentTask UUID\uFF08\u4E0E --space \u4E92\u65A5\uFF09" }],
|
|
3834
3856
|
flags: [
|
|
3835
3857
|
{ name: "space", type: "string", valueHint: "<id>", description: "\u7A7A\u95F4 ID\uFF08\u7BA1\u5BB6/\u7A7A\u95F4\u9762\uFF1B\u4E0E <taskId> \u4E92\u65A5\uFF09" },
|
|
@@ -3841,7 +3863,7 @@ var SPEC = {
|
|
|
3841
3863
|
examples: ["morula ci status <taskId>", "morula ci status --space <id> --failed"],
|
|
3842
3864
|
writes: "none",
|
|
3843
3865
|
idempotent: true,
|
|
3844
|
-
emits: ["ok", "taskId", "spaceId", "runs", "deployments", "hasCiConfig", "notice", "repoFilter"]
|
|
3866
|
+
emits: ["ok", "taskId", "spaceId", "runs", "deployments", "repos", "hasCiConfig", "notice", "repoFilter"]
|
|
3845
3867
|
},
|
|
3846
3868
|
{
|
|
3847
3869
|
action: "log",
|
package/dist/plugin/plugin.json
CHANGED
|
@@ -1412,7 +1412,7 @@ CI/CD pipeline facts and pipeline operations: pipeline runs / job logs / deploym
|
|
|
1412
1412
|
|
|
1413
1413
|
**用法**:`morula ci status [<taskId>] [--space <id>] [--repo <owner/name>] [--ref <branch>] [--failed] [--limit <n>]`
|
|
1414
1414
|
|
|
1415
|
-
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)
|
|
1415
|
+
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 space face repos[] answers per repo (a multi-repo space never answers hasCiConfig for "the space" — it is null there); on the task face --repo filters runs client-side by repoFullName and echoes repoFilter (the server does NOT support repo filtering)
|
|
1416
1416
|
|
|
1417
1417
|
| 位置参数 | 必填 | 说明 |
|
|
1418
1418
|
|---|---|---|
|
|
@@ -1433,7 +1433,7 @@ morula ci status <taskId>
|
|
|
1433
1433
|
morula ci status --space <id> --failed
|
|
1434
1434
|
```
|
|
1435
1435
|
|
|
1436
|
-
> `writes: none` · `interactive: no` · `idempotent: yes` · `emits: ok, taskId, spaceId, runs, deployments, hasCiConfig, notice, repoFilter`
|
|
1436
|
+
> `writes: none` · `interactive: no` · `idempotent: yes` · `emits: ok, taskId, spaceId, runs, deployments, repos, hasCiConfig, notice, repoFilter`
|
|
1437
1437
|
|
|
1438
1438
|
### `morula ci log`
|
|
1439
1439
|
|
|
@@ -26,6 +26,11 @@ allowed-tools: Bash(morula *), Bash(git *), Bash(gh *)
|
|
|
26
26
|
- **空间仓库清单**(多仓库任务判断依据):`morula repo list --space <spaceId>`——提示词不列仓库,需要时自己查。
|
|
27
27
|
- **「你的目标」**:系统提示「你的目标」段 = 本次任务的原始诉求,据此判断要做什么。
|
|
28
28
|
|
|
29
|
+
> **调 CLI 一律用 `$MORULA_CLI`**(daemon 注入的绝对路径,指向与本次运行同源的构建;下文所有 `morula xxx`
|
|
30
|
+
> 都按 `$MORULA_CLI xxx` 执行)。PATH 上的裸 `morula` 可能是宿主自带的旧版本(缺命令面、且不认会话/任务
|
|
31
|
+
> 凭证 → 写操作署名错误),不要用它;`env VAR=... $MORULA_CLI xxx` 这类 env 包装下同样可用。
|
|
32
|
+
> 仅当 `$MORULA_CLI` 为空时才退回裸 `morula`。
|
|
33
|
+
|
|
29
34
|
> **工作目录 = 任务工作区根**:根下放 `AGENTS.md`(空间项目说明,已作为 project.instructions 自动加载)、
|
|
30
35
|
> `.agents/`、`.agent_context/`、`.morula/`;**各仓库是工作区根下的子目录**(见 0.5)。
|
|
31
36
|
> 下文的 `AGENTS.md`/`.agents/`/`.agent_context/` 路径都相对这个工作区根。
|
|
@@ -33,6 +38,11 @@ allowed-tools: Bash(morula *), Bash(git *), Bash(gh *)
|
|
|
33
38
|
> **任务上下文文件**:同一套上下文也写在工作目录 `.agent_context/task-context.md`(与首条系统提示同源)。
|
|
34
39
|
> 需要再次确认任务边界时**读取该文件**(`cat .agent_context/task-context.md`),不要凭记忆推断。
|
|
35
40
|
|
|
41
|
+
> **本契约自身的读取方式**:契约以项目级 skill 形式注入在 `.agents/skills/morula-working-on-issues/SKILL.md`。
|
|
42
|
+
> 用 `skill` 工具按名加载**可能报 `Unknown skill`**(该工具的发现范围不含项目级目录)——此时
|
|
43
|
+
> **直接读文件**(`cat .agents/skills/morula-working-on-issues/SKILL.md` 或 read 工具),
|
|
44
|
+
> **不要因为加载失败就跳过契约**(issues/injected-contract-skill-not-loadable-by-skill-tool.md)。
|
|
45
|
+
|
|
36
46
|
详情见下文各节对 TaskID / 对外编号的具体用法。
|
|
37
47
|
|
|
38
48
|
## 0.1 通用行为约束
|
package/dist/plugin/skills/morula-working-on-issues/references/working-on-issues-source-map.md
CHANGED
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
| CLI 写评论(**契约禁止 agent 自行调用**:完成评论由服务端统一发送,见本文件第 5 条) | `morula comment add`(命令存在,但本契约要求不调用) | `packages/morula-cli/src/commands/comment.ts` |
|
|
19
19
|
| CLI 任务详情(**无参**取本任务;带参取业务对象) | `morula task get` → `GET /agent-tasks/:id`;`morula task get <objectId>` → `GET /objects/:id` | `packages/morula-cli/src/commands/task.ts` |
|
|
20
20
|
| daemon 注入凭据(agent 无需自行登录) | runner 注入 `env` 给 Provider 子进程 | `packages/runtime/src/daemon/runner.ts` |
|
|
21
|
+
| 调 CLI 用 `$MORULA_CLI`(绝对路径,与当前 daemon 同源;PATH 上的裸 `morula` 可能是宿主自带的旧版) | `resolveAgentCliPath`(优先本包 `dist/morula.js`,产物缺失回退插件启动器);注入点:任务链路 `env`、会话链路 `env` | `packages/runtime/src/daemon/plugin-register.ts`、`runner.ts`、`session-host.ts` |
|
|
21
22
|
| 系统提示注入(身份与边界 = 阶段职责 / 目标 / 钥匙 taskId+spaceId / 工具入口指引);任务详情与仓库清单由 `morula task get`(无参)、`morula repo list --space` 获取 | `buildTaskPromptWithContract`(`runner.ts`,唯一进 dim 的 messages[0]);CLI `packages/morula-cli/src/commands/task.ts`(resolveTaskId → `GET /agent-tasks/:id`) | `packages/runtime/src/daemon/runner.ts` |
|
|
22
23
|
| 运行中检查点(本回合内取用户意见) | CLI `morula task inbox [--peek]` → `GET /agent-tasks/:id/thread/inbox`(机器协议;默认取走即消费,落 `consumed` + 当回合号);契约时机见本 SKILL 1.3 | `packages/morula-cli/src/commands/task.ts`、`src/modules/agent-task/chat/object-agent-chat.controller.ts`、`object-agent-message.service.ts`(`getThreadInbox`) |
|
|
23
24
|
| 运行中打断(同一会话重开一轮) | daemon 在安全点(`inFlightTools === 0`)`session/cancel` → `session/resume` → 用新意见重开 prompt;回合号与中断点上报为 `turn_started` / `turn_interrupted` 事件 | `packages/runtime/src/daemon/acp/dim-acp-executor.ts`(回合循环)、`runner.ts`(`buildSteerPort`)、`src/modules/agent-task/chat/object-agent-message.service.ts`(`steerDeliveryStrategy`) |
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arcships/morula-runtime",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.1.0-alpha.
|
|
4
|
+
"version": "0.1.0-alpha.9",
|
|
5
5
|
"description": "Device-level CLI for the Morula local agent runtime (daemon/portal/models/auth) and the Morula business CLI (morula), distributed via npm",
|
|
6
6
|
"bin": {
|
|
7
7
|
"morula-runtime": "./bin/morula-runtime.js",
|