harness-engineering-agent 0.3.26 → 0.3.28
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/README.md +11 -0
- package/dist/agent/harness-role-capability-directory-data.d.ts.map +1 -1
- package/dist/agent/harness-role-capability-directory-data.js +2 -0
- package/dist/agent/harness-role-capability-directory-data.js.map +1 -1
- package/dist/controller/contracts.d.ts +2 -0
- package/dist/controller/contracts.d.ts.map +1 -1
- package/dist/controller/contracts.js.map +1 -1
- package/dist/controller/failure-classification.d.ts +5 -0
- package/dist/controller/failure-classification.d.ts.map +1 -0
- package/dist/controller/failure-classification.js +6 -0
- package/dist/controller/failure-classification.js.map +1 -0
- package/dist/controller/index.d.ts +5 -0
- package/dist/controller/index.d.ts.map +1 -1
- package/dist/controller/index.js +5 -0
- package/dist/controller/index.js.map +1 -1
- package/dist/controller/route-resolver.d.ts.map +1 -1
- package/dist/controller/route-resolver.js +19 -8
- package/dist/controller/route-resolver.js.map +1 -1
- package/dist/controller/run-controller.d.ts.map +1 -1
- package/dist/controller/run-controller.js +80 -8
- package/dist/controller/run-controller.js.map +1 -1
- package/dist/controller/run-error-finalizer.d.ts +15 -0
- package/dist/controller/run-error-finalizer.d.ts.map +1 -1
- package/dist/controller/run-error-finalizer.js +103 -4
- package/dist/controller/run-error-finalizer.js.map +1 -1
- package/dist/controller/run-lease.d.ts +26 -0
- package/dist/controller/run-lease.d.ts.map +1 -0
- package/dist/controller/run-lease.js +63 -0
- package/dist/controller/run-lease.js.map +1 -0
- package/dist/controller/run-stage-projection.d.ts +51 -0
- package/dist/controller/run-stage-projection.d.ts.map +1 -0
- package/dist/controller/run-stage-projection.js +149 -0
- package/dist/controller/run-stage-projection.js.map +1 -0
- package/dist/controller/run-watchdog.d.ts +36 -0
- package/dist/controller/run-watchdog.d.ts.map +1 -0
- package/dist/controller/run-watchdog.js +124 -0
- package/dist/controller/run-watchdog.js.map +1 -0
- package/dist/controller/task-executor.d.ts.map +1 -1
- package/dist/controller/task-executor.js +22 -0
- package/dist/controller/task-executor.js.map +1 -1
- package/dist/domain/failure.d.ts +100 -0
- package/dist/domain/failure.d.ts.map +1 -1
- package/dist/domain/failure.js +9 -0
- package/dist/domain/failure.js.map +1 -1
- package/dist/domain/report.d.ts +200 -0
- package/dist/domain/report.d.ts.map +1 -1
- package/dist/domain/run.d.ts +200 -0
- package/dist/domain/run.d.ts.map +1 -1
- package/dist/plugin/create-harness-plugin.d.ts.map +1 -1
- package/dist/plugin/create-harness-plugin.js +35 -6
- package/dist/plugin/create-harness-plugin.js.map +1 -1
- package/dist/plugin/harness-chat-hook.d.ts +2 -1
- package/dist/plugin/harness-chat-hook.d.ts.map +1 -1
- package/dist/plugin/harness-chat-hook.js +32 -17
- package/dist/plugin/harness-chat-hook.js.map +1 -1
- package/dist/plugin/harness-chat-protocol.d.ts +2 -1
- package/dist/plugin/harness-chat-protocol.d.ts.map +1 -1
- package/dist/plugin/harness-chat-protocol.js +9 -0
- package/dist/plugin/harness-chat-protocol.js.map +1 -1
- package/dist/plugin/harness-coordinator.d.ts +5 -0
- package/dist/plugin/harness-coordinator.d.ts.map +1 -1
- package/dist/plugin/harness-coordinator.js +84 -33
- package/dist/plugin/harness-coordinator.js.map +1 -1
- package/dist/plugin/harness-delivery-envelope.d.ts +19 -0
- package/dist/plugin/harness-delivery-envelope.d.ts.map +1 -0
- package/dist/plugin/harness-delivery-envelope.js +105 -0
- package/dist/plugin/harness-delivery-envelope.js.map +1 -0
- package/dist/plugin/harness-escalate-tool.d.ts +2 -1
- package/dist/plugin/harness-escalate-tool.d.ts.map +1 -1
- package/dist/plugin/harness-escalate-tool.js.map +1 -1
- package/dist/plugin/harness-plugin-runtime.d.ts +1 -0
- package/dist/plugin/harness-plugin-runtime.d.ts.map +1 -1
- package/dist/plugin/harness-plugin-runtime.js +1 -0
- package/dist/plugin/harness-plugin-runtime.js.map +1 -1
- package/dist/plugin/harness-plugin-scheduler.d.ts.map +1 -1
- package/dist/plugin/harness-plugin-scheduler.js +12 -12
- package/dist/plugin/harness-plugin-scheduler.js.map +1 -1
- package/dist/plugin/harness-request-router.d.ts.map +1 -1
- package/dist/plugin/harness-request-router.js +25 -0
- package/dist/plugin/harness-request-router.js.map +1 -1
- package/dist/plugin/harness-run-status-tool.d.ts +7 -0
- package/dist/plugin/harness-run-status-tool.d.ts.map +1 -0
- package/dist/plugin/harness-run-status-tool.js +33 -0
- package/dist/plugin/harness-run-status-tool.js.map +1 -0
- package/dist/store/filesystem-run-store.js +5 -0
- package/dist/store/filesystem-run-store.js.map +1 -1
- package/dist/store/run-event.d.ts +200 -0
- package/dist/store/run-event.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -5,6 +5,21 @@ export declare class PlanningBlockedError extends Error {
|
|
|
5
5
|
readonly name = "PlanningBlockedError";
|
|
6
6
|
constructor(run: Run);
|
|
7
7
|
}
|
|
8
|
+
export type RunErrorCode = "PLANNER_CONTRACT_GRAPH_REJECTED" | "PLANNER_CONTRACT_OUTPUT_INVALID" | "PLANNER_CONTRACT_READ_ONLY" | "AGENT_RUN_FAILED" | "BUDGET_EXHAUSTED" | "UNKNOWN";
|
|
9
|
+
/** 错误码推导链:显式 errorCode → 信号 → 退出码 → 兜底 UNKNOWN。结果保证非空。 */
|
|
10
|
+
export declare const deriveRunErrorCode: (error: unknown) => string;
|
|
11
|
+
/** 失败发生前的最后持久化阶段标签(尽力推导,永不抛错)。 */
|
|
12
|
+
export declare const lastPersistedStageOf: (run: Run | undefined) => string;
|
|
13
|
+
export type FailureRecoveryGuidance = {
|
|
14
|
+
readonly resumable: boolean;
|
|
15
|
+
readonly action: "resume" | "manual";
|
|
16
|
+
readonly preconditions: readonly string[];
|
|
17
|
+
};
|
|
18
|
+
/** 结构化恢复指引:resume 前置条件;自由文本(recoveryPlan/reason)仅作为补充字段。 */
|
|
19
|
+
export declare const structuredRecoveryGuidance: (input: {
|
|
20
|
+
readonly run?: Run;
|
|
21
|
+
readonly errorCode: string;
|
|
22
|
+
}) => FailureRecoveryGuidance;
|
|
8
23
|
export declare const finalizeAdvanceError: (input: {
|
|
9
24
|
readonly runId: Run["runId"];
|
|
10
25
|
readonly error: unknown;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-error-finalizer.d.ts","sourceRoot":"","sources":["../../src/controller/run-error-finalizer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,GAAG,EAAa,MAAM,oBAAoB,CAAA;AASxD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAS1D,qBAAa,oBAAqB,SAAQ,KAAK;IAGjC,QAAQ,CAAC,GAAG,EAAE,GAAG;IAF7B,QAAQ,CAAC,IAAI,0BAAyB;gBAEjB,GAAG,EAAE,GAAG;CAG9B;AAED,eAAO,MAAM,oBAAoB,GAAU,OAAO;IAChD,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC,OAAO,CAAC,CAAA;IAC5B,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;IACvB,QAAQ,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,GAAG,CAAC,OAAO,CAAC,KAAK,OAAO,CAAC,GAAG,CAAC,CAAA;IACvD,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAA;CAChC,KAAG,OAAO,CAAC,GAAG,
|
|
1
|
+
{"version":3,"file":"run-error-finalizer.d.ts","sourceRoot":"","sources":["../../src/controller/run-error-finalizer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,GAAG,EAAa,MAAM,oBAAoB,CAAA;AASxD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAS1D,qBAAa,oBAAqB,SAAQ,KAAK;IAGjC,QAAQ,CAAC,GAAG,EAAE,GAAG;IAF7B,QAAQ,CAAC,IAAI,0BAAyB;gBAEjB,GAAG,EAAE,GAAG;CAG9B;AAED,MAAM,MAAM,YAAY,GACpB,iCAAiC,GACjC,iCAAiC,GACjC,4BAA4B,GAC5B,kBAAkB,GAClB,kBAAkB,GAClB,SAAS,CAAA;AAEb,0DAA0D;AAC1D,eAAO,MAAM,kBAAkB,GAAI,OAAO,OAAO,KAAG,MAgCnD,CAAA;AAaD,kCAAkC;AAClC,eAAO,MAAM,oBAAoB,GAAI,KAAK,GAAG,GAAG,SAAS,KAAG,MAI3D,CAAA;AAED,MAAM,MAAM,uBAAuB,GAAG;IACpC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAA;IAC3B,QAAQ,CAAC,MAAM,EAAE,QAAQ,GAAG,QAAQ,CAAA;IACpC,QAAQ,CAAC,aAAa,EAAE,SAAS,MAAM,EAAE,CAAA;CAC1C,CAAA;AAED,4DAA4D;AAC5D,eAAO,MAAM,0BAA0B,GAAI,OAAO;IAChD,QAAQ,CAAC,GAAG,CAAC,EAAE,GAAG,CAAA;IAClB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAC3B,KAAG,uBA8BH,CAAA;AAED,eAAO,MAAM,oBAAoB,GAAU,OAAO;IAChD,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC,OAAO,CAAC,CAAA;IAC5B,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;IACvB,QAAQ,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,GAAG,CAAC,OAAO,CAAC,KAAK,OAAO,CAAC,GAAG,CAAC,CAAA;IACvD,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAA;CAChC,KAAG,OAAO,CAAC,GAAG,CAwGd,CAAA"}
|
|
@@ -9,6 +9,88 @@ export class PlanningBlockedError extends Error {
|
|
|
9
9
|
this.run = run;
|
|
10
10
|
}
|
|
11
11
|
}
|
|
12
|
+
/** 错误码推导链:显式 errorCode → 信号 → 退出码 → 兜底 UNKNOWN。结果保证非空。 */
|
|
13
|
+
export const deriveRunErrorCode = (error) => {
|
|
14
|
+
if (typeof error === "object" && error !== null) {
|
|
15
|
+
const explicit = Reflect.get(error, "errorCode");
|
|
16
|
+
if (typeof explicit === "string" && explicit.trim().length > 0) {
|
|
17
|
+
return explicit;
|
|
18
|
+
}
|
|
19
|
+
const signal = Reflect.get(error, "signal") ?? Reflect.get(Reflect.get(error, "cause") ?? {}, "signal");
|
|
20
|
+
if (typeof signal === "string" && signal.trim().length > 0) {
|
|
21
|
+
return `SIGNAL_${signal.toUpperCase()}`;
|
|
22
|
+
}
|
|
23
|
+
const exitCode = Reflect.get(error, "exitCode") ?? Reflect.get(Reflect.get(error, "cause") ?? {}, "exitCode");
|
|
24
|
+
if (typeof exitCode === "number" && Number.isFinite(exitCode)) {
|
|
25
|
+
return `EXIT_${exitCode}`;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
if (error instanceof GraphValidationError) {
|
|
29
|
+
return isReadOnlyContractError(error)
|
|
30
|
+
? "PLANNER_CONTRACT_READ_ONLY"
|
|
31
|
+
: "PLANNER_CONTRACT_GRAPH_REJECTED";
|
|
32
|
+
}
|
|
33
|
+
if (error instanceof AgentOutputParseError) {
|
|
34
|
+
return `PLANNER_CONTRACT_OUTPUT_${error.reasonCode.toUpperCase()}`;
|
|
35
|
+
}
|
|
36
|
+
if (error instanceof AgentRunFailedError) {
|
|
37
|
+
return "AGENT_RUN_FAILED";
|
|
38
|
+
}
|
|
39
|
+
if (error instanceof RunBudgetExceededError) {
|
|
40
|
+
return `BUDGET_${error.budget.toUpperCase()}`;
|
|
41
|
+
}
|
|
42
|
+
return "UNKNOWN";
|
|
43
|
+
};
|
|
44
|
+
const STAGE_BY_RUN_STATUS = {
|
|
45
|
+
created: "intake",
|
|
46
|
+
analyzing: "intake",
|
|
47
|
+
planning: "planner",
|
|
48
|
+
plan_ready: "planner",
|
|
49
|
+
executing: "worker",
|
|
50
|
+
verifying: "verifier",
|
|
51
|
+
paused: "worker",
|
|
52
|
+
completed: "acceptance",
|
|
53
|
+
};
|
|
54
|
+
/** 失败发生前的最后持久化阶段标签(尽力推导,永不抛错)。 */
|
|
55
|
+
export const lastPersistedStageOf = (run) => {
|
|
56
|
+
if (run === undefined)
|
|
57
|
+
return "unknown";
|
|
58
|
+
if (!("taskGraph" in run))
|
|
59
|
+
return "planner";
|
|
60
|
+
return STAGE_BY_RUN_STATUS[run.status] ?? "unknown";
|
|
61
|
+
};
|
|
62
|
+
/** 结构化恢复指引:resume 前置条件;自由文本(recoveryPlan/reason)仅作为补充字段。 */
|
|
63
|
+
export const structuredRecoveryGuidance = (input) => {
|
|
64
|
+
if (input.errorCode.startsWith("BUDGET_")) {
|
|
65
|
+
return {
|
|
66
|
+
resumable: true,
|
|
67
|
+
action: "manual",
|
|
68
|
+
preconditions: ["扩大对应预算或确认预算耗尽可接受后,再执行 resume"],
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
if (input.errorCode.startsWith("PLANNER_CONTRACT")) {
|
|
72
|
+
return {
|
|
73
|
+
resumable: true,
|
|
74
|
+
action: "resume",
|
|
75
|
+
preconditions: [
|
|
76
|
+
"确认 Planner 输出契约与阶段契约对齐",
|
|
77
|
+
"确认输入证据完整后执行 resume <runId>",
|
|
78
|
+
],
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
if (input.errorCode.startsWith("SIGNAL_") || input.errorCode === "UNKNOWN") {
|
|
82
|
+
return {
|
|
83
|
+
resumable: true,
|
|
84
|
+
action: "resume",
|
|
85
|
+
preconditions: ["确认运行环境可用后执行 resume <runId>,将从最后持久化阶段恢复"],
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
return {
|
|
89
|
+
resumable: true,
|
|
90
|
+
action: "resume",
|
|
91
|
+
preconditions: ["执行 resume <runId> 前确认失败原因已修复"],
|
|
92
|
+
};
|
|
93
|
+
};
|
|
12
94
|
export const finalizeAdvanceError = async (input) => {
|
|
13
95
|
const { runId, error, loadRun, writer } = input;
|
|
14
96
|
if (error instanceof GraphValidationError ||
|
|
@@ -21,8 +103,12 @@ export const finalizeAdvanceError = async (input) => {
|
|
|
21
103
|
return error.run;
|
|
22
104
|
}
|
|
23
105
|
const planning = withStatus(latest, "planning");
|
|
24
|
-
const
|
|
25
|
-
(error instanceof GraphValidationError && isReadOnlyContractError(error))
|
|
106
|
+
const isContractFailure = error instanceof AgentOutputParseError ||
|
|
107
|
+
(error instanceof GraphValidationError && isReadOnlyContractError(error));
|
|
108
|
+
const errorCode = deriveRunErrorCode(error);
|
|
109
|
+
const lastPersistedStage = lastPersistedStageOf(planning);
|
|
110
|
+
const recovery = structuredRecoveryGuidance({ run: planning, errorCode });
|
|
111
|
+
const planningWithFailure = isContractFailure
|
|
26
112
|
? RunSchema.parse({
|
|
27
113
|
...planning,
|
|
28
114
|
failures: [
|
|
@@ -40,18 +126,31 @@ export const finalizeAdvanceError = async (input) => {
|
|
|
40
126
|
recoveryPlan: "执行 resume <runId> 重试;若仍失败,检查 Planner 输出契约和输入证据。",
|
|
41
127
|
confidence: 1,
|
|
42
128
|
relatedEvidenceIds: [],
|
|
129
|
+
errorCode,
|
|
130
|
+
lastPersistedStage,
|
|
131
|
+
recoveryGuidance: recovery,
|
|
43
132
|
},
|
|
44
133
|
],
|
|
45
134
|
})
|
|
46
135
|
: planning;
|
|
136
|
+
const isBudgetExhausted = error instanceof RunBudgetExceededError;
|
|
137
|
+
// paused 是计划后状态:规划阶段(无 taskGraph)预算耗尽退化为 blocked,避免非法状态迁移
|
|
138
|
+
const terminalStatus = isBudgetExhausted
|
|
139
|
+
? "taskGraph" in planningWithFailure
|
|
140
|
+
? "paused"
|
|
141
|
+
: "blocked"
|
|
142
|
+
: "failed";
|
|
47
143
|
const blocked = withStatus(withGovernance(planningWithFailure, {
|
|
48
144
|
...planningWithFailure.governance,
|
|
49
145
|
blockingQuestionId: error instanceof RunBudgetExceededError
|
|
50
146
|
? createBlockedQuestionId(planningWithFailure)
|
|
51
147
|
: null,
|
|
52
|
-
}),
|
|
53
|
-
await writer.persist(blocked, writer.createEvent(runId,
|
|
148
|
+
}), terminalStatus);
|
|
149
|
+
await writer.persist(blocked, writer.createEvent(runId, isBudgetExhausted ? "run.paused" : "run.failed", {
|
|
54
150
|
reason: error.message,
|
|
151
|
+
errorCode,
|
|
152
|
+
lastPersistedStage,
|
|
153
|
+
recovery,
|
|
55
154
|
...(error instanceof RunBudgetExceededError
|
|
56
155
|
? {
|
|
57
156
|
budget: error.budget,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-error-finalizer.js","sourceRoot":"","sources":["../../src/controller/run-error-finalizer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,SAAS,EAAE,MAAM,oBAAoB,CAAA;AACxD,OAAO,EACL,qBAAqB,EACrB,mBAAmB,EACnB,oBAAoB,EACpB,uBAAuB,EACvB,oBAAoB,EACpB,cAAc,GACf,MAAM,aAAa,CAAA;AAEpB,OAAO,EACL,uBAAuB,EACvB,sBAAsB,EACtB,SAAS,EACT,cAAc,EACd,UAAU,GACX,MAAM,gBAAgB,CAAA;AAEvB,MAAM,OAAO,oBAAqB,SAAQ,KAAK;IAGxB;IAFZ,IAAI,GAAG,sBAAsB,CAAA;IAEtC,YAAqB,GAAQ;QAC3B,KAAK,CAAC,qBAAqB,GAAG,CAAC,MAAM,EAAE,CAAC,CAAA;QADrB,QAAG,GAAH,GAAG,CAAK;IAE7B,CAAC;CACF;AAED,MAAM,CAAC,MAAM,oBAAoB,GAAG,KAAK,EAAE,KAK1C,EAAgB,EAAE;IACjB,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,KAAK,CAAA;IAE/C,IACE,KAAK,YAAY,oBAAoB;QACrC,KAAK,YAAY,oBAAoB;QACrC,KAAK,YAAY,mBAAmB;QACpC,KAAK,YAAY,qBAAqB;QACtC,KAAK,YAAY,sBAAsB,EACvC,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,CAAA;QACnC,IAAI,KAAK,YAAY,oBAAoB,EAAE,CAAC;YAC1C,OAAO,KAAK,CAAC,GAAG,CAAA;QAClB,CAAC;QACD,MAAM,QAAQ,GAAG,UAAU,CAAC,MAAM,EAAE,UAAU,CAAC,CAAA;QAC/C,MAAM,
|
|
1
|
+
{"version":3,"file":"run-error-finalizer.js","sourceRoot":"","sources":["../../src/controller/run-error-finalizer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { RunId } from "../domain/index.js";
|
|
2
|
+
import type { RunStore } from "../store/index.js";
|
|
3
|
+
export type RunLeaseConfig = {
|
|
4
|
+
/** 租约 TTL(毫秒);默认与心跳周期绑定(心跳周期 × 3) */
|
|
5
|
+
readonly ttlMs: number;
|
|
6
|
+
};
|
|
7
|
+
export type RunLeaseAcquireResult = {
|
|
8
|
+
readonly acquired: true;
|
|
9
|
+
readonly holderId: string;
|
|
10
|
+
readonly expiresAt?: string | undefined;
|
|
11
|
+
} | {
|
|
12
|
+
readonly acquired: false;
|
|
13
|
+
readonly holderId?: string | undefined;
|
|
14
|
+
readonly expiresAt?: string | undefined;
|
|
15
|
+
};
|
|
16
|
+
export type RunLeaseManager = {
|
|
17
|
+
readonly acquire: (runId: RunId, holderId: string) => Promise<RunLeaseAcquireResult>;
|
|
18
|
+
readonly release: (runId: RunId, holderId: string) => Promise<void>;
|
|
19
|
+
};
|
|
20
|
+
export declare const createRunLeaseManager: (input: {
|
|
21
|
+
readonly store: RunStore;
|
|
22
|
+
readonly clock: () => Date;
|
|
23
|
+
readonly createEventId: (label: string) => string;
|
|
24
|
+
readonly config: RunLeaseConfig;
|
|
25
|
+
}) => RunLeaseManager;
|
|
26
|
+
//# sourceMappingURL=run-lease.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-lease.d.ts","sourceRoot":"","sources":["../../src/controller/run-lease.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAA;AAC/C,OAAO,KAAK,EAAY,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAE3D,MAAM,MAAM,cAAc,GAAG;IAC3B,qCAAqC;IACrC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CACvB,CAAA;AAED,MAAM,MAAM,qBAAqB,GAC7B;IACE,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAA;IACvB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CACxC,GACD;IACE,QAAQ,CAAC,QAAQ,EAAE,KAAK,CAAA;IACxB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACtC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CACxC,CAAA;AAEL,MAAM,MAAM,eAAe,GAAG;IAC5B,QAAQ,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,qBAAqB,CAAC,CAAA;IACpF,QAAQ,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CACpE,CAAA;AAED,eAAO,MAAM,qBAAqB,GAAI,OAAO;IAC3C,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAA;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,IAAI,CAAA;IAC1B,QAAQ,CAAC,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAA;IACjD,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAA;CAChC,KAAG,eAmEH,CAAA"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
export const createRunLeaseManager = (input) => {
|
|
3
|
+
const leaseEvent = (runId, type, payload) => ({
|
|
4
|
+
schemaVersion: "1.0.0",
|
|
5
|
+
eventId: input.createEventId(`${type}-${runId}`),
|
|
6
|
+
idempotencyKey: `${type}-${runId}-${input.clock().toISOString()}-${randomUUID().slice(0, 8)}`,
|
|
7
|
+
runId,
|
|
8
|
+
type,
|
|
9
|
+
timestamp: input.clock().toISOString(),
|
|
10
|
+
payload,
|
|
11
|
+
});
|
|
12
|
+
const readPayloadString = (event, key) => {
|
|
13
|
+
const payload = event.payload;
|
|
14
|
+
if (typeof payload !== "object" || payload === null || Array.isArray(payload))
|
|
15
|
+
return undefined;
|
|
16
|
+
const value = Reflect.get(payload, key);
|
|
17
|
+
return typeof value === "string" ? value : undefined;
|
|
18
|
+
};
|
|
19
|
+
const acquire = async (runId, holderId) => {
|
|
20
|
+
const events = await input.store.listEvents(runId);
|
|
21
|
+
const lastLeaseEvent = events
|
|
22
|
+
.filter((event) => event.type === "run.lease.acquired" || event.type === "run.lease.released")
|
|
23
|
+
.at(-1);
|
|
24
|
+
if (lastLeaseEvent?.type === "run.lease.acquired") {
|
|
25
|
+
const holder = readPayloadString(lastLeaseEvent, "holderId");
|
|
26
|
+
const expiresAt = readPayloadString(lastLeaseEvent, "expiresAt");
|
|
27
|
+
const expiresAtMs = expiresAt === undefined ? Number.NaN : new Date(expiresAt).getTime();
|
|
28
|
+
const expired = !Number.isFinite(expiresAtMs) || expiresAtMs <= input.clock().getTime();
|
|
29
|
+
if (!expired) {
|
|
30
|
+
if (holder === holderId) {
|
|
31
|
+
return { acquired: true, holderId, ...(expiresAt === undefined ? {} : { expiresAt }) };
|
|
32
|
+
}
|
|
33
|
+
return {
|
|
34
|
+
acquired: false,
|
|
35
|
+
...(holder === undefined ? {} : { holderId: holder }),
|
|
36
|
+
...(expiresAt === undefined ? {} : { expiresAt }),
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
// 租约超时可重获:重获前二次确认自上一次租约获取后没有任何新事件(含心跳),
|
|
40
|
+
// 避免夺取一个仍在推进的持有者的租约。
|
|
41
|
+
const acquiredIndex = events.findIndex((event) => event.eventId === lastLeaseEvent.eventId);
|
|
42
|
+
if (acquiredIndex >= 0 && acquiredIndex < events.length - 1) {
|
|
43
|
+
return { acquired: false, ...(holder === undefined ? {} : { holderId: holder }) };
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
const acquiredAt = input.clock().toISOString();
|
|
47
|
+
const expiresAt = new Date(input.clock().getTime() + input.config.ttlMs).toISOString();
|
|
48
|
+
await input.store.appendEvents(runId, [
|
|
49
|
+
leaseEvent(runId, "run.lease.acquired", { holderId, acquiredAt, expiresAt }),
|
|
50
|
+
]);
|
|
51
|
+
return { acquired: true, holderId, expiresAt };
|
|
52
|
+
};
|
|
53
|
+
const release = async (runId, holderId) => {
|
|
54
|
+
await input.store.appendEvents(runId, [
|
|
55
|
+
leaseEvent(runId, "run.lease.released", {
|
|
56
|
+
holderId,
|
|
57
|
+
releasedAt: input.clock().toISOString(),
|
|
58
|
+
}),
|
|
59
|
+
]);
|
|
60
|
+
};
|
|
61
|
+
return { acquire, release };
|
|
62
|
+
};
|
|
63
|
+
//# sourceMappingURL=run-lease.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-lease.js","sourceRoot":"","sources":["../../src/controller/run-lease.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { Run } from "../domain/index.js";
|
|
2
|
+
import type { RunEvent, RunStore } from "../store/index.js";
|
|
3
|
+
export type RunStageEntry = {
|
|
4
|
+
readonly stage: string;
|
|
5
|
+
readonly enteredAt: string;
|
|
6
|
+
readonly exitedAt?: string;
|
|
7
|
+
readonly taskId?: string;
|
|
8
|
+
readonly taskOutcome?: "started" | "completed" | "failed";
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* 将 run store 事件流折叠为带时间戳的阶段/任务投影序列。
|
|
12
|
+
* 任务级 started/completed/failed 在投影中以 taskOutcome 区分;心跳与租约事件不进入投影。
|
|
13
|
+
*/
|
|
14
|
+
export declare const projectRunStages: (events: readonly RunEvent[]) => readonly RunStageEntry[];
|
|
15
|
+
export declare const latestEventTimestamp: (events: readonly RunEvent[]) => string | undefined;
|
|
16
|
+
export declare const currentTaskIdFromEvents: (events: readonly RunEvent[]) => string | undefined;
|
|
17
|
+
export type RunStatusSnapshot = {
|
|
18
|
+
readonly status: Run["status"];
|
|
19
|
+
readonly phase: string;
|
|
20
|
+
readonly currentTaskId?: string | undefined;
|
|
21
|
+
readonly budgets: Run["budgets"];
|
|
22
|
+
readonly lastEventAt?: string | undefined;
|
|
23
|
+
readonly blockers: readonly string[];
|
|
24
|
+
readonly routingDecision?: {
|
|
25
|
+
readonly scheduling: string;
|
|
26
|
+
readonly governance: string;
|
|
27
|
+
readonly reasons: readonly string[];
|
|
28
|
+
} | undefined;
|
|
29
|
+
readonly stages: readonly RunStageEntry[];
|
|
30
|
+
};
|
|
31
|
+
/** 从已加载的 run 状态与事件流构造 run_status 查询快照。 */
|
|
32
|
+
export declare const deriveRunStatusSnapshot: (run: Run, events: readonly RunEvent[]) => RunStatusSnapshot;
|
|
33
|
+
export type RunStatusQuery = {
|
|
34
|
+
readonly ok: true;
|
|
35
|
+
readonly runId: string;
|
|
36
|
+
readonly snapshot: RunStatusSnapshot;
|
|
37
|
+
} | {
|
|
38
|
+
readonly ok: false;
|
|
39
|
+
readonly runId: string;
|
|
40
|
+
readonly error: {
|
|
41
|
+
readonly code: "run-not-found" | "store-error";
|
|
42
|
+
readonly message: string;
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
export declare const createRunStatusQuery: (input: {
|
|
46
|
+
readonly store: RunStore;
|
|
47
|
+
}) => {
|
|
48
|
+
query: (runId: string) => Promise<RunStatusQuery>;
|
|
49
|
+
};
|
|
50
|
+
export declare const isMissingRunStateError: (error: unknown, runId: string) => boolean;
|
|
51
|
+
//# sourceMappingURL=run-stage-projection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-stage-projection.d.ts","sourceRoot":"","sources":["../../src/controller/run-stage-projection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAA;AAC7C,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAE3D,MAAM,MAAM,aAAa,GAAG;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,GAAG,WAAW,GAAG,QAAQ,CAAA;CAC1D,CAAA;AA+BD;;;GAGG;AACH,eAAO,MAAM,gBAAgB,GAAI,QAAQ,SAAS,QAAQ,EAAE,KAAG,SAAS,aAAa,EA+BpF,CAAA;AAED,eAAO,MAAM,oBAAoB,GAAI,QAAQ,SAAS,QAAQ,EAAE,KAAG,MAAM,GAAG,SAClD,CAAA;AAE1B,eAAO,MAAM,uBAAuB,GAAI,QAAQ,SAAS,QAAQ,EAAE,KAAG,MAAM,GAAG,SAe9E,CAAA;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,CAAC,MAAM,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAA;IAC9B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3C,QAAQ,CAAC,OAAO,EAAE,GAAG,CAAC,SAAS,CAAC,CAAA;IAChC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACzC,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAA;IACpC,QAAQ,CAAC,eAAe,CAAC,EACrB;QACE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;QAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;QAC3B,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAA;KACpC,GACD,SAAS,CAAA;IACb,QAAQ,CAAC,MAAM,EAAE,SAAS,aAAa,EAAE,CAAA;CAC1C,CAAA;AAED,0CAA0C;AAC1C,eAAO,MAAM,uBAAuB,GAClC,KAAK,GAAG,EACR,QAAQ,SAAS,QAAQ,EAAE,KAC1B,iBAmCF,CAAA;AAED,MAAM,MAAM,cAAc,GACtB;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,CAAA;CAAE,GACnF;IACE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAA;IAClB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,KAAK,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,eAAe,GAAG,aAAa,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAA;CAC7F,CAAA;AAEL,eAAO,MAAM,oBAAoB,GAAI,OAAO;IAAE,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAA;CAAE;mBAC1C,MAAM,KAAG,OAAO,CAAC,cAAc,CAAC;CAoB7D,CAAA;AAED,eAAO,MAAM,sBAAsB,GAAI,OAAO,OAAO,EAAE,OAAO,MAAM,KAAG,OAatE,CAAA"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
const HEARTBEAT_AND_LEASE_EVENT_PREFIXES = ["run.heartbeat", "run.lease."];
|
|
2
|
+
const RUN_STAGE_EVENTS = new Set([
|
|
3
|
+
"run.created",
|
|
4
|
+
"run.planning",
|
|
5
|
+
"run.executing",
|
|
6
|
+
"run.paused",
|
|
7
|
+
"run.failed",
|
|
8
|
+
"run.completed",
|
|
9
|
+
"run.cancelled",
|
|
10
|
+
]);
|
|
11
|
+
const TASK_OUTCOME_BY_EVENT = {
|
|
12
|
+
"task.started": "started",
|
|
13
|
+
"task.completed": "completed",
|
|
14
|
+
"task.failed": "failed",
|
|
15
|
+
};
|
|
16
|
+
const isInternalTrackingEvent = (type) => HEARTBEAT_AND_LEASE_EVENT_PREFIXES.some((prefix) => type.startsWith(prefix));
|
|
17
|
+
const readPayloadString = (payload, key) => {
|
|
18
|
+
if (typeof payload !== "object" || payload === null || Array.isArray(payload)) {
|
|
19
|
+
return undefined;
|
|
20
|
+
}
|
|
21
|
+
const value = Reflect.get(payload, key);
|
|
22
|
+
return typeof value === "string" ? value : undefined;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* 将 run store 事件流折叠为带时间戳的阶段/任务投影序列。
|
|
26
|
+
* 任务级 started/completed/failed 在投影中以 taskOutcome 区分;心跳与租约事件不进入投影。
|
|
27
|
+
*/
|
|
28
|
+
export const projectRunStages = (events) => {
|
|
29
|
+
const stages = [];
|
|
30
|
+
let openRunStage;
|
|
31
|
+
const closeOpenRunStage = (exitedAt) => {
|
|
32
|
+
if (openRunStage === undefined)
|
|
33
|
+
return;
|
|
34
|
+
stages.push({ ...openRunStage, exitedAt });
|
|
35
|
+
openRunStage = undefined;
|
|
36
|
+
};
|
|
37
|
+
for (const event of events) {
|
|
38
|
+
if (isInternalTrackingEvent(event.type))
|
|
39
|
+
continue;
|
|
40
|
+
const taskOutcome = TASK_OUTCOME_BY_EVENT[event.type];
|
|
41
|
+
const taskId = readPayloadString(event.payload, "taskId");
|
|
42
|
+
if (taskOutcome !== undefined && taskId !== undefined) {
|
|
43
|
+
closeOpenRunStage(event.timestamp);
|
|
44
|
+
stages.push({
|
|
45
|
+
stage: event.type,
|
|
46
|
+
enteredAt: event.timestamp,
|
|
47
|
+
taskId,
|
|
48
|
+
taskOutcome,
|
|
49
|
+
});
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
if (RUN_STAGE_EVENTS.has(event.type)) {
|
|
53
|
+
closeOpenRunStage(event.timestamp);
|
|
54
|
+
openRunStage = { stage: event.type, enteredAt: event.timestamp };
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (openRunStage !== undefined)
|
|
58
|
+
stages.push(openRunStage);
|
|
59
|
+
return stages;
|
|
60
|
+
};
|
|
61
|
+
export const latestEventTimestamp = (events) => events.at(-1)?.timestamp;
|
|
62
|
+
export const currentTaskIdFromEvents = (events) => {
|
|
63
|
+
for (let index = events.length - 1; index >= 0; index -= 1) {
|
|
64
|
+
const event = events[index];
|
|
65
|
+
if (event === undefined)
|
|
66
|
+
continue;
|
|
67
|
+
if (event.type !== "task.started" &&
|
|
68
|
+
event.type !== "task.completed" &&
|
|
69
|
+
event.type !== "task.failed") {
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
if (event.type !== "task.started")
|
|
73
|
+
return undefined;
|
|
74
|
+
return readPayloadString(event.payload, "taskId");
|
|
75
|
+
}
|
|
76
|
+
return undefined;
|
|
77
|
+
};
|
|
78
|
+
/** 从已加载的 run 状态与事件流构造 run_status 查询快照。 */
|
|
79
|
+
export const deriveRunStatusSnapshot = (run, events) => {
|
|
80
|
+
const blockers = [];
|
|
81
|
+
if (run.governance.blockingQuestionId !== null) {
|
|
82
|
+
blockers.push(`blocking-question:${run.governance.blockingQuestionId}`);
|
|
83
|
+
}
|
|
84
|
+
if (run.governance.blockReason !== null) {
|
|
85
|
+
blockers.push(`block-reason:${run.governance.blockReason.kind}`);
|
|
86
|
+
}
|
|
87
|
+
if (run.blockingDetails !== undefined) {
|
|
88
|
+
blockers.push(`blocking-details:${run.blockingDetails.kind}`);
|
|
89
|
+
}
|
|
90
|
+
const lastFailure = run.failures.at(-1);
|
|
91
|
+
if (lastFailure !== undefined && run.status === "failed") {
|
|
92
|
+
blockers.push(`failure:${lastFailure.category}`);
|
|
93
|
+
}
|
|
94
|
+
return {
|
|
95
|
+
status: run.status,
|
|
96
|
+
phase: run.status,
|
|
97
|
+
...(run.status === "executing" || run.status === "verifying"
|
|
98
|
+
? { currentTaskId: currentTaskIdFromEvents(events) }
|
|
99
|
+
: {}),
|
|
100
|
+
budgets: run.budgets,
|
|
101
|
+
...(events.length === 0 ? {} : { lastEventAt: latestEventTimestamp(events) }),
|
|
102
|
+
blockers,
|
|
103
|
+
...(run.routingDecision === undefined
|
|
104
|
+
? {}
|
|
105
|
+
: {
|
|
106
|
+
routingDecision: {
|
|
107
|
+
scheduling: run.routingDecision.scheduling,
|
|
108
|
+
governance: run.routingDecision.governance,
|
|
109
|
+
reasons: run.routingDecision.reasons,
|
|
110
|
+
},
|
|
111
|
+
}),
|
|
112
|
+
stages: projectRunStages(events),
|
|
113
|
+
};
|
|
114
|
+
};
|
|
115
|
+
export const createRunStatusQuery = (input) => {
|
|
116
|
+
const query = async (runId) => {
|
|
117
|
+
let run;
|
|
118
|
+
try {
|
|
119
|
+
run = await input.store.loadState(runId);
|
|
120
|
+
}
|
|
121
|
+
catch (error) {
|
|
122
|
+
return {
|
|
123
|
+
ok: false,
|
|
124
|
+
runId,
|
|
125
|
+
error: isMissingRunStateError(error, runId)
|
|
126
|
+
? { code: "run-not-found", message: `run ${runId} 不存在` }
|
|
127
|
+
: {
|
|
128
|
+
code: "store-error",
|
|
129
|
+
message: error instanceof Error ? error.message : "unknown run store error",
|
|
130
|
+
},
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
const events = await input.store.listEvents(runId);
|
|
134
|
+
return { ok: true, runId, snapshot: deriveRunStatusSnapshot(run, events) };
|
|
135
|
+
};
|
|
136
|
+
return { query };
|
|
137
|
+
};
|
|
138
|
+
export const isMissingRunStateError = (error, runId) => {
|
|
139
|
+
if (error instanceof TypeError && error.message === `missing run ${runId}`)
|
|
140
|
+
return true;
|
|
141
|
+
if (error instanceof Error &&
|
|
142
|
+
"code" in error &&
|
|
143
|
+
error.code === "ENOENT") {
|
|
144
|
+
return true;
|
|
145
|
+
}
|
|
146
|
+
const cause = error?.cause;
|
|
147
|
+
return (cause instanceof Error && "code" in cause && cause.code === "ENOENT");
|
|
148
|
+
};
|
|
149
|
+
//# sourceMappingURL=run-stage-projection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-stage-projection.js","sourceRoot":"","sources":["../../src/controller/run-stage-projection.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { type Run } from "../domain/index.js";
|
|
2
|
+
import type { RunStore } from "../store/index.js";
|
|
3
|
+
export type RunWatchdogConfig = {
|
|
4
|
+
/** 活跃 run 心跳写入周期(毫秒),默认分钟级 */
|
|
5
|
+
readonly heartbeatIntervalMs: number;
|
|
6
|
+
/** 心跳超时阈值(毫秒),超时未刷新视为僵死 */
|
|
7
|
+
readonly staleTimeoutMs: number;
|
|
8
|
+
/** 后台扫描周期(毫秒) */
|
|
9
|
+
readonly scanIntervalMs: number;
|
|
10
|
+
};
|
|
11
|
+
export declare const DEFAULT_WATCHDOG_HEARTBEAT_INTERVAL_MS = 60000;
|
|
12
|
+
export declare const resolveRunWatchdogConfig: (overrides?: Partial<RunWatchdogConfig>, sessionTimeoutMs?: number) => RunWatchdogConfig;
|
|
13
|
+
export declare const WATCHDOG_ERROR_CODE_STALE = "RUN_HEARTBEAT_TIMEOUT";
|
|
14
|
+
export declare const WATCHDOG_ERROR_CODE_STALE_REPEATED = "RUN_HEARTBEAT_TIMEOUT_REPEATED";
|
|
15
|
+
export declare const WATCHDOG_ACTOR_ID = "harness-watchdog";
|
|
16
|
+
export type WatchdogMigration = {
|
|
17
|
+
readonly runId: Run["runId"];
|
|
18
|
+
readonly migratedTo: "paused" | "failed";
|
|
19
|
+
readonly errorCode: string;
|
|
20
|
+
};
|
|
21
|
+
export type RunWatchdog = {
|
|
22
|
+
/** 向 run store 追加一条持久化心跳事件(不带状态快照,避免写放大) */
|
|
23
|
+
readonly heartbeat: (runId: Run["runId"]) => Promise<void>;
|
|
24
|
+
/** 扫描心跳超时的活跃 run 并迁移到 paused(优先)或 failed(重复僵死) */
|
|
25
|
+
readonly scan: () => Promise<readonly WatchdogMigration[]>;
|
|
26
|
+
readonly start: () => void;
|
|
27
|
+
readonly stop: () => void;
|
|
28
|
+
};
|
|
29
|
+
export type RunWatchdogDependencies = {
|
|
30
|
+
readonly store: RunStore;
|
|
31
|
+
readonly clock: () => Date;
|
|
32
|
+
readonly createEventId: (label: string) => string;
|
|
33
|
+
readonly config: RunWatchdogConfig;
|
|
34
|
+
};
|
|
35
|
+
export declare const createRunWatchdog: (input: RunWatchdogDependencies) => RunWatchdog;
|
|
36
|
+
//# sourceMappingURL=run-watchdog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-watchdog.d.ts","sourceRoot":"","sources":["../../src/controller/run-watchdog.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,GAAG,EAAa,MAAM,oBAAoB,CAAA;AACxD,OAAO,KAAK,EAAY,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAE3D,MAAM,MAAM,iBAAiB,GAAG;IAC9B,8BAA8B;IAC9B,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAA;IACpC,2BAA2B;IAC3B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAA;IAC/B,iBAAiB;IACjB,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAA;CAChC,CAAA;AAED,eAAO,MAAM,sCAAsC,QAAS,CAAA;AAE5D,eAAO,MAAM,wBAAwB,GACnC,YAAY,OAAO,CAAC,iBAAiB,CAAC,EACtC,yBAA0B,KACzB,iBAID,CAAA;AASF,eAAO,MAAM,yBAAyB,0BAA0B,CAAA;AAChE,eAAO,MAAM,kCAAkC,mCAAmC,CAAA;AAClF,eAAO,MAAM,iBAAiB,qBAAqB,CAAA;AAEnD,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC,OAAO,CAAC,CAAA;IAC5B,QAAQ,CAAC,UAAU,EAAE,QAAQ,GAAG,QAAQ,CAAA;IACxC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAC3B,CAAA;AAED,MAAM,MAAM,WAAW,GAAG;IACxB,4CAA4C;IAC5C,QAAQ,CAAC,SAAS,EAAE,CAAC,KAAK,EAAE,GAAG,CAAC,OAAO,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAC1D,kDAAkD;IAClD,QAAQ,CAAC,IAAI,EAAE,MAAM,OAAO,CAAC,SAAS,iBAAiB,EAAE,CAAC,CAAA;IAC1D,QAAQ,CAAC,KAAK,EAAE,MAAM,IAAI,CAAA;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,IAAI,CAAA;CAC1B,CAAA;AAED,MAAM,MAAM,uBAAuB,GAAG;IACpC,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAA;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,IAAI,CAAA;IAC1B,QAAQ,CAAC,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAA;IACjD,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAA;CACnC,CAAA;AAED,eAAO,MAAM,iBAAiB,GAAI,OAAO,uBAAuB,KAAG,WA+GlE,CAAA"}
|