@clawos-dev/clawd 0.2.455 → 0.2.457
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/app-builder-plugin/mcp-server.cjs +31 -3
- package/dist/cli.cjs +35 -6
- package/dist/deploy-kit/scripts/ensure-credentials.sh +18 -8
- package/dist/deploy-kit/scripts/ensure-credentials.spec.ts +60 -1
- package/dist/dispatch/mcp-server.cjs +31 -3
- package/dist/persona-defaults/persona-master/CLAUDE.md +68 -0
- package/dist/share-ui/assets/{guest-Dh-ssMM-.js → guest-joTJl1Mi.js} +133 -133
- package/dist/share-ui/guest.html +1 -1
- package/package.json +1 -1
|
@@ -22062,6 +22062,28 @@ var ChannelDeleteResultSchema = external_exports.object({
|
|
|
22062
22062
|
|
|
22063
22063
|
// ../protocol/src/topic.ts
|
|
22064
22064
|
var nonBlank2 = external_exports.string().trim().min(1);
|
|
22065
|
+
var TOPIC_DECISION_TYPES = ["master-confirmed", "owner-needed"];
|
|
22066
|
+
var TOPIC_DECISION_STATUSES = ["open", "resolved"];
|
|
22067
|
+
var TOPIC_DECISION_TYPE_MASTER_CONFIRMED = TOPIC_DECISION_TYPES[0];
|
|
22068
|
+
var TOPIC_DECISION_TYPE_OWNER_NEEDED = TOPIC_DECISION_TYPES[1];
|
|
22069
|
+
var TOPIC_DECISION_STATUS_OPEN = TOPIC_DECISION_STATUSES[0];
|
|
22070
|
+
var TOPIC_DECISION_STATUS_RESOLVED = TOPIC_DECISION_STATUSES[1];
|
|
22071
|
+
var TopicDecisionTypeSchema = external_exports.enum(TOPIC_DECISION_TYPES);
|
|
22072
|
+
var TopicDecisionStatusSchema = external_exports.enum(TOPIC_DECISION_STATUSES);
|
|
22073
|
+
var TopicDecisionSchema = external_exports.object({
|
|
22074
|
+
type: TopicDecisionTypeSchema,
|
|
22075
|
+
status: TopicDecisionStatusSchema,
|
|
22076
|
+
question: nonBlank2,
|
|
22077
|
+
recommendation: nonBlank2
|
|
22078
|
+
}).superRefine((decision, ctx) => {
|
|
22079
|
+
if (decision.type === TOPIC_DECISION_TYPE_MASTER_CONFIRMED && decision.status !== TOPIC_DECISION_STATUS_RESOLVED) {
|
|
22080
|
+
ctx.addIssue({
|
|
22081
|
+
code: external_exports.ZodIssueCode.custom,
|
|
22082
|
+
path: ["status"],
|
|
22083
|
+
message: "master-confirmed decisions must be resolved"
|
|
22084
|
+
});
|
|
22085
|
+
}
|
|
22086
|
+
});
|
|
22065
22087
|
var TOPIC_STATES = ["planning", "running", "done"];
|
|
22066
22088
|
var TopicStateSchema = external_exports.enum(TOPIC_STATES);
|
|
22067
22089
|
var TopicActivityEntrySchema = external_exports.object({
|
|
@@ -22071,7 +22093,12 @@ var TopicActivityEntrySchema = external_exports.object({
|
|
|
22071
22093
|
target: external_exports.string().optional(),
|
|
22072
22094
|
reason: external_exports.string().min(1),
|
|
22073
22095
|
/** 该动作确认的产出物(watcher 返回的 artifacts);影响面视图的唯一数据源 */
|
|
22074
|
-
artifacts: external_exports.array(nonBlank2).optional()
|
|
22096
|
+
artifacts: external_exports.array(nonBlank2).optional(),
|
|
22097
|
+
/**
|
|
22098
|
+
* Optional decision projection; legacy activity entries omit this field. `open` means the
|
|
22099
|
+
* owner still needs to answer; `resolved` records the conclusion without deleting the question.
|
|
22100
|
+
*/
|
|
22101
|
+
decision: TopicDecisionSchema.optional()
|
|
22075
22102
|
});
|
|
22076
22103
|
var TopicLineMetaSchema = external_exports.object({
|
|
22077
22104
|
rejectCount: external_exports.number().int().min(0),
|
|
@@ -22178,7 +22205,8 @@ var TopicAppendArgsSchema = external_exports.object({
|
|
|
22178
22205
|
target: nonBlank2.optional(),
|
|
22179
22206
|
reason: nonBlank2,
|
|
22180
22207
|
/** 该动作确认的产出物;影响面视图只吃这个字段 */
|
|
22181
|
-
artifacts: external_exports.array(nonBlank2).optional()
|
|
22208
|
+
artifacts: external_exports.array(nonBlank2).optional(),
|
|
22209
|
+
decision: TopicActivityEntrySchema.shape.decision
|
|
22182
22210
|
});
|
|
22183
22211
|
var TopicRejectArgsSchema = external_exports.object({
|
|
22184
22212
|
topicId: external_exports.string().min(1),
|
|
@@ -23932,7 +23960,7 @@ var METHOD_DOCS = {
|
|
|
23932
23960
|
args: TopicSetPlanArgsSchema
|
|
23933
23961
|
},
|
|
23934
23962
|
"topic:append": {
|
|
23935
|
-
summary:
|
|
23963
|
+
summary: "\u5F80\u8BDD\u9898\u6D41\u6C34\u8FFD\u52A0\u4E00\u6761\uFF1Breason \u5FC5\u586B\u3002Master \u505A\u4EE3\u8001\u677F\u786E\u8BA4\u6216\u5347\u7EA7\u8001\u677F\u51B3\u7B56\u65F6\uFF0C\u5FC5\u987B\u9644 decision\uFF08type/status/question/recommendation\uFF09",
|
|
23936
23964
|
args: TopicAppendArgsSchema
|
|
23937
23965
|
},
|
|
23938
23966
|
"topic:reject": {
|
package/dist/cli.cjs
CHANGED
|
@@ -6876,13 +6876,35 @@ var init_channel = __esm({
|
|
|
6876
6876
|
});
|
|
6877
6877
|
|
|
6878
6878
|
// ../protocol/src/topic.ts
|
|
6879
|
-
var nonBlank2, TOPIC_STATES, TopicStateSchema, TopicActivityEntrySchema, TopicLineMetaSchema, TopicSchema, TopicLineViewSchema, TopicListArgsSchema, TopicGetArgsSchema, TopicCreateArgsSchema, TopicSetPlanArgsSchema, TopicAppendArgsSchema, TopicRejectArgsSchema, TopicAcceptArgsSchema, TopicCloseArgsSchema, TopicRenameArgsSchema, TopicDeleteArgsSchema, TopicListItemSchema, TopicListResultSchema, TopicGetResultSchema, TopicCreateResultSchema, TopicRejectResultSchema, TopicAcceptResultSchema, TopicResultSchema, TopicDeleteResultSchema;
|
|
6879
|
+
var nonBlank2, TOPIC_DECISION_TYPES, TOPIC_DECISION_STATUSES, TOPIC_DECISION_TYPE_MASTER_CONFIRMED, TOPIC_DECISION_TYPE_OWNER_NEEDED, TOPIC_DECISION_STATUS_OPEN, TOPIC_DECISION_STATUS_RESOLVED, TopicDecisionTypeSchema, TopicDecisionStatusSchema, TopicDecisionSchema, TOPIC_STATES, TopicStateSchema, TopicActivityEntrySchema, TopicLineMetaSchema, TopicSchema, TopicLineViewSchema, TopicListArgsSchema, TopicGetArgsSchema, TopicCreateArgsSchema, TopicSetPlanArgsSchema, TopicAppendArgsSchema, TopicRejectArgsSchema, TopicAcceptArgsSchema, TopicCloseArgsSchema, TopicRenameArgsSchema, TopicDeleteArgsSchema, TopicListItemSchema, TopicListResultSchema, TopicGetResultSchema, TopicCreateResultSchema, TopicRejectResultSchema, TopicAcceptResultSchema, TopicResultSchema, TopicDeleteResultSchema;
|
|
6880
6880
|
var init_topic = __esm({
|
|
6881
6881
|
"../protocol/src/topic.ts"() {
|
|
6882
6882
|
"use strict";
|
|
6883
6883
|
init_zod();
|
|
6884
6884
|
init_dispatch();
|
|
6885
6885
|
nonBlank2 = external_exports.string().trim().min(1);
|
|
6886
|
+
TOPIC_DECISION_TYPES = ["master-confirmed", "owner-needed"];
|
|
6887
|
+
TOPIC_DECISION_STATUSES = ["open", "resolved"];
|
|
6888
|
+
TOPIC_DECISION_TYPE_MASTER_CONFIRMED = TOPIC_DECISION_TYPES[0];
|
|
6889
|
+
TOPIC_DECISION_TYPE_OWNER_NEEDED = TOPIC_DECISION_TYPES[1];
|
|
6890
|
+
TOPIC_DECISION_STATUS_OPEN = TOPIC_DECISION_STATUSES[0];
|
|
6891
|
+
TOPIC_DECISION_STATUS_RESOLVED = TOPIC_DECISION_STATUSES[1];
|
|
6892
|
+
TopicDecisionTypeSchema = external_exports.enum(TOPIC_DECISION_TYPES);
|
|
6893
|
+
TopicDecisionStatusSchema = external_exports.enum(TOPIC_DECISION_STATUSES);
|
|
6894
|
+
TopicDecisionSchema = external_exports.object({
|
|
6895
|
+
type: TopicDecisionTypeSchema,
|
|
6896
|
+
status: TopicDecisionStatusSchema,
|
|
6897
|
+
question: nonBlank2,
|
|
6898
|
+
recommendation: nonBlank2
|
|
6899
|
+
}).superRefine((decision, ctx) => {
|
|
6900
|
+
if (decision.type === TOPIC_DECISION_TYPE_MASTER_CONFIRMED && decision.status !== TOPIC_DECISION_STATUS_RESOLVED) {
|
|
6901
|
+
ctx.addIssue({
|
|
6902
|
+
code: external_exports.ZodIssueCode.custom,
|
|
6903
|
+
path: ["status"],
|
|
6904
|
+
message: "master-confirmed decisions must be resolved"
|
|
6905
|
+
});
|
|
6906
|
+
}
|
|
6907
|
+
});
|
|
6886
6908
|
TOPIC_STATES = ["planning", "running", "done"];
|
|
6887
6909
|
TopicStateSchema = external_exports.enum(TOPIC_STATES);
|
|
6888
6910
|
TopicActivityEntrySchema = external_exports.object({
|
|
@@ -6892,7 +6914,12 @@ var init_topic = __esm({
|
|
|
6892
6914
|
target: external_exports.string().optional(),
|
|
6893
6915
|
reason: external_exports.string().min(1),
|
|
6894
6916
|
/** 该动作确认的产出物(watcher 返回的 artifacts);影响面视图的唯一数据源 */
|
|
6895
|
-
artifacts: external_exports.array(nonBlank2).optional()
|
|
6917
|
+
artifacts: external_exports.array(nonBlank2).optional(),
|
|
6918
|
+
/**
|
|
6919
|
+
* Optional decision projection; legacy activity entries omit this field. `open` means the
|
|
6920
|
+
* owner still needs to answer; `resolved` records the conclusion without deleting the question.
|
|
6921
|
+
*/
|
|
6922
|
+
decision: TopicDecisionSchema.optional()
|
|
6896
6923
|
});
|
|
6897
6924
|
TopicLineMetaSchema = external_exports.object({
|
|
6898
6925
|
rejectCount: external_exports.number().int().min(0),
|
|
@@ -6999,7 +7026,8 @@ var init_topic = __esm({
|
|
|
6999
7026
|
target: nonBlank2.optional(),
|
|
7000
7027
|
reason: nonBlank2,
|
|
7001
7028
|
/** 该动作确认的产出物;影响面视图只吃这个字段 */
|
|
7002
|
-
artifacts: external_exports.array(nonBlank2).optional()
|
|
7029
|
+
artifacts: external_exports.array(nonBlank2).optional(),
|
|
7030
|
+
decision: TopicActivityEntrySchema.shape.decision
|
|
7003
7031
|
});
|
|
7004
7032
|
TopicRejectArgsSchema = external_exports.object({
|
|
7005
7033
|
topicId: external_exports.string().min(1),
|
|
@@ -8881,7 +8909,7 @@ var init_methods = __esm({
|
|
|
8881
8909
|
args: TopicSetPlanArgsSchema
|
|
8882
8910
|
},
|
|
8883
8911
|
"topic:append": {
|
|
8884
|
-
summary:
|
|
8912
|
+
summary: "\u5F80\u8BDD\u9898\u6D41\u6C34\u8FFD\u52A0\u4E00\u6761\uFF1Breason \u5FC5\u586B\u3002Master \u505A\u4EE3\u8001\u677F\u786E\u8BA4\u6216\u5347\u7EA7\u8001\u677F\u51B3\u7B56\u65F6\uFF0C\u5FC5\u987B\u9644 decision\uFF08type/status/question/recommendation\uFF09",
|
|
8885
8913
|
args: TopicAppendArgsSchema
|
|
8886
8914
|
},
|
|
8887
8915
|
"topic:reject": {
|
|
@@ -63880,7 +63908,7 @@ function computeMethodAccess(args) {
|
|
|
63880
63908
|
}
|
|
63881
63909
|
|
|
63882
63910
|
// src/version.ts
|
|
63883
|
-
var version = "0.2.
|
|
63911
|
+
var version = "0.2.457".length > 0 ? "0.2.457" : "dev";
|
|
63884
63912
|
|
|
63885
63913
|
// src/cli-probe/probe.ts
|
|
63886
63914
|
var fs70 = __toESM(require("fs"), 1);
|
|
@@ -65632,7 +65660,8 @@ function buildTopicHandlers(deps) {
|
|
|
65632
65660
|
action: args.action,
|
|
65633
65661
|
...args.target ? { target: args.target } : {},
|
|
65634
65662
|
reason: args.reason,
|
|
65635
|
-
...args.artifacts ? { artifacts: args.artifacts } : {}
|
|
65663
|
+
...args.artifacts ? { artifacts: args.artifacts } : {},
|
|
65664
|
+
...args.decision ? { decision: args.decision } : {}
|
|
65636
65665
|
});
|
|
65637
65666
|
announceChanged(topic);
|
|
65638
65667
|
return { response: { ok: true } };
|
|
@@ -19,17 +19,27 @@
|
|
|
19
19
|
S_ACCESS_ALIAS=clawd-fc
|
|
20
20
|
|
|
21
21
|
# 分层加载阿里云 AK 进 env:shared demo(OTA 每次启动覆盖)→ 本机 .local override(永不被覆盖)。
|
|
22
|
+
#
|
|
23
|
+
# 两种来源,**文件优先、env 兜底**:
|
|
24
|
+
# - 本机:`$KIT_DIR/.secrets/aliyun.env`(+ 可选 .local),OTA 刷新;
|
|
25
|
+
# - 云上容器:没有 `.secrets/`(`cloud-host/provision/build-image.mjs` 刻意把它剔出镜像层
|
|
26
|
+
# ——镜像要分发,凭据进层就洗不掉了),AK 由 gateway 经 **MCP server 的 per-server env**
|
|
27
|
+
# 交到调用本脚本的那个进程里(M1b Step 9)。这条分支不落盘是有意的:写成文件的话
|
|
28
|
+
# agent 一个 `cat` 就看见了,而 env 只有这个子进程有。
|
|
22
29
|
ensure_aliyun_env() {
|
|
23
30
|
local kit="${KIT_DIR:?ensure_aliyun_env 需要调用方先设 KIT_DIR}"
|
|
24
|
-
[ -f "$kit/.secrets/aliyun.env" ]
|
|
25
|
-
|
|
31
|
+
if [ -f "$kit/.secrets/aliyun.env" ]; then
|
|
32
|
+
set -a; . "$kit/.secrets/aliyun.env"; set +a
|
|
33
|
+
# aliyun.env.local: 本机个人 override(永远不被 OTA 覆盖,见 refreshDeployKit)。有就后 source 覆盖 env。
|
|
34
|
+
# 写成 if 而不是 `[ -f ] && { }`:后者在函数末尾会把「文件不存在」变成函数返回 1,调用方 set -e 直接中止。
|
|
35
|
+
if [ -f "$kit/.secrets/aliyun.env.local" ]; then
|
|
36
|
+
set -a; . "$kit/.secrets/aliyun.env.local"; set +a
|
|
37
|
+
fi
|
|
38
|
+
elif [ -n "${ALIBABA_CLOUD_ACCESS_KEY_ID:-}" ] && [ -n "${ALIBABA_CLOUD_ACCESS_KEY_SECRET:-}" ]; then
|
|
39
|
+
: # 云上:值已经在本进程 env 里,不落文件
|
|
40
|
+
else
|
|
41
|
+
echo "❌ 缺 $kit/.secrets/aliyun.env(clawd ship 的共享 demo 凭证,OTA 自动刷新),env 里也没有 ALIBABA_CLOUD_ACCESS_KEY_ID/_SECRET。参考 .secrets/aliyun.env.example 填写。" >&2
|
|
26
42
|
return 1
|
|
27
|
-
}
|
|
28
|
-
set -a; . "$kit/.secrets/aliyun.env"; set +a
|
|
29
|
-
# aliyun.env.local: 本机个人 override(永远不被 OTA 覆盖,见 refreshDeployKit)。有就后 source 覆盖 env。
|
|
30
|
-
# 写成 if 而不是 `[ -f ] && { }`:后者在函数末尾会把「文件不存在」变成函数返回 1,调用方 set -e 直接中止。
|
|
31
|
-
if [ -f "$kit/.secrets/aliyun.env.local" ]; then
|
|
32
|
-
set -a; . "$kit/.secrets/aliyun.env.local"; set +a
|
|
33
43
|
fi
|
|
34
44
|
export ALIBABA_CLOUD_REGION_ID="${REGION:?config.env 缺 REGION}"
|
|
35
45
|
}
|
|
@@ -182,11 +182,70 @@ describe('ensure_credentials', () => {
|
|
|
182
182
|
expect(kitAccessYaml()).toContain("AccountID: '5566778899001122'")
|
|
183
183
|
})
|
|
184
184
|
|
|
185
|
-
it('
|
|
185
|
+
it('缺共享凭证文件、env 里也没有 AK 时 fail-loud', () => {
|
|
186
186
|
rmSync(join(box.kit, '.secrets', 'aliyun.env'))
|
|
187
187
|
expect(() => runInKit('ensure_credentials')).toThrow()
|
|
188
188
|
expect(existsSync(join(box.kit, '.s-home', '.s', 'access.yaml'))).toBe(false)
|
|
189
189
|
})
|
|
190
|
+
|
|
191
|
+
// 云上分支(persona 上云 M1b Step 9):容器里没有 `.secrets/`——`build-image.mjs` 刻意把它
|
|
192
|
+
// 剔出镜像层(镜像要分发,凭据进层洗不掉)。AK 由 gateway 经 **MCP server 的 per-server env**
|
|
193
|
+
// 交到调用本脚本的那个子进程里,不落文件:写成文件的话 agent 一个 `cat` 就看见了。
|
|
194
|
+
it('没有 .secrets/aliyun.env 但 env 里有 AK 时用 env(云上容器那条路)', () => {
|
|
195
|
+
rmSync(join(box.kit, '.secrets', 'aliyun.env'))
|
|
196
|
+
const out = execFileSync(
|
|
197
|
+
'bash',
|
|
198
|
+
[
|
|
199
|
+
'-c',
|
|
200
|
+
`set -euo pipefail
|
|
201
|
+
KIT_DIR="${box.kit}"
|
|
202
|
+
REGION=cn-hangzhou
|
|
203
|
+
source "$KIT_DIR/scripts/ensure-credentials.sh"
|
|
204
|
+
ensure_credentials
|
|
205
|
+
printf 'ok %s\\n' "$ALIBABA_CLOUD_ACCESS_KEY_ID"`,
|
|
206
|
+
],
|
|
207
|
+
{
|
|
208
|
+
env: {
|
|
209
|
+
...process.env,
|
|
210
|
+
HOME: box.home,
|
|
211
|
+
PATH: `${box.bin}:${process.env.PATH}`,
|
|
212
|
+
ALIBABA_CLOUD_ACCESS_KEY_ID: 'LTAI-FROM-ENV',
|
|
213
|
+
ALIBABA_CLOUD_ACCESS_KEY_SECRET: 'secret-from-env',
|
|
214
|
+
},
|
|
215
|
+
encoding: 'utf8',
|
|
216
|
+
},
|
|
217
|
+
)
|
|
218
|
+
expect(out).toContain('ok LTAI-FROM-ENV')
|
|
219
|
+
// 走 env 分支照样把凭证落进 kit 私有 s-home(publish 用的是那份 profile),仍不碰用户全局
|
|
220
|
+
expect(kitAccessYaml()).toContain('LTAI-FROM-ENV')
|
|
221
|
+
expect(userAccessYaml()).toContain('LTAI-USER-OWN-KEY')
|
|
222
|
+
})
|
|
223
|
+
|
|
224
|
+
it('文件在就优先用文件(云上那条只是兜底,不能反过来盖掉本机 shared 凭证)', () => {
|
|
225
|
+
const out = execFileSync(
|
|
226
|
+
'bash',
|
|
227
|
+
[
|
|
228
|
+
'-c',
|
|
229
|
+
`set -euo pipefail
|
|
230
|
+
KIT_DIR="${box.kit}"
|
|
231
|
+
REGION=cn-hangzhou
|
|
232
|
+
source "$KIT_DIR/scripts/ensure-credentials.sh"
|
|
233
|
+
ensure_aliyun_env
|
|
234
|
+
printf 'id=%s\\n' "$ALIBABA_CLOUD_ACCESS_KEY_ID"`,
|
|
235
|
+
],
|
|
236
|
+
{
|
|
237
|
+
env: {
|
|
238
|
+
...process.env,
|
|
239
|
+
HOME: box.home,
|
|
240
|
+
PATH: `${box.bin}:${process.env.PATH}`,
|
|
241
|
+
ALIBABA_CLOUD_ACCESS_KEY_ID: 'LTAI-FROM-ENV',
|
|
242
|
+
ALIBABA_CLOUD_ACCESS_KEY_SECRET: 'secret-from-env',
|
|
243
|
+
},
|
|
244
|
+
encoding: 'utf8',
|
|
245
|
+
},
|
|
246
|
+
)
|
|
247
|
+
expect(out).not.toContain('LTAI-FROM-ENV')
|
|
248
|
+
})
|
|
190
249
|
})
|
|
191
250
|
|
|
192
251
|
describe('publish.sh', () => {
|
|
@@ -22056,6 +22056,28 @@ var ChannelDeleteResultSchema = external_exports.object({
|
|
|
22056
22056
|
|
|
22057
22057
|
// ../protocol/src/topic.ts
|
|
22058
22058
|
var nonBlank2 = external_exports.string().trim().min(1);
|
|
22059
|
+
var TOPIC_DECISION_TYPES = ["master-confirmed", "owner-needed"];
|
|
22060
|
+
var TOPIC_DECISION_STATUSES = ["open", "resolved"];
|
|
22061
|
+
var TOPIC_DECISION_TYPE_MASTER_CONFIRMED = TOPIC_DECISION_TYPES[0];
|
|
22062
|
+
var TOPIC_DECISION_TYPE_OWNER_NEEDED = TOPIC_DECISION_TYPES[1];
|
|
22063
|
+
var TOPIC_DECISION_STATUS_OPEN = TOPIC_DECISION_STATUSES[0];
|
|
22064
|
+
var TOPIC_DECISION_STATUS_RESOLVED = TOPIC_DECISION_STATUSES[1];
|
|
22065
|
+
var TopicDecisionTypeSchema = external_exports.enum(TOPIC_DECISION_TYPES);
|
|
22066
|
+
var TopicDecisionStatusSchema = external_exports.enum(TOPIC_DECISION_STATUSES);
|
|
22067
|
+
var TopicDecisionSchema = external_exports.object({
|
|
22068
|
+
type: TopicDecisionTypeSchema,
|
|
22069
|
+
status: TopicDecisionStatusSchema,
|
|
22070
|
+
question: nonBlank2,
|
|
22071
|
+
recommendation: nonBlank2
|
|
22072
|
+
}).superRefine((decision, ctx) => {
|
|
22073
|
+
if (decision.type === TOPIC_DECISION_TYPE_MASTER_CONFIRMED && decision.status !== TOPIC_DECISION_STATUS_RESOLVED) {
|
|
22074
|
+
ctx.addIssue({
|
|
22075
|
+
code: external_exports.ZodIssueCode.custom,
|
|
22076
|
+
path: ["status"],
|
|
22077
|
+
message: "master-confirmed decisions must be resolved"
|
|
22078
|
+
});
|
|
22079
|
+
}
|
|
22080
|
+
});
|
|
22059
22081
|
var TOPIC_STATES = ["planning", "running", "done"];
|
|
22060
22082
|
var TopicStateSchema = external_exports.enum(TOPIC_STATES);
|
|
22061
22083
|
var TopicActivityEntrySchema = external_exports.object({
|
|
@@ -22065,7 +22087,12 @@ var TopicActivityEntrySchema = external_exports.object({
|
|
|
22065
22087
|
target: external_exports.string().optional(),
|
|
22066
22088
|
reason: external_exports.string().min(1),
|
|
22067
22089
|
/** 该动作确认的产出物(watcher 返回的 artifacts);影响面视图的唯一数据源 */
|
|
22068
|
-
artifacts: external_exports.array(nonBlank2).optional()
|
|
22090
|
+
artifacts: external_exports.array(nonBlank2).optional(),
|
|
22091
|
+
/**
|
|
22092
|
+
* Optional decision projection; legacy activity entries omit this field. `open` means the
|
|
22093
|
+
* owner still needs to answer; `resolved` records the conclusion without deleting the question.
|
|
22094
|
+
*/
|
|
22095
|
+
decision: TopicDecisionSchema.optional()
|
|
22069
22096
|
});
|
|
22070
22097
|
var TopicLineMetaSchema = external_exports.object({
|
|
22071
22098
|
rejectCount: external_exports.number().int().min(0),
|
|
@@ -22172,7 +22199,8 @@ var TopicAppendArgsSchema = external_exports.object({
|
|
|
22172
22199
|
target: nonBlank2.optional(),
|
|
22173
22200
|
reason: nonBlank2,
|
|
22174
22201
|
/** 该动作确认的产出物;影响面视图只吃这个字段 */
|
|
22175
|
-
artifacts: external_exports.array(nonBlank2).optional()
|
|
22202
|
+
artifacts: external_exports.array(nonBlank2).optional(),
|
|
22203
|
+
decision: TopicActivityEntrySchema.shape.decision
|
|
22176
22204
|
});
|
|
22177
22205
|
var TopicRejectArgsSchema = external_exports.object({
|
|
22178
22206
|
topicId: external_exports.string().min(1),
|
|
@@ -23925,7 +23953,7 @@ var METHOD_DOCS = {
|
|
|
23925
23953
|
args: TopicSetPlanArgsSchema
|
|
23926
23954
|
},
|
|
23927
23955
|
"topic:append": {
|
|
23928
|
-
summary:
|
|
23956
|
+
summary: "\u5F80\u8BDD\u9898\u6D41\u6C34\u8FFD\u52A0\u4E00\u6761\uFF1Breason \u5FC5\u586B\u3002Master \u505A\u4EE3\u8001\u677F\u786E\u8BA4\u6216\u5347\u7EA7\u8001\u677F\u51B3\u7B56\u65F6\uFF0C\u5FC5\u987B\u9644 decision\uFF08type/status/question/recommendation\uFF09",
|
|
23929
23957
|
args: TopicAppendArgsSchema
|
|
23930
23958
|
},
|
|
23931
23959
|
"topic:reject": {
|
|
@@ -154,6 +154,74 @@ worker 干到一半上报「答不了的问题」(它会以回报形式带出
|
|
|
154
154
|
先自己判断——你是任务源头,多数问题你能答,答了就续派回注。答不了 → 停下上报老板拍板。
|
|
155
155
|
**不许用未经确认的假设擅自解锁一条挂起的线**——除非该假设来自设定里的预授权或老板临场拍板。
|
|
156
156
|
|
|
157
|
+
### 6.1 决策留痕:代老板确认与向老板升级(硬性)
|
|
158
|
+
|
|
159
|
+
worker 的问题不能只在对话里一闪而过。你每次替老板作出判断,或因为判断不了而停线,
|
|
160
|
+
都必须在**作出动作的当下**用 `topic:append` 记录一条决策;普通的派活、收结果、进度更新
|
|
161
|
+
仍按下面「落账纪律」记录,**不要给每条普通流水都加 `decision`**。
|
|
162
|
+
|
|
163
|
+
#### 你能独立判断时:记录 `master-confirmed`
|
|
164
|
+
|
|
165
|
+
只有设定中已有预授权、或问题完全落在本话题已确认的目标/边界/验收标准内,才可以代老板
|
|
166
|
+
确认。先落账并确认 RPC 成功,再把决定回注给对应 worker;落账失败就停下并上报,不能无痕继续:
|
|
167
|
+
|
|
168
|
+
mcp__clawd-rpc__call({ method: 'topic:append', args: {
|
|
169
|
+
topicId, action: '代老板确认:采用方案 A', target: '<lineId>',
|
|
170
|
+
reason: '方案 A 符合已确认的边界 <边界>,不会触碰 <风险>;因此无需打扰老板',
|
|
171
|
+
decision: {
|
|
172
|
+
type: 'master-confirmed', status: 'resolved',
|
|
173
|
+
question: 'worker 提出的问题原文', recommendation: '最终采用的决定',
|
|
174
|
+
},
|
|
175
|
+
}})
|
|
176
|
+
|
|
177
|
+
`target` 必须指向提出问题的 worker lane;`question` 保留问题原文,`recommendation` 写实际
|
|
178
|
+
采取的决定。`reason` 不能只写「符合预授权」,要指出对应哪条边界/标准以及排除了什么风险。
|
|
179
|
+
|
|
180
|
+
#### 你不能独立判断时:记录 `owner-needed` 并停线
|
|
181
|
+
|
|
182
|
+
遇到设定没有覆盖、目标或边界有两种合理解释、会造成不可逆外部影响,或你判断「可能判断错」
|
|
183
|
+
时,**禁止猜测后继续**。先停止给对应 lane 续派;如果 worker 仍在运行,先按下面的方式温柔中断,
|
|
184
|
+
再落账。任何 RPC 失败都要保持暂停并把失败原因一并上报:
|
|
185
|
+
|
|
186
|
+
mcp__clawd-rpc__call({ method: 'session:interrupt', args: {
|
|
187
|
+
sessionId: '<该线的 workerSessionId>',
|
|
188
|
+
}})
|
|
189
|
+
|
|
190
|
+
`session:interrupt` 只结束当前 worker turn,不杀会话、不丢上下文;恢复时仍复用原
|
|
191
|
+
`dispatchId`。如果该调用失败,不能假定 worker 已停下;仍要追加下面的 `owner-needed`
|
|
192
|
+
记录,并在 `reason` 里写明中断失败,继续保持不续派。
|
|
193
|
+
|
|
194
|
+
mcp__clawd-rpc__call({ method: 'topic:append', args: {
|
|
195
|
+
topicId, action: '需要老板拍板:<一句话问题>', target: '<lineId>',
|
|
196
|
+
reason: '现有设定同时允许 <A> 与 <B>,继续执行可能导致 <具体后果>,我无法安全代判',
|
|
197
|
+
decision: {
|
|
198
|
+
type: 'owner-needed', status: 'open',
|
|
199
|
+
question: '请老板在 <选项 A> / <选项 B> 中选择(附必要上下文)',
|
|
200
|
+
recommendation: '如无额外偏好,我建议 <选项>,因为 <理由>',
|
|
201
|
+
},
|
|
202
|
+
}})
|
|
203
|
+
|
|
204
|
+
然后向老板报告这条待决策项,并等待明确答复;不要用普通 `topic:append` 假装已经解决。
|
|
205
|
+
如果 worker 已经 idle,则不需要额外 RPC;只是不再给该 `dispatchId` 续派,等老板答复。
|
|
206
|
+
老板答复后,先把答复原样记录成同一 `target` 的已解决决策,再用**同一个 `dispatchId`**
|
|
207
|
+
续派可执行指令;不要新建第二条线。`session:interrupt` 失败时不能当作已经停住。
|
|
208
|
+
记录已解决决策的调用仍走 `topic:append`:
|
|
209
|
+
|
|
210
|
+
mcp__clawd-rpc__call({ method: 'topic:append', args: {
|
|
211
|
+
topicId, action: '按老板决定:<一句话结论>', target: '<lineId>',
|
|
212
|
+
reason: '老板明确选择了 <选项>,因此按该选择恢复这条线',
|
|
213
|
+
decision: {
|
|
214
|
+
type: 'owner-needed', status: 'resolved',
|
|
215
|
+
question: '<原待决策问题>', recommendation: '老板最终选择:<选项>',
|
|
216
|
+
},
|
|
217
|
+
}})
|
|
218
|
+
|
|
219
|
+
随后才用原 `dispatchId` 续派。决策记录落账失败就不要继续派活,先上报失败原因。
|
|
220
|
+
决策 tab 会据此保留完整的「提出问题 → 得到结论」轨迹。
|
|
221
|
+
|
|
222
|
+
这两类记录是老板在话题「决策」tab 里唯一关注的内容:没有 `decision` 的旧流水不会出现在
|
|
223
|
+
该 tab,但仍保存在话题外部大脑中,供你用 `topic:get` 重建现场。
|
|
224
|
+
|
|
157
225
|
### 7. 收敛与上报
|
|
158
226
|
|
|
159
227
|
`topic:accept` 返回 `allAccepted: true` → 合并 → 自己先验一遍 → 交付。
|