botmux 2.93.1 → 2.94.0
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/adapters/cli/claude-code.d.ts.map +1 -1
- package/dist/adapters/cli/claude-code.js +6 -1
- package/dist/adapters/cli/claude-code.js.map +1 -1
- package/dist/bot-registry.d.ts +10 -1
- package/dist/bot-registry.d.ts.map +1 -1
- package/dist/bot-registry.js +2 -0
- package/dist/bot-registry.js.map +1 -1
- package/dist/cli/workflow.d.ts.map +1 -1
- package/dist/cli/workflow.js +11 -4
- package/dist/cli/workflow.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +133 -1
- package/dist/cli.js.map +1 -1
- package/dist/core/dashboard-ipc-server.d.ts.map +1 -1
- package/dist/core/dashboard-ipc-server.js +3 -0
- package/dist/core/dashboard-ipc-server.js.map +1 -1
- package/dist/core/inherit-peer.d.ts +5 -0
- package/dist/core/inherit-peer.d.ts.map +1 -1
- package/dist/core/inherit-peer.js +3 -0
- package/dist/core/inherit-peer.js.map +1 -1
- package/dist/core/worker-pool.d.ts.map +1 -1
- package/dist/core/worker-pool.js +29 -0
- package/dist/core/worker-pool.js.map +1 -1
- package/dist/daemon.d.ts.map +1 -1
- package/dist/daemon.js +282 -12
- package/dist/daemon.js.map +1 -1
- package/dist/dashboard/auth.d.ts.map +1 -1
- package/dist/dashboard/auth.js +7 -1
- package/dist/dashboard/auth.js.map +1 -1
- package/dist/dashboard/bot-payload.d.ts +1 -0
- package/dist/dashboard/bot-payload.d.ts.map +1 -1
- package/dist/dashboard/bot-payload.js +1 -0
- package/dist/dashboard/bot-payload.js.map +1 -1
- package/dist/dashboard/v3-runs-api.d.ts +26 -0
- package/dist/dashboard/v3-runs-api.d.ts.map +1 -0
- package/dist/dashboard/v3-runs-api.js +67 -0
- package/dist/dashboard/v3-runs-api.js.map +1 -0
- package/dist/dashboard/web/app.js +21 -9
- package/dist/dashboard/web/app.js.map +1 -1
- package/dist/dashboard/web/bot-defaults.d.ts.map +1 -1
- package/dist/dashboard/web/bot-defaults.js +24 -1
- package/dist/dashboard/web/bot-defaults.js.map +1 -1
- package/dist/dashboard/web/i18n.d.ts.map +1 -1
- package/dist/dashboard/web/i18n.js +12 -4
- package/dist/dashboard/web/i18n.js.map +1 -1
- package/dist/dashboard/web/legacy-workflow-link.d.ts +2 -0
- package/dist/dashboard/web/legacy-workflow-link.d.ts.map +1 -0
- package/dist/dashboard/web/legacy-workflow-link.js +12 -0
- package/dist/dashboard/web/legacy-workflow-link.js.map +1 -0
- package/dist/dashboard/web/v3-terminal.d.ts +11 -0
- package/dist/dashboard/web/v3-terminal.d.ts.map +1 -0
- package/dist/dashboard/web/v3-terminal.js +143 -0
- package/dist/dashboard/web/v3-terminal.js.map +1 -0
- package/dist/dashboard/web/v3.d.ts +2 -0
- package/dist/dashboard/web/v3.d.ts.map +1 -0
- package/dist/dashboard/web/v3.js +564 -0
- package/dist/dashboard/web/v3.js.map +1 -0
- package/dist/dashboard/web/workflows.d.ts.map +1 -1
- package/dist/dashboard/web/workflows.js +12 -8
- package/dist/dashboard/web/workflows.js.map +1 -1
- package/dist/dashboard-web/app.js +787 -699
- package/dist/dashboard-web/index.html +1 -1
- package/dist/dashboard-web/style.css +223 -0
- package/dist/dashboard.js +7 -0
- package/dist/dashboard.js.map +1 -1
- package/dist/i18n/en.js +3 -3
- package/dist/i18n/zh.js +3 -3
- package/dist/im/lark/card-handler.d.ts +12 -0
- package/dist/im/lark/card-handler.d.ts.map +1 -1
- package/dist/im/lark/card-handler.js +28 -0
- package/dist/im/lark/card-handler.js.map +1 -1
- package/dist/im/lark/v3-blocked-card-handler.d.ts +28 -0
- package/dist/im/lark/v3-blocked-card-handler.d.ts.map +1 -0
- package/dist/im/lark/v3-blocked-card-handler.js +134 -0
- package/dist/im/lark/v3-blocked-card-handler.js.map +1 -0
- package/dist/im/lark/v3-blocked-card.d.ts +75 -0
- package/dist/im/lark/v3-blocked-card.d.ts.map +1 -0
- package/dist/im/lark/v3-blocked-card.js +206 -0
- package/dist/im/lark/v3-blocked-card.js.map +1 -0
- package/dist/im/lark/v3-gate-card-handler.d.ts +31 -0
- package/dist/im/lark/v3-gate-card-handler.d.ts.map +1 -0
- package/dist/im/lark/v3-gate-card-handler.js +110 -0
- package/dist/im/lark/v3-gate-card-handler.js.map +1 -0
- package/dist/im/lark/v3-gate-card.d.ts +47 -0
- package/dist/im/lark/v3-gate-card.d.ts.map +1 -0
- package/dist/im/lark/v3-gate-card.js +119 -0
- package/dist/im/lark/v3-gate-card.js.map +1 -0
- package/dist/im/lark/v3-loop-grant-card-handler.d.ts +28 -0
- package/dist/im/lark/v3-loop-grant-card-handler.d.ts.map +1 -0
- package/dist/im/lark/v3-loop-grant-card-handler.js +90 -0
- package/dist/im/lark/v3-loop-grant-card-handler.js.map +1 -0
- package/dist/im/lark/v3-loop-grant-card.d.ts +46 -0
- package/dist/im/lark/v3-loop-grant-card.d.ts.map +1 -0
- package/dist/im/lark/v3-loop-grant-card.js +119 -0
- package/dist/im/lark/v3-loop-grant-card.js.map +1 -0
- package/dist/im/lark/v3-revisit-grant-card-handler.d.ts +29 -0
- package/dist/im/lark/v3-revisit-grant-card-handler.d.ts.map +1 -0
- package/dist/im/lark/v3-revisit-grant-card-handler.js +96 -0
- package/dist/im/lark/v3-revisit-grant-card-handler.js.map +1 -0
- package/dist/im/lark/v3-revisit-grant-card.d.ts +52 -0
- package/dist/im/lark/v3-revisit-grant-card.d.ts.map +1 -0
- package/dist/im/lark/v3-revisit-grant-card.js +123 -0
- package/dist/im/lark/v3-revisit-grant-card.js.map +1 -0
- package/dist/im/lark/workflow-cards.d.ts.map +1 -1
- package/dist/im/lark/workflow-cards.js +5 -1
- package/dist/im/lark/workflow-cards.js.map +1 -1
- package/dist/im/lark/workflow-progress-card.d.ts +1 -1
- package/dist/im/lark/workflow-progress-card.js +1 -1
- package/dist/im/lark/workflow-slash-command.d.ts +28 -0
- package/dist/im/lark/workflow-slash-command.d.ts.map +1 -1
- package/dist/im/lark/workflow-slash-command.js +61 -5
- package/dist/im/lark/workflow-slash-command.js.map +1 -1
- package/dist/services/card-prefs-store.d.ts +4 -0
- package/dist/services/card-prefs-store.d.ts.map +1 -1
- package/dist/services/card-prefs-store.js +19 -0
- package/dist/services/card-prefs-store.js.map +1 -1
- package/dist/skills/definitions.d.ts.map +1 -1
- package/dist/skills/definitions.js +208 -4
- package/dist/skills/definitions.js.map +1 -1
- package/dist/worker.js +10 -1
- package/dist/worker.js.map +1 -1
- package/dist/workflows/definition.d.ts +80 -80
- package/dist/workflows/events/payloads.d.ts +4 -4
- package/dist/workflows/events/schema.d.ts +16 -16
- package/dist/workflows/v3/architect.d.ts +37 -0
- package/dist/workflows/v3/architect.d.ts.map +1 -0
- package/dist/workflows/v3/architect.js +226 -0
- package/dist/workflows/v3/architect.js.map +1 -0
- package/dist/workflows/v3/bot-resolve.d.ts +21 -0
- package/dist/workflows/v3/bot-resolve.d.ts.map +1 -0
- package/dist/workflows/v3/bot-resolve.js +47 -0
- package/dist/workflows/v3/bot-resolve.js.map +1 -0
- package/dist/workflows/v3/cli-run.d.ts +24 -0
- package/dist/workflows/v3/cli-run.d.ts.map +1 -0
- package/dist/workflows/v3/cli-run.js +265 -0
- package/dist/workflows/v3/cli-run.js.map +1 -0
- package/dist/workflows/v3/contract.d.ts +302 -0
- package/dist/workflows/v3/contract.d.ts.map +1 -0
- package/dist/workflows/v3/contract.js +91 -0
- package/dist/workflows/v3/contract.js.map +1 -0
- package/dist/workflows/v3/daemon-run.d.ts +311 -0
- package/dist/workflows/v3/daemon-run.d.ts.map +1 -0
- package/dist/workflows/v3/daemon-run.js +775 -0
- package/dist/workflows/v3/daemon-run.js.map +1 -0
- package/dist/workflows/v3/dag.d.ts +332 -0
- package/dist/workflows/v3/dag.d.ts.map +1 -0
- package/dist/workflows/v3/dag.js +1040 -0
- package/dist/workflows/v3/dag.js.map +1 -0
- package/dist/workflows/v3/ephemeral-pool.d.ts +29 -0
- package/dist/workflows/v3/ephemeral-pool.d.ts.map +1 -0
- package/dist/workflows/v3/ephemeral-pool.js +331 -0
- package/dist/workflows/v3/ephemeral-pool.js.map +1 -0
- package/dist/workflows/v3/grill-state.d.ts +92 -0
- package/dist/workflows/v3/grill-state.d.ts.map +1 -0
- package/dist/workflows/v3/grill-state.js +151 -0
- package/dist/workflows/v3/grill-state.js.map +1 -0
- package/dist/workflows/v3/host.d.ts +88 -0
- package/dist/workflows/v3/host.d.ts.map +1 -0
- package/dist/workflows/v3/host.js +349 -0
- package/dist/workflows/v3/host.js.map +1 -0
- package/dist/workflows/v3/human-gate.d.ts +85 -0
- package/dist/workflows/v3/human-gate.d.ts.map +1 -0
- package/dist/workflows/v3/human-gate.js +153 -0
- package/dist/workflows/v3/human-gate.js.map +1 -0
- package/dist/workflows/v3/journal.d.ts +207 -0
- package/dist/workflows/v3/journal.d.ts.map +1 -0
- package/dist/workflows/v3/journal.js +74 -0
- package/dist/workflows/v3/journal.js.map +1 -0
- package/dist/workflows/v3/manifest.d.ts +17 -0
- package/dist/workflows/v3/manifest.d.ts.map +1 -0
- package/dist/workflows/v3/manifest.js +266 -0
- package/dist/workflows/v3/manifest.js.map +1 -0
- package/dist/workflows/v3/ops-projection.d.ts +110 -0
- package/dist/workflows/v3/ops-projection.d.ts.map +1 -0
- package/dist/workflows/v3/ops-projection.js +0 -0
- package/dist/workflows/v3/ops-projection.js.map +1 -0
- package/dist/workflows/v3/orchestrator.d.ts +168 -0
- package/dist/workflows/v3/orchestrator.d.ts.map +1 -0
- package/dist/workflows/v3/orchestrator.js +417 -0
- package/dist/workflows/v3/orchestrator.js.map +1 -0
- package/dist/workflows/v3/runtime.d.ts +193 -0
- package/dist/workflows/v3/runtime.d.ts.map +1 -0
- package/dist/workflows/v3/runtime.js +1284 -0
- package/dist/workflows/v3/runtime.js.map +1 -0
- package/dist/workflows/v3/spec.d.ts +32 -0
- package/dist/workflows/v3/spec.d.ts.map +1 -0
- package/dist/workflows/v3/spec.js +173 -0
- package/dist/workflows/v3/spec.js.map +1 -0
- package/dist/workflows/v3/state.d.ts +74 -0
- package/dist/workflows/v3/state.d.ts.map +1 -0
- package/dist/workflows/v3/state.js +353 -0
- package/dist/workflows/v3/state.js.map +1 -0
- package/package.json +1 -1
- package/dist/dashboard/web/workflow-catalog.d.ts +0 -2
- package/dist/dashboard/web/workflow-catalog.d.ts.map +0 -1
- package/dist/dashboard/web/workflow-catalog.js +0 -323
- package/dist/dashboard/web/workflow-catalog.js.map +0 -1
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v3 blocked-node 重试卡 —— blocked/failed 两档里 blocked(契约性失败,可恢复)
|
|
3
|
+
* 的飞书入口。daemon 驱动的 run 走到 runBlocked 时发这张卡;点「重试」=
|
|
4
|
+
* `requestV3Retry`(append nodeRetryRequested)+ 重驱动,幂等沿 humanGate wait
|
|
5
|
+
* 那套思路(codex 拍的第一版边界:卡只带 runId/nodeId/attemptId/errorCode/
|
|
6
|
+
* message + Retry,不塞 live 终端 / 复杂诊断)。
|
|
7
|
+
*
|
|
8
|
+
* 自带 action namespace(`v3_blocked_retry`),不与 gate 卡混用。纯函数,单测友好。
|
|
9
|
+
*/
|
|
10
|
+
export declare const V3_BLOCKED_RETRY_ACTION = "v3_blocked_retry";
|
|
11
|
+
/** 运行时 human-ask 选项按钮的 action(与「重试」同卡不同 namespace)。 */
|
|
12
|
+
export declare const V3_BLOCKED_ASK_ANSWER_ACTION = "v3_blocked_ask_answer";
|
|
13
|
+
export declare const V3_BLOCKED_ASK_TEXT_FIELD = "v3_blocked_ask_text";
|
|
14
|
+
/** card 按钮回传的 value 形态——v3-blocked-card-handler 据此解析。 */
|
|
15
|
+
export interface V3BlockedActionValue {
|
|
16
|
+
action: typeof V3_BLOCKED_RETRY_ACTION;
|
|
17
|
+
runId: string;
|
|
18
|
+
nodeId: string;
|
|
19
|
+
/** 受阻的 attemptId —— nonce 按它推导,旧 attempt 的 stale 卡天然失效。 */
|
|
20
|
+
attemptId: string;
|
|
21
|
+
nonce: string;
|
|
22
|
+
}
|
|
23
|
+
/** ask 回传的 value —— 人的答案 + 受阻 attempt(freshness)。 */
|
|
24
|
+
export type V3AskAnswerActionValue = {
|
|
25
|
+
action: typeof V3_BLOCKED_ASK_ANSWER_ACTION;
|
|
26
|
+
runId: string;
|
|
27
|
+
nodeId: string;
|
|
28
|
+
attemptId: string;
|
|
29
|
+
/** 选中的选项文本(= GoalAsk.options 之一),落库为 answer.selected。 */
|
|
30
|
+
selected: string;
|
|
31
|
+
nonce: string;
|
|
32
|
+
} | {
|
|
33
|
+
action: typeof V3_BLOCKED_ASK_ANSWER_ACTION;
|
|
34
|
+
runId: string;
|
|
35
|
+
nodeId: string;
|
|
36
|
+
attemptId: string;
|
|
37
|
+
/** 自由文本答案走 form_value[V3_BLOCKED_ASK_TEXT_FIELD],不塞进 button value。 */
|
|
38
|
+
answerKind: 'text';
|
|
39
|
+
nonce: string;
|
|
40
|
+
};
|
|
41
|
+
export interface V3BlockedCardInput {
|
|
42
|
+
runId: string;
|
|
43
|
+
nodeId: string;
|
|
44
|
+
attemptId: string;
|
|
45
|
+
errorClass?: string;
|
|
46
|
+
errorCode?: string;
|
|
47
|
+
message?: string;
|
|
48
|
+
/** 省略则按 runId/nodeId/attemptId 推导(幂等校验用)。 */
|
|
49
|
+
nonce?: string;
|
|
50
|
+
webDetailUrl?: string;
|
|
51
|
+
messageMaxChars?: number;
|
|
52
|
+
/** 有值 → 渲染冻结的「已重试」卡(无按钮,防 stale UI 重复提交)。 */
|
|
53
|
+
retried?: {
|
|
54
|
+
nextAttemptId: string;
|
|
55
|
+
by?: string;
|
|
56
|
+
};
|
|
57
|
+
/** 运行时 human-ask:agent 的问题 → 渲染选项按钮或自由文本输入卡。 */
|
|
58
|
+
ask?: {
|
|
59
|
+
question: string;
|
|
60
|
+
options?: string[];
|
|
61
|
+
freeText?: boolean;
|
|
62
|
+
};
|
|
63
|
+
/** 有值 → 渲染冻结的「已回答」卡(ask 专用,无按钮)。 */
|
|
64
|
+
answered?: {
|
|
65
|
+
selected?: string;
|
|
66
|
+
text?: string;
|
|
67
|
+
nextAttemptId: string;
|
|
68
|
+
by?: string;
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
/** 稳定 nonce:同一 run 同一节点同一 attempt 的卡 nonce 固定(重发卡一致);
|
|
72
|
+
* attempt 入 nonce —— 重试后旧卡的 nonce 对不上新 attempt,不会误触。 */
|
|
73
|
+
export declare function v3BlockedCardNonce(runId: string, nodeId: string, attemptId: string): string;
|
|
74
|
+
export declare function buildV3BlockedCard(input: V3BlockedCardInput): string;
|
|
75
|
+
//# sourceMappingURL=v3-blocked-card.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"v3-blocked-card.d.ts","sourceRoot":"","sources":["../../../src/im/lark/v3-blocked-card.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,eAAO,MAAM,uBAAuB,qBAAqB,CAAC;AAC1D,uDAAuD;AACvD,eAAO,MAAM,4BAA4B,0BAA0B,CAAC;AACpE,eAAO,MAAM,yBAAyB,wBAAwB,CAAC;AAE/D,yDAAyD;AACzD,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,OAAO,uBAAuB,CAAC;IACvC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,2DAA2D;IAC3D,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,qDAAqD;AACrD,MAAM,MAAM,sBAAsB,GAC9B;IACE,MAAM,EAAE,OAAO,4BAA4B,CAAC;IAC5C,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,yDAAyD;IACzD,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;CACf,GACD;IACE,MAAM,EAAE,OAAO,4BAA4B,CAAC;IAC5C,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,sEAAsE;IACtE,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEN,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,6CAA6C;IAC7C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,6CAA6C;IAC7C,OAAO,CAAC,EAAE;QAAE,aAAa,EAAE,MAAM,CAAC;QAAC,EAAE,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACjD,gDAAgD;IAChD,GAAG,CAAC,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IACnE,oCAAoC;IACpC,QAAQ,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAC;QAAC,EAAE,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACrF;AAID;yDACyD;AACzD,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAE3F;AAMD,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,kBAAkB,GAAG,MAAM,CAiKpE"}
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v3 blocked-node 重试卡 —— blocked/failed 两档里 blocked(契约性失败,可恢复)
|
|
3
|
+
* 的飞书入口。daemon 驱动的 run 走到 runBlocked 时发这张卡;点「重试」=
|
|
4
|
+
* `requestV3Retry`(append nodeRetryRequested)+ 重驱动,幂等沿 humanGate wait
|
|
5
|
+
* 那套思路(codex 拍的第一版边界:卡只带 runId/nodeId/attemptId/errorCode/
|
|
6
|
+
* message + Retry,不塞 live 终端 / 复杂诊断)。
|
|
7
|
+
*
|
|
8
|
+
* 自带 action namespace(`v3_blocked_retry`),不与 gate 卡混用。纯函数,单测友好。
|
|
9
|
+
*/
|
|
10
|
+
import { config } from '../../config.js';
|
|
11
|
+
export const V3_BLOCKED_RETRY_ACTION = 'v3_blocked_retry';
|
|
12
|
+
/** 运行时 human-ask 选项按钮的 action(与「重试」同卡不同 namespace)。 */
|
|
13
|
+
export const V3_BLOCKED_ASK_ANSWER_ACTION = 'v3_blocked_ask_answer';
|
|
14
|
+
export const V3_BLOCKED_ASK_TEXT_FIELD = 'v3_blocked_ask_text';
|
|
15
|
+
const DEFAULT_MESSAGE_MAX_CHARS = 500;
|
|
16
|
+
/** 稳定 nonce:同一 run 同一节点同一 attempt 的卡 nonce 固定(重发卡一致);
|
|
17
|
+
* attempt 入 nonce —— 重试后旧卡的 nonce 对不上新 attempt,不会误触。 */
|
|
18
|
+
export function v3BlockedCardNonce(runId, nodeId, attemptId) {
|
|
19
|
+
return `v3blocked:${runId}:${nodeId}:${attemptId}`;
|
|
20
|
+
}
|
|
21
|
+
function v3RunDetailUrl(runId) {
|
|
22
|
+
return `http://${config.dashboard.externalHost}:${config.dashboard.port}/#/v3/${encodeURIComponent(runId)}`;
|
|
23
|
+
}
|
|
24
|
+
export function buildV3BlockedCard(input) {
|
|
25
|
+
const nonce = input.nonce ?? v3BlockedCardNonce(input.runId, input.nodeId, input.attemptId);
|
|
26
|
+
const webDetailUrl = input.webDetailUrl ?? v3RunDetailUrl(input.runId);
|
|
27
|
+
const msgMax = input.messageMaxChars ?? DEFAULT_MESSAGE_MAX_CHARS;
|
|
28
|
+
const { retried, ask, answered } = input;
|
|
29
|
+
// 四态共用一张卡,header 决定语气:蓝=等人拍板 / 绿=已回答·已重试 / 橙=受阻待重试。
|
|
30
|
+
let title;
|
|
31
|
+
let template;
|
|
32
|
+
if (answered) {
|
|
33
|
+
title = `已回答:节点 ${input.nodeId}`;
|
|
34
|
+
template = 'green';
|
|
35
|
+
}
|
|
36
|
+
else if (ask) {
|
|
37
|
+
title = `需要你拍板:节点 ${input.nodeId}`;
|
|
38
|
+
template = 'blue';
|
|
39
|
+
}
|
|
40
|
+
else if (retried) {
|
|
41
|
+
title = `已重试:节点 ${input.nodeId}`;
|
|
42
|
+
template = 'green';
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
title = `节点受阻:${input.nodeId}`;
|
|
46
|
+
template = 'orange';
|
|
47
|
+
}
|
|
48
|
+
const attemptNNN = input.attemptId.slice(input.attemptId.lastIndexOf('/') + 1);
|
|
49
|
+
const elements = [
|
|
50
|
+
{
|
|
51
|
+
tag: 'div',
|
|
52
|
+
fields: [
|
|
53
|
+
{ is_short: true, text: { tag: 'lark_md', content: `**Run**\n${escapeMd(short(input.runId, 24))}` } },
|
|
54
|
+
{ is_short: true, text: { tag: 'lark_md', content: `**节点 / attempt**\n${escapeMd(input.nodeId)} · ${escapeMd(attemptNNN)}` } },
|
|
55
|
+
],
|
|
56
|
+
},
|
|
57
|
+
{ tag: 'hr' },
|
|
58
|
+
];
|
|
59
|
+
if (ask || answered) {
|
|
60
|
+
// ── 运行时 human-ask:渲染问题 + 选项按钮(或冻结的「已回答」)──
|
|
61
|
+
const question = ask?.question;
|
|
62
|
+
if (question) {
|
|
63
|
+
elements.push({
|
|
64
|
+
tag: 'div',
|
|
65
|
+
text: { tag: 'lark_md', content: `**${escapeMd(truncate(question, msgMax))}**` },
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
if (answered) {
|
|
69
|
+
const answerPreview = answered.text ?? answered.selected ?? '';
|
|
70
|
+
elements.push({ tag: 'hr' });
|
|
71
|
+
elements.push({
|
|
72
|
+
tag: 'div',
|
|
73
|
+
text: {
|
|
74
|
+
tag: 'lark_md',
|
|
75
|
+
content: `✅ 已回答 → **${escapeMd(truncate(answerPreview, msgMax))}**` +
|
|
76
|
+
(answered.by ? ` · by ${escapeMd(short(answered.by, 20))}` : '') +
|
|
77
|
+
` · 重跑 ${escapeMd(answered.nextAttemptId.slice(answered.nextAttemptId.lastIndexOf('/') + 1))}`,
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
else if (ask?.freeText) {
|
|
82
|
+
elements.push({
|
|
83
|
+
tag: 'form',
|
|
84
|
+
name: 'v3_blocked_ask_text_form',
|
|
85
|
+
elements: [
|
|
86
|
+
{
|
|
87
|
+
tag: 'input',
|
|
88
|
+
name: V3_BLOCKED_ASK_TEXT_FIELD,
|
|
89
|
+
placeholder: { tag: 'plain_text', content: '填写答案' },
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
tag: 'button',
|
|
93
|
+
text: { tag: 'plain_text', content: '提交并重跑' },
|
|
94
|
+
type: 'primary',
|
|
95
|
+
name: 'v3_blocked_ask_text_submit',
|
|
96
|
+
action_type: 'form_submit',
|
|
97
|
+
value: {
|
|
98
|
+
action: V3_BLOCKED_ASK_ANSWER_ACTION,
|
|
99
|
+
runId: input.runId,
|
|
100
|
+
nodeId: input.nodeId,
|
|
101
|
+
attemptId: input.attemptId,
|
|
102
|
+
answerKind: 'text',
|
|
103
|
+
nonce,
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
],
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
else if (ask) {
|
|
110
|
+
// 一个选项一个按钮,选中文本回传为 answer.selected(按 attempt 入 nonce 防 stale)。
|
|
111
|
+
elements.push({
|
|
112
|
+
tag: 'action',
|
|
113
|
+
actions: (ask.options ?? []).map((opt) => ({
|
|
114
|
+
tag: 'button',
|
|
115
|
+
text: { tag: 'plain_text', content: short(opt, 80) },
|
|
116
|
+
type: 'primary',
|
|
117
|
+
value: {
|
|
118
|
+
action: V3_BLOCKED_ASK_ANSWER_ACTION,
|
|
119
|
+
runId: input.runId,
|
|
120
|
+
nodeId: input.nodeId,
|
|
121
|
+
attemptId: input.attemptId,
|
|
122
|
+
selected: opt,
|
|
123
|
+
nonce,
|
|
124
|
+
},
|
|
125
|
+
})),
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
// ── 普通受阻 / 已重试 ──
|
|
131
|
+
elements.push({
|
|
132
|
+
tag: 'div',
|
|
133
|
+
text: {
|
|
134
|
+
tag: 'lark_md',
|
|
135
|
+
content: `**原因**\n${escapeMd(input.errorClass ?? 'blocked')}` +
|
|
136
|
+
(input.errorCode ? ` · \`${escapeMd(input.errorCode)}\`` : '') +
|
|
137
|
+
(input.message ? `\n${escapeMd(truncate(input.message, msgMax))}` : ''),
|
|
138
|
+
},
|
|
139
|
+
});
|
|
140
|
+
if (retried) {
|
|
141
|
+
elements.push({ tag: 'hr' });
|
|
142
|
+
elements.push({
|
|
143
|
+
tag: 'div',
|
|
144
|
+
text: {
|
|
145
|
+
tag: 'lark_md',
|
|
146
|
+
content: `🔄 已重试 → ${escapeMd(retried.nextAttemptId.slice(retried.nextAttemptId.lastIndexOf('/') + 1))}` +
|
|
147
|
+
(retried.by ? ` · by ${escapeMd(short(retried.by, 20))}` : ''),
|
|
148
|
+
},
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
elements.push({
|
|
153
|
+
tag: 'div',
|
|
154
|
+
text: { tag: 'lark_md', content: '处理掉阻塞原因(如完成鉴权)后点重试,会以新 attempt 重跑该节点。' },
|
|
155
|
+
});
|
|
156
|
+
elements.push({
|
|
157
|
+
tag: 'action',
|
|
158
|
+
actions: [
|
|
159
|
+
{
|
|
160
|
+
tag: 'button',
|
|
161
|
+
text: { tag: 'plain_text', content: '🔄 重试' },
|
|
162
|
+
type: 'primary',
|
|
163
|
+
value: {
|
|
164
|
+
action: V3_BLOCKED_RETRY_ACTION,
|
|
165
|
+
runId: input.runId,
|
|
166
|
+
nodeId: input.nodeId,
|
|
167
|
+
attemptId: input.attemptId,
|
|
168
|
+
nonce,
|
|
169
|
+
},
|
|
170
|
+
},
|
|
171
|
+
],
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
elements.push({
|
|
176
|
+
tag: 'action',
|
|
177
|
+
actions: [
|
|
178
|
+
{
|
|
179
|
+
tag: 'button',
|
|
180
|
+
text: { tag: 'plain_text', content: 'Web 详情' },
|
|
181
|
+
type: 'default',
|
|
182
|
+
multi_url: {
|
|
183
|
+
url: webDetailUrl, pc_url: webDetailUrl, android_url: webDetailUrl, ios_url: webDetailUrl,
|
|
184
|
+
},
|
|
185
|
+
},
|
|
186
|
+
],
|
|
187
|
+
});
|
|
188
|
+
return JSON.stringify({
|
|
189
|
+
config: { wide_screen_mode: true },
|
|
190
|
+
header: { template, title: { tag: 'plain_text', content: title } },
|
|
191
|
+
elements,
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
function truncate(s, max) {
|
|
195
|
+
if (s.length <= max)
|
|
196
|
+
return s;
|
|
197
|
+
return `${s.slice(0, max)}…(截断,完整见 Web 详情)`;
|
|
198
|
+
}
|
|
199
|
+
function short(s, max) {
|
|
200
|
+
return s.length <= max ? s : `${s.slice(0, max)}…`;
|
|
201
|
+
}
|
|
202
|
+
/** 转义 lark_md 里会被解析的字符,防 message 注入破坏卡片结构。 */
|
|
203
|
+
function escapeMd(s) {
|
|
204
|
+
return s.replace(/[\\*_~`\[\]]/g, (c) => `\\${c}`);
|
|
205
|
+
}
|
|
206
|
+
//# sourceMappingURL=v3-blocked-card.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"v3-blocked-card.js","sourceRoot":"","sources":["../../../src/im/lark/v3-blocked-card.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v3 humanGate 审批卡点击处理 —— card-handler 的 v3 分支(对称于 v0.2 的
|
|
3
|
+
* `workflow-card-handler`,但走 v3 自己的 wait/journal 权威,不复用 v0.2 wait
|
|
4
|
+
* path)。把一次点击翻译成:权限校验 → `resolveV3GateClick`(幂等 + terminal-safe)
|
|
5
|
+
* → 冻结卡 / toast + 触发 `driveV3Run` 续跑。
|
|
6
|
+
*
|
|
7
|
+
* 纯逻辑 + 注入 seam(resolveClick / driveRun / canResolve),单测友好;真正的
|
|
8
|
+
* Lark 发送 / driveV3Run 由 daemon 在 deps 里接。
|
|
9
|
+
*/
|
|
10
|
+
import { type V3GateActionValue } from './v3-gate-card.js';
|
|
11
|
+
import { resolveV3GateClick } from '../../workflows/v3/daemon-run.js';
|
|
12
|
+
import { type RunChatBinding } from '../../workflows/v3/grill-state.js';
|
|
13
|
+
export declare function isV3GateAction(action: unknown): boolean;
|
|
14
|
+
export interface V3GateCardHandlerDeps {
|
|
15
|
+
baseDir?: string;
|
|
16
|
+
/** Re-enter the run after a resolved gate. Fire-and-forget; the daemon logs
|
|
17
|
+
* errors (this is the `driveV3Run` wiring with postGateCard/onTerminal). */
|
|
18
|
+
driveRun: (runId: string) => void;
|
|
19
|
+
/** Permission: may this operator resolve gates for this run? Default: allow
|
|
20
|
+
* (MVP — daemon injects a canOperate-backed check). */
|
|
21
|
+
canResolve?: (binding: RunChatBinding | undefined, operatorOpenId: string | undefined) => boolean;
|
|
22
|
+
/** Injectable for tests. Default = real resolveV3GateClick. */
|
|
23
|
+
resolveClick?: typeof resolveV3GateClick;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Handle a v3 gate card click. Returns the Lark card-action response: a frozen
|
|
27
|
+
* card object (replaces the clicked card so its buttons can't re-submit), or a
|
|
28
|
+
* `{ toast }` wrapper. Triggers `driveRun` as a side effect on a real resolve.
|
|
29
|
+
*/
|
|
30
|
+
export declare function handleV3GateAction(value: V3GateActionValue, operatorOpenId: string | undefined, deps: V3GateCardHandlerDeps): Promise<unknown>;
|
|
31
|
+
//# sourceMappingURL=v3-gate-card-handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"v3-gate-card-handler.d.ts","sourceRoot":"","sources":["../../../src/im/lark/v3-gate-card-handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAKL,KAAK,iBAAiB,EACvB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAC;AACtE,OAAO,EAGL,KAAK,cAAc,EACpB,MAAM,mCAAmC,CAAC;AAI3C,wBAAgB,cAAc,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAEvD;AAED,MAAM,WAAW,qBAAqB;IACpC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;iFAC6E;IAC7E,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC;4DACwD;IACxD,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,cAAc,GAAG,SAAS,EAAE,cAAc,EAAE,MAAM,GAAG,SAAS,KAAK,OAAO,CAAC;IAClG,+DAA+D;IAC/D,YAAY,CAAC,EAAE,OAAO,kBAAkB,CAAC;CAC1C;AAED;;;;GAIG;AACH,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,iBAAiB,EACxB,cAAc,EAAE,MAAM,GAAG,SAAS,EAClC,IAAI,EAAE,qBAAqB,GAC1B,OAAO,CAAC,OAAO,CAAC,CAwFlB"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v3 humanGate 审批卡点击处理 —— card-handler 的 v3 分支(对称于 v0.2 的
|
|
3
|
+
* `workflow-card-handler`,但走 v3 自己的 wait/journal 权威,不复用 v0.2 wait
|
|
4
|
+
* path)。把一次点击翻译成:权限校验 → `resolveV3GateClick`(幂等 + terminal-safe)
|
|
5
|
+
* → 冻结卡 / toast + 触发 `driveV3Run` 续跑。
|
|
6
|
+
*
|
|
7
|
+
* 纯逻辑 + 注入 seam(resolveClick / driveRun / canResolve),单测友好;真正的
|
|
8
|
+
* Lark 发送 / driveV3Run 由 daemon 在 deps 里接。
|
|
9
|
+
*/
|
|
10
|
+
import { join } from 'node:path';
|
|
11
|
+
import { V3_GATE_APPROVE_ACTION, V3_GATE_REJECT_ACTION, buildV3GateCard, v3GateCardNonce, } from './v3-gate-card.js';
|
|
12
|
+
import { resolveV3GateClick } from '../../workflows/v3/daemon-run.js';
|
|
13
|
+
import { readGrillState, defaultBaseDir, } from '../../workflows/v3/grill-state.js';
|
|
14
|
+
import { readWait } from '../../workflows/v3/human-gate.js';
|
|
15
|
+
import { isValidRunId, isValidWaitId } from '../../workflows/v3/ops-projection.js';
|
|
16
|
+
export function isV3GateAction(action) {
|
|
17
|
+
return action === V3_GATE_APPROVE_ACTION || action === V3_GATE_REJECT_ACTION;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Handle a v3 gate card click. Returns the Lark card-action response: a frozen
|
|
21
|
+
* card object (replaces the clicked card so its buttons can't re-submit), or a
|
|
22
|
+
* `{ toast }` wrapper. Triggers `driveRun` as a side effect on a real resolve.
|
|
23
|
+
*/
|
|
24
|
+
export async function handleV3GateAction(value, operatorOpenId, deps) {
|
|
25
|
+
const baseDir = deps.baseDir ?? defaultBaseDir();
|
|
26
|
+
// Guard BOTH externally-supplied ids before any path join: waitId flows into
|
|
27
|
+
// `runDir/waits/<waitId>.json` (resolveV3GateClick → human-gate), and the
|
|
28
|
+
// reproducible non-secret nonce can't stop a `../..` waitId on its own.
|
|
29
|
+
if (!isValidRunId(value.runId)) {
|
|
30
|
+
return { toast: { type: 'warning', content: 'gate 已失效(非法 run)' } };
|
|
31
|
+
}
|
|
32
|
+
if (typeof value.waitId !== 'string' || !isValidWaitId(value.waitId)) {
|
|
33
|
+
return { toast: { type: 'warning', content: 'gate 已失效(非法 wait)' } };
|
|
34
|
+
}
|
|
35
|
+
// Nonce check (codex medium): the card carries a stable nonce; a value whose
|
|
36
|
+
// nonce doesn't match the run/wait pair is a tampered/foreign card → stale.
|
|
37
|
+
if (value.nonce !== v3GateCardNonce(value.runId, value.waitId)) {
|
|
38
|
+
return { toast: { type: 'warning', content: 'gate 卡已失效(nonce 不匹配)' } };
|
|
39
|
+
}
|
|
40
|
+
const runDir = join(baseDir, value.runId);
|
|
41
|
+
const grill = readGrillState(runDir);
|
|
42
|
+
const binding = grill?.chatBinding;
|
|
43
|
+
if (deps.canResolve && !deps.canResolve(binding, operatorOpenId)) {
|
|
44
|
+
return { toast: { type: 'warning', content: '你没有权限审批这个 gate' } };
|
|
45
|
+
}
|
|
46
|
+
const selected = value.selected ?? (value.action === V3_GATE_APPROVE_ACTION ? 'approve' : 'reject');
|
|
47
|
+
const resolveClick = deps.resolveClick ?? resolveV3GateClick;
|
|
48
|
+
let outcome;
|
|
49
|
+
try {
|
|
50
|
+
outcome = resolveClick(baseDir, value.runId, {
|
|
51
|
+
waitId: value.waitId,
|
|
52
|
+
selected,
|
|
53
|
+
by: operatorOpenId ?? 'unknown',
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
catch (err) {
|
|
57
|
+
// journal append failed after resolveWait (codex #5): warn + don't fake
|
|
58
|
+
// success; the card stays clickable, cold-attach reconcile heals on restart.
|
|
59
|
+
return {
|
|
60
|
+
toast: {
|
|
61
|
+
type: 'error',
|
|
62
|
+
content: `处理失败,请重试:${err instanceof Error ? err.message : String(err)}`,
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
if (outcome.kind === 'stale-run') {
|
|
67
|
+
return {
|
|
68
|
+
toast: {
|
|
69
|
+
type: 'warning',
|
|
70
|
+
content: outcome.reason === 'terminal' ? '该 run 已结束,gate 失效' : 'gate 已失效',
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
if (outcome.kind === 'already-settled') {
|
|
75
|
+
// Idempotent recovery (codex nit #14): if a prior click already APPROVED the
|
|
76
|
+
// gate but its driveRun didn't land (transient), a re-click should re-drive
|
|
77
|
+
// instead of dead-ending at an info toast — mirrors the blocked/loop grant
|
|
78
|
+
// handlers' already-granted branch. driveRun is terminal-safe (short-circuits
|
|
79
|
+
// a finished run), so this is harmless if the run already moved on. A rejected
|
|
80
|
+
// gate is terminal-ish, so don't re-drive it.
|
|
81
|
+
if (outcome.status === 'approved')
|
|
82
|
+
deps.driveRun(value.runId);
|
|
83
|
+
return {
|
|
84
|
+
toast: {
|
|
85
|
+
type: 'info',
|
|
86
|
+
content: `已是「${outcome.status === 'approved' ? '通过' : '拒绝'}」状态`,
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
if (outcome.kind === 'unauthorized') {
|
|
91
|
+
return {
|
|
92
|
+
toast: {
|
|
93
|
+
type: 'warning',
|
|
94
|
+
content: '你不在这个 gate 的审批人名单中',
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
// resolved → drive the run forward (fresh replay) + freeze this card.
|
|
99
|
+
deps.driveRun(value.runId);
|
|
100
|
+
const prompt = readWait(runDir, value.waitId)?.prompt ?? '';
|
|
101
|
+
const frozen = buildV3GateCard({
|
|
102
|
+
runId: value.runId,
|
|
103
|
+
waitId: value.waitId,
|
|
104
|
+
nodeId: value.nodeId,
|
|
105
|
+
prompt,
|
|
106
|
+
resolution: { kind: outcome.resolution, by: operatorOpenId, selected },
|
|
107
|
+
});
|
|
108
|
+
return JSON.parse(frozen);
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=v3-gate-card-handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"v3-gate-card-handler.js","sourceRoot":"","sources":["../../../src/im/lark/v3-gate-card-handler.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v3 humanGate 审批卡 — 复用 v0.2 审批卡的视觉(header 配色 / 字段 / freeze 态),
|
|
3
|
+
* 但**自带 action namespace + value 形态**(codex review #4):
|
|
4
|
+
* - action: `v3_gate_approve` / `v3_gate_reject`
|
|
5
|
+
* - value: `{ action, runId, waitId, nodeId, nonce, selected }`
|
|
6
|
+
* 刻意不复用 v0.2 `workflow-card-handler` 的 wait path —— v3 的 wait 权威是
|
|
7
|
+
* `waits/<id>.json + journal.ndjson`,跟 v0.2 events schema 不同(见 humanGate
|
|
8
|
+
* daemon-card 设计 §4.3)。本文件**纯函数**,不碰 daemon / IO,单测友好。
|
|
9
|
+
*/
|
|
10
|
+
export declare const V3_GATE_APPROVE_ACTION = "v3_gate_approve";
|
|
11
|
+
export declare const V3_GATE_REJECT_ACTION = "v3_gate_reject";
|
|
12
|
+
export type V3GateResolutionKind = 'approved' | 'rejected';
|
|
13
|
+
/** card 按钮回传的 value 形态——v3-gate-card-handler 据此解析。 */
|
|
14
|
+
export interface V3GateActionValue {
|
|
15
|
+
action: typeof V3_GATE_APPROVE_ACTION | typeof V3_GATE_REJECT_ACTION;
|
|
16
|
+
runId: string;
|
|
17
|
+
/** waitId = `${nodeId}-gate`;nodeId 单独带,免得 handler 去 strip 后缀(节点名可能含 -gate)。 */
|
|
18
|
+
waitId: string;
|
|
19
|
+
nodeId: string;
|
|
20
|
+
nonce: string;
|
|
21
|
+
selected?: string;
|
|
22
|
+
}
|
|
23
|
+
export interface V3GateCardInput {
|
|
24
|
+
runId: string;
|
|
25
|
+
waitId: string;
|
|
26
|
+
nodeId: string;
|
|
27
|
+
prompt: string;
|
|
28
|
+
/** 卡 nonce(防 stale 卡重复触发);省略则按 runId/waitId 推导。 */
|
|
29
|
+
nonce?: string;
|
|
30
|
+
webDetailUrl?: string;
|
|
31
|
+
promptMaxChars?: number;
|
|
32
|
+
options?: string[];
|
|
33
|
+
approveOptions?: string[];
|
|
34
|
+
approvers?: string[];
|
|
35
|
+
/** 有值 → 渲染冻结的「已通过 / 已拒绝」卡(无按钮,防 stale UI 重复提交)。 */
|
|
36
|
+
resolution?: {
|
|
37
|
+
kind: V3GateResolutionKind;
|
|
38
|
+
by?: string;
|
|
39
|
+
selected?: string;
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
/** 稳定 nonce:同一 run 同一 wait 的卡 nonce 固定,重发卡也一致(幂等校验用)。 */
|
|
43
|
+
export declare function v3GateCardNonce(runId: string, waitId: string): string;
|
|
44
|
+
/** v3 run 在 dashboard 的详情页 URL(跟 v0.2 的 #/workflows 对称,走 #/v3)。 */
|
|
45
|
+
export declare function v3RunDetailUrl(runId: string): string;
|
|
46
|
+
export declare function buildV3GateCard(input: V3GateCardInput): string;
|
|
47
|
+
//# sourceMappingURL=v3-gate-card.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"v3-gate-card.d.ts","sourceRoot":"","sources":["../../../src/im/lark/v3-gate-card.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,eAAO,MAAM,sBAAsB,oBAAoB,CAAC;AACxD,eAAO,MAAM,qBAAqB,mBAAmB,CAAC;AAEtD,MAAM,MAAM,oBAAoB,GAAG,UAAU,GAAG,UAAU,CAAC;AAE3D,sDAAsD;AACtD,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,OAAO,sBAAsB,GAAG,OAAO,qBAAqB,CAAC;IACrE,KAAK,EAAE,MAAM,CAAC;IACd,gFAAgF;IAChF,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,mDAAmD;IACnD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,mDAAmD;IACnD,UAAU,CAAC,EAAE;QAAE,IAAI,EAAE,oBAAoB,CAAC;QAAC,EAAE,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC7E;AAID,yDAAyD;AACzD,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAErE;AAED,mEAAmE;AACnE,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM,CAmE9D"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v3 humanGate 审批卡 — 复用 v0.2 审批卡的视觉(header 配色 / 字段 / freeze 态),
|
|
3
|
+
* 但**自带 action namespace + value 形态**(codex review #4):
|
|
4
|
+
* - action: `v3_gate_approve` / `v3_gate_reject`
|
|
5
|
+
* - value: `{ action, runId, waitId, nodeId, nonce, selected }`
|
|
6
|
+
* 刻意不复用 v0.2 `workflow-card-handler` 的 wait path —— v3 的 wait 权威是
|
|
7
|
+
* `waits/<id>.json + journal.ndjson`,跟 v0.2 events schema 不同(见 humanGate
|
|
8
|
+
* daemon-card 设计 §4.3)。本文件**纯函数**,不碰 daemon / IO,单测友好。
|
|
9
|
+
*/
|
|
10
|
+
import { config } from '../../config.js';
|
|
11
|
+
import { DEFAULT_HUMAN_GATE_OPTIONS } from '../../workflows/v3/dag.js';
|
|
12
|
+
export const V3_GATE_APPROVE_ACTION = 'v3_gate_approve';
|
|
13
|
+
export const V3_GATE_REJECT_ACTION = 'v3_gate_reject';
|
|
14
|
+
const DEFAULT_PROMPT_MAX_CHARS = 500;
|
|
15
|
+
/** 稳定 nonce:同一 run 同一 wait 的卡 nonce 固定,重发卡也一致(幂等校验用)。 */
|
|
16
|
+
export function v3GateCardNonce(runId, waitId) {
|
|
17
|
+
return `v3gate:${runId}:${waitId}`;
|
|
18
|
+
}
|
|
19
|
+
/** v3 run 在 dashboard 的详情页 URL(跟 v0.2 的 #/workflows 对称,走 #/v3)。 */
|
|
20
|
+
export function v3RunDetailUrl(runId) {
|
|
21
|
+
return `http://${config.dashboard.externalHost}:${config.dashboard.port}/#/v3/${encodeURIComponent(runId)}`;
|
|
22
|
+
}
|
|
23
|
+
export function buildV3GateCard(input) {
|
|
24
|
+
const nonce = input.nonce ?? v3GateCardNonce(input.runId, input.waitId);
|
|
25
|
+
const webDetailUrl = input.webDetailUrl ?? v3RunDetailUrl(input.runId);
|
|
26
|
+
const promptMax = input.promptMaxChars ?? DEFAULT_PROMPT_MAX_CHARS;
|
|
27
|
+
const prompt = truncate(input.prompt, promptMax);
|
|
28
|
+
const resolution = input.resolution;
|
|
29
|
+
const options = input.options ?? [...DEFAULT_HUMAN_GATE_OPTIONS];
|
|
30
|
+
const approveOptions = input.approveOptions ?? (options.includes('approve') ? ['approve'] : [options[0]]);
|
|
31
|
+
const title = resolution
|
|
32
|
+
? `${resolutionPrefix(resolution.kind)}:${titleText(input.nodeId)}`
|
|
33
|
+
: `需要审批:${titleText(input.nodeId)}`;
|
|
34
|
+
const template = resolution ? (resolution.kind === 'approved' ? 'green' : 'red') : 'blue';
|
|
35
|
+
const elements = [
|
|
36
|
+
{
|
|
37
|
+
tag: 'div',
|
|
38
|
+
fields: [
|
|
39
|
+
{ is_short: true, text: { tag: 'lark_md', content: `**Run**\n${escapeMd(short(input.runId, 24))}` } },
|
|
40
|
+
{ is_short: true, text: { tag: 'lark_md', content: `**节点**\n${escapeMd(input.nodeId)}` } },
|
|
41
|
+
],
|
|
42
|
+
},
|
|
43
|
+
{ tag: 'hr' },
|
|
44
|
+
{
|
|
45
|
+
tag: 'div',
|
|
46
|
+
text: { tag: 'lark_md', content: `**审批内容**\n${escapeMd(prompt)}` },
|
|
47
|
+
},
|
|
48
|
+
];
|
|
49
|
+
if (resolution) {
|
|
50
|
+
elements.push({ tag: 'hr' });
|
|
51
|
+
elements.push({
|
|
52
|
+
tag: 'div',
|
|
53
|
+
text: {
|
|
54
|
+
tag: 'lark_md',
|
|
55
|
+
content: (resolution.kind === 'approved' ? '✅ 已通过' : '❌ 已拒绝') +
|
|
56
|
+
(resolution.selected ? ` · ${escapeMd(short(resolution.selected, 20))}` : '') +
|
|
57
|
+
(resolution.by ? ` · by ${escapeMd(short(resolution.by, 20))}` : ''),
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
elements.push({
|
|
63
|
+
tag: 'action',
|
|
64
|
+
actions: options.map((opt) => optionButton(opt, approveOptions, input, nonce)),
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
elements.push({
|
|
68
|
+
tag: 'action',
|
|
69
|
+
actions: [
|
|
70
|
+
{
|
|
71
|
+
tag: 'button',
|
|
72
|
+
text: { tag: 'plain_text', content: 'Web 详情' },
|
|
73
|
+
type: 'default',
|
|
74
|
+
multi_url: {
|
|
75
|
+
url: webDetailUrl, pc_url: webDetailUrl, android_url: webDetailUrl, ios_url: webDetailUrl,
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
],
|
|
79
|
+
});
|
|
80
|
+
return JSON.stringify({
|
|
81
|
+
config: { wide_screen_mode: true },
|
|
82
|
+
header: { template, title: { tag: 'plain_text', content: title } },
|
|
83
|
+
elements,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
function actionValue(action, runId, waitId, nodeId, nonce, selected) {
|
|
87
|
+
return { action, runId, waitId, nodeId, nonce, selected };
|
|
88
|
+
}
|
|
89
|
+
function optionButton(selected, approveOptions, input, nonce) {
|
|
90
|
+
const approved = approveOptions.includes(selected);
|
|
91
|
+
const label = selected === 'approve' ? '✅ 通过'
|
|
92
|
+
: selected === 'reject' ? '❌ 拒绝'
|
|
93
|
+
: selected;
|
|
94
|
+
return {
|
|
95
|
+
tag: 'button',
|
|
96
|
+
text: { tag: 'plain_text', content: label },
|
|
97
|
+
type: approved ? 'primary' : 'danger',
|
|
98
|
+
value: actionValue(approved ? V3_GATE_APPROVE_ACTION : V3_GATE_REJECT_ACTION, input.runId, input.waitId, input.nodeId, nonce, selected),
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
function resolutionPrefix(kind) {
|
|
102
|
+
return kind === 'approved' ? '已通过' : '已拒绝';
|
|
103
|
+
}
|
|
104
|
+
function titleText(nodeId) {
|
|
105
|
+
return `humanGate · ${nodeId}`;
|
|
106
|
+
}
|
|
107
|
+
function truncate(s, max) {
|
|
108
|
+
if (s.length <= max)
|
|
109
|
+
return s;
|
|
110
|
+
return `${s.slice(0, max)}…(截断,完整见 Web 详情)`;
|
|
111
|
+
}
|
|
112
|
+
function short(s, max) {
|
|
113
|
+
return s.length <= max ? s : `${s.slice(0, max)}…`;
|
|
114
|
+
}
|
|
115
|
+
/** 转义 lark_md 里会被解析的字符,防 prompt 注入破坏卡片结构。 */
|
|
116
|
+
function escapeMd(s) {
|
|
117
|
+
return s.replace(/[\\*_~`\[\]]/g, (c) => `\\${c}`);
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=v3-gate-card.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"v3-gate-card.js","sourceRoot":"","sources":["../../../src/im/lark/v3-gate-card.ts"],"names":[],"mappings":"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"}
|