@deepseek-ai/dsh-goal 0.2.0-rc.2 → 0.2.1-alpha.1
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.i18n.yaml +4 -4
- package/README.md +1 -2
- package/README.zh.md +1 -2
- package/lib/typert.host.js +14 -2
- package/package.json +25 -32
- package/lib/invariant.js +0 -332
- package/lib/types/invariant.d.ts +0 -13
- package/lib/types/invariant.js +0 -71
package/README.i18n.yaml
CHANGED
|
@@ -42,14 +42,14 @@
|
|
|
42
42
|
en: 6f19e891ffc79754
|
|
43
43
|
zh: 9599e3b142f1e6b5
|
|
44
44
|
/deepseek-ai-dsh-goal/understand-the-implementation/source-map:
|
|
45
|
-
en:
|
|
46
|
-
zh:
|
|
45
|
+
en: aef62dff93f32796
|
|
46
|
+
zh: dba79da0466218a7
|
|
47
47
|
/deepseek-ai-dsh-goal/understand-the-implementation/events-and-attribution:
|
|
48
48
|
en: 502cf61dba8b22ca
|
|
49
49
|
zh: 2b6f672bb2ac84ba
|
|
50
50
|
/deepseek-ai-dsh-goal/further-exploration:
|
|
51
|
-
en:
|
|
52
|
-
zh:
|
|
51
|
+
en: 11e7ecd3115d0b6b
|
|
52
|
+
zh: d1dff8b7d05a2f09
|
|
53
53
|
/deepseek-ai-dsh-goal/model-experience:
|
|
54
54
|
en: 215e7ba838619b7b
|
|
55
55
|
zh: a311da3843709f90
|
package/README.md
CHANGED
|
@@ -109,7 +109,6 @@ This section explains how the service realizes the behavior above; the observabl
|
|
|
109
109
|
| [`src/types.ts`](src/types.ts) | Pure client-safe types: `GoalView`, `GoalSnapshot`, `GoalActivationChanged`, projection-key declaration |
|
|
110
110
|
| [`src/fold.ts`](src/fold.ts) | Strict replay fold and decoder for durable goal changes |
|
|
111
111
|
| [`src/runtime.ts`](src/runtime.ts) | `GoalId` brand, `GoalError` codes, change-version constant |
|
|
112
|
-
| [`src/invariant.ts`](src/invariant.ts) | Invariant companion: independent incremental fold over every attached session |
|
|
113
112
|
|
|
114
113
|
### Events and attribution
|
|
115
114
|
|
|
@@ -127,7 +126,7 @@ The package-level contract is enough for most consumers; read these when you nee
|
|
|
127
126
|
- [Goal subsystem](../../../docs/subsystems/goal.md) — the goal types, durable change payloads, and generated service API.
|
|
128
127
|
- [Goal group map](../README.md) — the goal packages and how they compose.
|
|
129
128
|
- [Generated configuration catalog](../../../docs/config-catalog.md#deepseek-aidsh-goal) — every accepted config field and its source declaration.
|
|
130
|
-
- [Goal domain Agent Note](../../../.agents/notes/
|
|
129
|
+
- [historical Goal domain Agent Note](../../../.agents/notes/archived/feature/2026-07-19-persisted-same-session-goal-domain.md) — the domain design, alternatives, and decisions.
|
|
131
130
|
|
|
132
131
|
-----
|
|
133
132
|
|
package/README.zh.md
CHANGED
|
@@ -109,7 +109,6 @@ view.activation // 'armed' | 'disarmed' — not persisted
|
|
|
109
109
|
| [`src/types.ts`](src/types.ts) | 纯客户端安全类型:`GoalView`、`GoalSnapshot`、`GoalActivationChanged`、投影键声明 |
|
|
110
110
|
| [`src/fold.ts`](src/fold.ts) | 持久 goal 变更的严格回放折叠与解码器 |
|
|
111
111
|
| [`src/runtime.ts`](src/runtime.ts) | `GoalId` 品牌、`GoalError` 代码、变更版本常量 |
|
|
112
|
-
| [`src/invariant.ts`](src/invariant.ts) | 不变式配套模块:对每个已挂接会话的独立增量折叠 |
|
|
113
112
|
|
|
114
113
|
### 事件与归属
|
|
115
114
|
|
|
@@ -127,7 +126,7 @@ view.activation // 'armed' | 'disarmed' — not persisted
|
|
|
127
126
|
- [goal 子系统](../../../docs/subsystems/goal.zh.md)——goal 类型、持久的变更载荷与生成的服务 API。
|
|
128
127
|
- [goal 组地图](../README.zh.md)——goal 各包及其组合方式。
|
|
129
128
|
- [生成的配置目录](../../../docs/config-catalog.zh.md#deepseek-aidsh-goal)——每个受支持配置字段及其源声明。
|
|
130
|
-
- [goal 领域 Agent Note](../../../.agents/notes/
|
|
129
|
+
- [历史goal 领域 Agent Note](../../../.agents/notes/archived/feature/2026-07-19-persisted-same-session-goal-domain.md)——领域设计、备选方案与决策。
|
|
131
130
|
|
|
132
131
|
-----
|
|
133
132
|
|
package/lib/typert.host.js
CHANGED
|
@@ -785,6 +785,14 @@ export const TYPERT = {
|
|
|
785
785
|
"name": "LlmFailure",
|
|
786
786
|
"declaration": "export interface LlmFailure {\n readonly message: string;\n readonly code: string;\n readonly status?: number;\n readonly providerRetryAfterMs?: number;\n readonly requestId?: ProviderRequestId;\n readonly offloadImages?: number;\n}"
|
|
787
787
|
},
|
|
788
|
+
{
|
|
789
|
+
"name": "LlmRetryEventData",
|
|
790
|
+
"declaration": "export type LlmRetryEventData = { retryId: RetryId; turn: number; step: number; provider: string; mode: 'normal'; policyKey: string; retry: number; maxRetries: number; delayMs: number; failure: LlmFailure; } | { retryId: RetryId; turn: number; step: number; provider: string; mode: 'always'; policyKey: string; retry: number; delayMs: number; failure: LlmFailure; };"
|
|
791
|
+
},
|
|
792
|
+
{
|
|
793
|
+
"name": "LlmRetryStartedEventData",
|
|
794
|
+
"declaration": "export interface LlmRetryStartedEventData {\n retryId: RetryId;\n turn: number;\n step: number;\n retry: number;\n}"
|
|
795
|
+
},
|
|
788
796
|
{
|
|
789
797
|
"name": "Message",
|
|
790
798
|
"declaration": "export type Message = MessageRoleMap[keyof MessageRoleMap];"
|
|
@@ -827,7 +835,7 @@ export const TYPERT = {
|
|
|
827
835
|
},
|
|
828
836
|
{
|
|
829
837
|
"name": "MessageSourceMap",
|
|
830
|
-
"declaration": "export interface MessageSourceMap {\n user: { kind: 'user'; };\n model: ModelMessageSource;\n tool: ToolMessageSource;\n 'system-prompt': SystemPromptMessageSource;\n 'model-selection': { kind: 'model-selection'; } & ContextFormed;\n 'user-approval': { kind: 'user-approval'; } & ContextFormed;\n 'ptc-mode': { kind: 'ptc-mode'; };\n 'tool-registry': { kind: 'tool-registry'; };\n 'user-rpc': { kind: 'user'; rpcId: SessionRequestId; clientTimeZone?: string; };\n 'agent-message': AgentMessageSource;\n 'subagent-settled': SubagentSettledMessageSource;\n 'skill-invocation': SkillInvocationSource;\n 'cordis-host-runner': { kind: 'cordis-host-runner'; };\n
|
|
838
|
+
"declaration": "export interface MessageSourceMap {\n user: { kind: 'user'; };\n model: ModelMessageSource;\n tool: ToolMessageSource;\n 'system-prompt': SystemPromptMessageSource;\n 'model-selection': { kind: 'model-selection'; } & ContextFormed;\n 'user-approval': { kind: 'user-approval'; } & ContextFormed;\n 'ptc-mode': { kind: 'ptc-mode'; };\n 'tool-registry': { kind: 'tool-registry'; };\n 'user-rpc': { kind: 'user'; rpcId: SessionRequestId; clientTimeZone?: string; };\n 'agent-message': AgentMessageSource;\n 'subagent-settled': SubagentSettledMessageSource;\n 'skill-invocation': SkillInvocationSource;\n 'cordis-host-runner': { kind: 'cordis-host-runner'; };\n 'compact-checkpoint': CompactionCheckpointSource;\n 'user-question-reply': { kind: 'user-question-reply'; callId: ToolCallId; outcome: 'answered'; };\n goal: GoalMessageSource;\n schedule: { kind: 'schedule'; } & ContextFormed;\n 'session-reference': SessionReferenceSource;\n}"
|
|
831
839
|
},
|
|
832
840
|
{
|
|
833
841
|
"name": "ModelMessageSource",
|
|
@@ -881,6 +889,10 @@ export const TYPERT = {
|
|
|
881
889
|
"name": "RequestHeaderReason",
|
|
882
890
|
"declaration": "export type RequestHeaderReason = 'initial' | 'resume' | 'change' | 'series';"
|
|
883
891
|
},
|
|
892
|
+
{
|
|
893
|
+
"name": "RetryId",
|
|
894
|
+
"declaration": "export type RetryId = Branded<'RetryId'>;"
|
|
895
|
+
},
|
|
884
896
|
{
|
|
885
897
|
"name": "SandboxMode",
|
|
886
898
|
"declaration": "export type SandboxMode = 'read-only' | 'workspace-write' | 'danger-full-access';"
|
|
@@ -915,7 +927,7 @@ export const TYPERT = {
|
|
|
915
927
|
},
|
|
916
928
|
{
|
|
917
929
|
"name": "SessionEventMap",
|
|
918
|
-
"declaration": "export interface SessionEventMap {\n 'turn/start': { turn: number; };\n 'turn/end': { turn: number; reason: TurnEndReason; };\n 'step/start': { turn: number; step: number; };\n 'step/end': { turn: number; step: number; };\n 'user/message': UserMessage;\n 'developer/message': { turn: number; step: number; message: DeveloperMessage; headerSeq?: SessionSeq; };\n 'system/message': { turn: number; step: number; message: SystemMessage; };\n 'assistant/message': { turn: number; step: number; message: AssistantMessage; stream: AssistantStreamRecord[]; usage?: TokenUsage; interrupted?: true; };\n 'assistant/attempt': { turn: number; step: number; stream: AssistantStreamRecord[]; };\n 'tool/call': { turn: number; step: number; callId: ToolCallId; name: string; arguments: string; };\n 'tool/result': { turn: number; step: number; message: ToolResultMessage; error?: { name: string; code: string; reason?: string; }; meta?: JsonValue; };\n 'request/header': { header: EpochHeader; reason: RequestHeaderReason; startsSeries?: true; };\n 'request/context': RequestContext;\n 'session/end-seed': { inherited?: true; };\n 'agent/inbox/spliced': { target: InboxTarget; start: number; removedCount?: number; inserted: UserMessage[]; outcome?: 'canceled'; };\n 'sandbox/mode': { mode: SandboxMode; source?: 'delegation'; };\n 'approval/asked': { id: ApprovalRequestId; toolName: string; callId?: ToolCallId; reason?: string; };\n 'approval/decided': { id: ApprovalRequestId; outcome: ApprovalOutcome; };\n 'approval/policy': { policy: ApprovalPolicy; source?: 'delegation'; };\n 'tool/ptc-dispatch-start': PtcDispatchStartEventData;\n 'tool/ptc-dispatch': PtcDispatchEventData;\n 'agent-preset/selected': { agentPreset: string; };\n 'command/run': { commandId: CommandId; name: string; args?: string; source: CommandSource; };\n 'command/done': { commandId: CommandId; kind: 'success' | 'error'; text?: string; sourceEventSeq?: import('@deepseek-ai/dsh-session/types').SessionSeq; };\n 'image/offload': { targets: ImageOffloadTarget[]; };\n 'session/title': SessionTitleEventData;\n 'todo/write': { todos: TodoItem[]; };\n 'model/selection': ModelSelection;\n 'subagent/descriptor': SubagentDescriptorData;\n 'permission/preset': { preset: string; };\n 'subagent/catalog': SubagentCatalogEvent;\n 'compaction/start': { compactionId: CompactionId; sourceCommandId?: CommandId; turn: number | null; };\n 'compaction/summary': { compactionId: CompactionId; sourceCommandId?: CommandId; summary: ContentBlock[]; shadowedRange: { start: SessionSeq; end: SessionSeq; }; shadowedSeqs: SessionSeq[]; shadowedTokenCount: number; provider: string; model: string; maxTokens?: number; usage?: TokenUsage; } & ({ rawOutput: ContentBlock[]; llmStreamCall: true; } | { rawOutput?: ContentBlock[]; llmStreamCall?: never; });\n 'compaction/end': { compactionId: CompactionId; sourceCommandId?: CommandId; turn: number | null; error?: string; };\n 'compaction/prune': { shadowedRange: { start: SessionSeq; end: SessionSeq; }; shadowedSeqs: SessionSeq[]; shadowedTokenCount: number; };\n 'feedback/record': FeedbackRecord;\n 'goal/change': GoalChangeMeta;\n 'feedback/message-put': MessageFeedbackPut;\n 'feedback/message-delete': MessageFeedbackDelete;\n 'schedule/change': ScheduleChange;\n}"
|
|
930
|
+
"declaration": "export interface SessionEventMap {\n 'turn/start': { turn: number; };\n 'turn/end': { turn: number; reason: TurnEndReason; };\n 'step/start': { turn: number; step: number; };\n 'step/end': { turn: number; step: number; };\n 'user/message': UserMessage;\n 'developer/message': { turn: number; step: number; message: DeveloperMessage; headerSeq?: SessionSeq; };\n 'system/message': { turn: number; step: number; message: SystemMessage; };\n 'assistant/message': { turn: number; step: number; message: AssistantMessage; stream: AssistantStreamRecord[]; usage?: TokenUsage; interrupted?: true; };\n 'assistant/attempt': { turn: number; step: number; stream: AssistantStreamRecord[]; };\n 'tool/call': { turn: number; step: number; callId: ToolCallId; name: string; arguments: string; };\n 'tool/result': { turn: number; step: number; message: ToolResultMessage; error?: { name: string; code: string; reason?: string; }; meta?: JsonValue; };\n 'request/header': { header: EpochHeader; reason: RequestHeaderReason; startsSeries?: true; };\n 'request/context': RequestContext;\n 'session/end-seed': { inherited?: true; };\n 'agent/inbox/spliced': { target: InboxTarget; start: number; removedCount?: number; inserted: UserMessage[]; outcome?: 'canceled'; };\n 'sandbox/mode': { mode: SandboxMode; source?: 'delegation'; };\n 'approval/asked': { id: ApprovalRequestId; toolName: string; callId?: ToolCallId; reason?: string; };\n 'approval/decided': { id: ApprovalRequestId; outcome: ApprovalOutcome; };\n 'approval/policy': { policy: ApprovalPolicy; source?: 'delegation'; };\n 'tool/ptc-dispatch-start': PtcDispatchStartEventData;\n 'tool/ptc-dispatch': PtcDispatchEventData;\n 'agent-preset/selected': { agentPreset: string; };\n 'command/run': { commandId: CommandId; name: string; args?: string; source: CommandSource; };\n 'command/done': { commandId: CommandId; kind: 'success' | 'error'; text?: string; sourceEventSeq?: import('@deepseek-ai/dsh-session/types').SessionSeq; };\n 'image/offload': { targets: ImageOffloadTarget[]; };\n 'session/title': SessionTitleEventData;\n 'todo/write': { todos: TodoItem[]; };\n 'model/selection': ModelSelection;\n 'subagent/descriptor': SubagentDescriptorData;\n 'permission/preset': { preset: string; };\n 'subagent/catalog': SubagentCatalogEvent;\n 'compaction/start': { compactionId: CompactionId; sourceCommandId?: CommandId; turn: number | null; };\n 'compaction/summary': { compactionId: CompactionId; sourceCommandId?: CommandId; summary: ContentBlock[]; shadowedRange: { start: SessionSeq; end: SessionSeq; }; shadowedSeqs: SessionSeq[]; shadowedTokenCount: number; provider: string; model: string; maxTokens?: number; usage?: TokenUsage; } & ({ rawOutput: ContentBlock[]; llmStreamCall: true; } | { rawOutput?: ContentBlock[]; llmStreamCall?: never; });\n 'compaction/end': { compactionId: CompactionId; sourceCommandId?: CommandId; turn: number | null; error?: string; };\n 'compaction/prune': { shadowedRange: { start: SessionSeq; end: SessionSeq; }; shadowedSeqs: SessionSeq[]; shadowedTokenCount: number; };\n 'feedback/record': FeedbackRecord;\n 'llm/retry': LlmRetryEventData;\n 'llm/retry-started': LlmRetryStartedEventData;\n 'goal/change': GoalChangeMeta;\n 'feedback/message-put': MessageFeedbackPut;\n 'feedback/message-delete': MessageFeedbackDelete;\n 'schedule/change': ScheduleChange;\n}"
|
|
919
931
|
},
|
|
920
932
|
{
|
|
921
933
|
"name": "SessionEventType",
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deepseek-ai/dsh-goal",
|
|
3
3
|
"description": "Event-sourced same-session goal state and lifecycle service for the DeepSeek Harness",
|
|
4
|
-
"version": "0.2.
|
|
4
|
+
"version": "0.2.1-alpha.1",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -18,10 +18,6 @@
|
|
|
18
18
|
"types": "./lib/types/index.d.ts",
|
|
19
19
|
"default": "./lib/index.js"
|
|
20
20
|
},
|
|
21
|
-
"./invariant": {
|
|
22
|
-
"types": "./lib/types/invariant.d.ts",
|
|
23
|
-
"default": "./lib/invariant.js"
|
|
24
|
-
},
|
|
25
21
|
"./types": {
|
|
26
22
|
"types": "./lib/types/types.d.ts",
|
|
27
23
|
"default": "./lib/types/types.js"
|
|
@@ -43,7 +39,6 @@
|
|
|
43
39
|
},
|
|
44
40
|
"files": [
|
|
45
41
|
"lib/index.js",
|
|
46
|
-
"lib/invariant.js",
|
|
47
42
|
"lib/types/**/*.js",
|
|
48
43
|
"lib/types/**/*.d.ts",
|
|
49
44
|
"lib/typert.host.js",
|
|
@@ -53,36 +48,34 @@
|
|
|
53
48
|
],
|
|
54
49
|
"license": "MIT",
|
|
55
50
|
"peerDependencies": {
|
|
56
|
-
"@deepseek-ai/dsh-
|
|
57
|
-
"@deepseek-ai/dsh-
|
|
58
|
-
"@deepseek-ai/dsh-
|
|
59
|
-
"@deepseek-ai/dsh-
|
|
60
|
-
"@deepseek-ai/dsh-
|
|
61
|
-
"@deepseek-ai/dsh-session": "0.2.
|
|
62
|
-
"@deepseek-ai/dsh-typert-protocol": "0.2.
|
|
63
|
-
"@deepseek-ai/cordis": "~4.0.
|
|
64
|
-
"@deepseek-ai/dsh-scope": "0.2.0-rc.2"
|
|
51
|
+
"@deepseek-ai/dsh-agent": "0.2.1-alpha.1",
|
|
52
|
+
"@deepseek-ai/dsh-session-projection": "0.2.1-alpha.1",
|
|
53
|
+
"@deepseek-ai/dsh-brand": "0.2.1-alpha.1",
|
|
54
|
+
"@deepseek-ai/dsh-llm": "0.2.1-alpha.1",
|
|
55
|
+
"@deepseek-ai/dsh-scope": "0.2.1-alpha.1",
|
|
56
|
+
"@deepseek-ai/dsh-session": "0.2.1-alpha.1",
|
|
57
|
+
"@deepseek-ai/dsh-typert-protocol": "0.2.1-alpha.1",
|
|
58
|
+
"@deepseek-ai/cordis": "~4.0.5-alpha.1"
|
|
65
59
|
},
|
|
66
60
|
"dependencies": {
|
|
67
61
|
"zod": "^4.4.3",
|
|
68
|
-
"@deepseek-ai/schemastery": "~3.18.
|
|
62
|
+
"@deepseek-ai/schemastery": "~3.18.5-alpha.1"
|
|
69
63
|
},
|
|
70
64
|
"devDependencies": {
|
|
71
|
-
"@deepseek-ai/dsh-agent": "0.2.
|
|
72
|
-
"@deepseek-ai/dsh-
|
|
73
|
-
"@deepseek-ai/dsh-agent-loop": "0.2.
|
|
74
|
-
"@deepseek-ai/dsh-
|
|
75
|
-
"@deepseek-ai/dsh-session-projection": "0.2.
|
|
76
|
-
"@deepseek-ai/dsh-brand": "0.2.
|
|
77
|
-
"@deepseek-ai/dsh-
|
|
78
|
-
"@deepseek-ai/dsh-
|
|
79
|
-
"@deepseek-ai/dsh-
|
|
80
|
-
"@deepseek-ai/dsh-session
|
|
81
|
-
"@deepseek-ai/dsh-session-persistence-jsonl": "0.2.
|
|
82
|
-
"@deepseek-ai/dsh-subprocess-local": "0.2.
|
|
83
|
-
"@deepseek-ai/
|
|
84
|
-
"@deepseek-ai/
|
|
85
|
-
"@deepseek-ai/dsh-
|
|
86
|
-
"@deepseek-ai/dsh-typert-protocol": "0.2.0-rc.2"
|
|
65
|
+
"@deepseek-ai/dsh-agent": "0.2.1-alpha.1",
|
|
66
|
+
"@deepseek-ai/dsh-agent-loop": "0.2.1-alpha.1",
|
|
67
|
+
"@deepseek-ai/dsh-agent-loop-testkit": "0.2.1-alpha.1",
|
|
68
|
+
"@deepseek-ai/dsh-bash-local": "0.2.1-alpha.1",
|
|
69
|
+
"@deepseek-ai/dsh-session-projection": "0.2.1-alpha.1",
|
|
70
|
+
"@deepseek-ai/dsh-brand": "0.2.1-alpha.1",
|
|
71
|
+
"@deepseek-ai/dsh-scope": "0.2.1-alpha.1",
|
|
72
|
+
"@deepseek-ai/dsh-loader-smoke": "0.2.1-alpha.1",
|
|
73
|
+
"@deepseek-ai/dsh-llm": "0.2.1-alpha.1",
|
|
74
|
+
"@deepseek-ai/dsh-session": "0.2.1-alpha.1",
|
|
75
|
+
"@deepseek-ai/dsh-session-persistence-jsonl": "0.2.1-alpha.1",
|
|
76
|
+
"@deepseek-ai/dsh-subprocess-local": "0.2.1-alpha.1",
|
|
77
|
+
"@deepseek-ai/dsh-typert-protocol": "0.2.1-alpha.1",
|
|
78
|
+
"@deepseek-ai/cordis": "~4.0.5-alpha.1",
|
|
79
|
+
"@deepseek-ai/dsh-session-checkpoint-policy": "0.2.1-alpha.1"
|
|
87
80
|
}
|
|
88
81
|
}
|
package/lib/invariant.js
DELETED
|
@@ -1,332 +0,0 @@
|
|
|
1
|
-
import "@deepseek-ai/dsh-llm";
|
|
2
|
-
//#region lib/types/runtime.js
|
|
3
|
-
/**
|
|
4
|
-
* Brand a string as a goal id.
|
|
5
|
-
* @param id - raw goal identifier.
|
|
6
|
-
* @returns the same string with the compile-time brand.
|
|
7
|
-
*/
|
|
8
|
-
function GoalId(id) {
|
|
9
|
-
return id;
|
|
10
|
-
}
|
|
11
|
-
//#endregion
|
|
12
|
-
//#region lib/types/fold.js
|
|
13
|
-
/** Pure replay fold and strict decoder for durable goal changes. */
|
|
14
|
-
const SNAPSHOT_OPERATIONS = new Set([
|
|
15
|
-
"create",
|
|
16
|
-
"edit",
|
|
17
|
-
"pause",
|
|
18
|
-
"resume",
|
|
19
|
-
"complete",
|
|
20
|
-
"block"
|
|
21
|
-
]);
|
|
22
|
-
const PHASES = new Set([
|
|
23
|
-
"active",
|
|
24
|
-
"paused",
|
|
25
|
-
"blocked",
|
|
26
|
-
"complete"
|
|
27
|
-
]);
|
|
28
|
-
/**
|
|
29
|
-
* Build an empty replay accumulator.
|
|
30
|
-
* @returns mutable state with no current goal or prior ref.
|
|
31
|
-
*/
|
|
32
|
-
function emptyGoalFoldState() {
|
|
33
|
-
return {
|
|
34
|
-
goal: void 0,
|
|
35
|
-
roundsStarted: 0,
|
|
36
|
-
createdAt: void 0,
|
|
37
|
-
updatedAt: void 0,
|
|
38
|
-
lastRef: void 0,
|
|
39
|
-
seenGoalIds: /* @__PURE__ */ new Set()
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
/** Whether a value is a JSON record rather than an array. */
|
|
43
|
-
function isRecord(value) {
|
|
44
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
45
|
-
}
|
|
46
|
-
/** Require one positive safe integer. */
|
|
47
|
-
function positiveInteger(value, field) {
|
|
48
|
-
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 1) throw new Error(`goal change ${field} must be a positive safe integer`);
|
|
49
|
-
return value;
|
|
50
|
-
}
|
|
51
|
-
/** Require one non-negative safe integer. */
|
|
52
|
-
function nonNegativeInteger(value, field) {
|
|
53
|
-
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) throw new Error(`goal change ${field} must be a non-negative safe integer`);
|
|
54
|
-
return value;
|
|
55
|
-
}
|
|
56
|
-
/** Decode one canonical blocker explanation. */
|
|
57
|
-
function decodeBlockReason(value) {
|
|
58
|
-
if (!isRecord(value) || Object.keys(value).sort().join(",") !== "code,message") throw new Error("goal change goal.blockedReason must have exactly code and message fields");
|
|
59
|
-
if (typeof value["code"] !== "string" || !/^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/.test(value["code"])) throw new Error("goal change goal.blockedReason.code must be lower-kebab-case");
|
|
60
|
-
if (typeof value["message"] !== "string" || value["message"].trim().length === 0 || value["message"] !== value["message"].trim()) throw new Error("goal change goal.blockedReason.message must be non-empty and normalized");
|
|
61
|
-
return {
|
|
62
|
-
code: value["code"],
|
|
63
|
-
message: value["message"]
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
/** Decode and validate one snapshot. */
|
|
67
|
-
function decodeSnapshot(value) {
|
|
68
|
-
if (!isRecord(value)) throw new Error("goal change goal must be a record");
|
|
69
|
-
if (typeof value["id"] !== "string" || value["id"].length === 0) throw new Error("goal change goal.id must be a non-empty string");
|
|
70
|
-
if (typeof value["objective"] !== "string" || value["objective"].trim().length === 0 || value["objective"] !== value["objective"].trim()) throw new Error("goal change goal.objective must be non-empty and normalized");
|
|
71
|
-
if (typeof value["phase"] !== "string" || !PHASES.has(value["phase"])) throw new Error("goal change goal.phase is invalid");
|
|
72
|
-
const phase = value["phase"];
|
|
73
|
-
const expectedKeys = phase === "blocked" ? "blockedReason,id,maxGoalRounds,objective,phase,revision" : "id,maxGoalRounds,objective,phase,revision";
|
|
74
|
-
if (Object.keys(value).sort().join(",") !== expectedKeys) throw new Error(`goal change goal for phase ${phase} must have exactly ${expectedKeys} fields`);
|
|
75
|
-
return {
|
|
76
|
-
id: GoalId(value["id"]),
|
|
77
|
-
revision: positiveInteger(value["revision"], "goal.revision"),
|
|
78
|
-
objective: value["objective"],
|
|
79
|
-
phase,
|
|
80
|
-
maxGoalRounds: positiveInteger(value["maxGoalRounds"], "goal.maxGoalRounds"),
|
|
81
|
-
...phase === "blocked" ? { blockedReason: decodeBlockReason(value["blockedReason"]) } : {}
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
|
-
/** Decode and validate one ref. */
|
|
85
|
-
function decodeRef(value) {
|
|
86
|
-
if (!isRecord(value) || Object.keys(value).sort().join(",") !== "id,revision") throw new Error("goal clear tombstone must have exactly id and revision fields");
|
|
87
|
-
if (typeof value["id"] !== "string" || value["id"].length === 0) throw new Error("goal clear tombstone id must be a non-empty string");
|
|
88
|
-
return {
|
|
89
|
-
id: GoalId(value["id"]),
|
|
90
|
-
revision: positiveInteger(value["revision"], "cleared.revision")
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
|
-
/**
|
|
94
|
-
* Decode a value that declares itself as a goal change. Unrelated values
|
|
95
|
-
* return `undefined`; malformed goal changes fail replay loudly.
|
|
96
|
-
* @param value - candidate source change.
|
|
97
|
-
* @returns validated goal change or `undefined` for another value kind.
|
|
98
|
-
*/
|
|
99
|
-
function decodeGoalChange(value) {
|
|
100
|
-
if (!isRecord(value) || value["kind"] !== "goal/change") return void 0;
|
|
101
|
-
if (value["version"] !== 1) throw new Error(`unsupported goal change version ${String(value["version"])}`);
|
|
102
|
-
if (value["operation"] === "clear") {
|
|
103
|
-
const allowed = [
|
|
104
|
-
"cleared",
|
|
105
|
-
"clearedAt",
|
|
106
|
-
"kind",
|
|
107
|
-
"operation",
|
|
108
|
-
"version"
|
|
109
|
-
];
|
|
110
|
-
if (Object.keys(value).sort().join(",") !== allowed.sort().join(",")) throw new Error(`goal clear change must have exactly ${allowed.sort().join(",")} fields`);
|
|
111
|
-
return {
|
|
112
|
-
kind: "goal/change",
|
|
113
|
-
version: 1,
|
|
114
|
-
operation: "clear",
|
|
115
|
-
cleared: decodeRef(value["cleared"]),
|
|
116
|
-
clearedAt: nonNegativeInteger(value["clearedAt"], "clearedAt")
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
if (typeof value["operation"] !== "string" || !SNAPSHOT_OPERATIONS.has(value["operation"])) throw new Error("goal change operation is invalid");
|
|
120
|
-
const allowed = [
|
|
121
|
-
"createdAt",
|
|
122
|
-
"goal",
|
|
123
|
-
"kind",
|
|
124
|
-
"operation",
|
|
125
|
-
"roundsStarted",
|
|
126
|
-
"updatedAt",
|
|
127
|
-
"version"
|
|
128
|
-
];
|
|
129
|
-
if (Object.keys(value).sort().join(",") !== allowed.sort().join(",")) throw new Error(`goal snapshot change must have exactly ${allowed.sort().join(",")} fields`);
|
|
130
|
-
const createdAt = nonNegativeInteger(value["createdAt"], "createdAt");
|
|
131
|
-
const updatedAt = nonNegativeInteger(value["updatedAt"], "updatedAt");
|
|
132
|
-
if (updatedAt < createdAt) throw new Error("goal change updatedAt cannot precede createdAt");
|
|
133
|
-
return {
|
|
134
|
-
kind: "goal/change",
|
|
135
|
-
version: 1,
|
|
136
|
-
operation: value["operation"],
|
|
137
|
-
goal: decodeSnapshot(value["goal"]),
|
|
138
|
-
roundsStarted: nonNegativeInteger(value["roundsStarted"], "roundsStarted"),
|
|
139
|
-
createdAt,
|
|
140
|
-
updatedAt
|
|
141
|
-
};
|
|
142
|
-
}
|
|
143
|
-
/** Narrow model attribution to a valid goal source. */
|
|
144
|
-
function goalSource(source) {
|
|
145
|
-
if (source.kind !== "goal") return void 0;
|
|
146
|
-
if (typeof source.goalId !== "string" || source.goalId.length === 0 || !Number.isSafeInteger(source.revision) || source.revision < 1 || !Number.isSafeInteger(source.round) || source.round < 1) throw new Error("goal message source is invalid");
|
|
147
|
-
return source;
|
|
148
|
-
}
|
|
149
|
-
/** Require two snapshots to retain fields that only `edit` may replace. */
|
|
150
|
-
function requireSameDefinition(current, next, operation) {
|
|
151
|
-
if (next.objective !== current.objective || next.maxGoalRounds !== current.maxGoalRounds) throw new Error(`goal ${operation} cannot change objective or maxGoalRounds`);
|
|
152
|
-
}
|
|
153
|
-
/** Require one exact next revision of the current goal. */
|
|
154
|
-
function requireNextRevision(current, next, operation) {
|
|
155
|
-
if (next.id !== current.id || next.revision !== current.revision + 1) throw new Error(`goal ${operation} must advance the current goal by one revision`);
|
|
156
|
-
}
|
|
157
|
-
/** Validate one non-create snapshot operation against the preceding projection. */
|
|
158
|
-
function validateSnapshotTransition(state, change, current) {
|
|
159
|
-
const next = change.goal;
|
|
160
|
-
requireNextRevision(current, next, change.operation);
|
|
161
|
-
/* v8 ignore next -- a current goal established by this fold always has an updatedAt */
|
|
162
|
-
if (state.updatedAt === void 0) throw new Error("current goal fold lacks updatedAt");
|
|
163
|
-
if (change.createdAt !== state.createdAt || change.updatedAt < state.updatedAt || change.roundsStarted !== state.roundsStarted) throw new Error(`goal ${change.operation} does not preserve the current counters and timestamps`);
|
|
164
|
-
switch (change.operation) {
|
|
165
|
-
case "edit":
|
|
166
|
-
if (next.phase !== current.phase || JSON.stringify(next.blockedReason) !== JSON.stringify(current.blockedReason)) throw new Error("goal edit cannot change phase or blocked reason");
|
|
167
|
-
break;
|
|
168
|
-
case "pause":
|
|
169
|
-
requireSameDefinition(current, next, change.operation);
|
|
170
|
-
if (current.phase !== "active" || next.phase !== "paused") throw new Error("goal pause has an invalid phase transition");
|
|
171
|
-
break;
|
|
172
|
-
case "resume":
|
|
173
|
-
requireSameDefinition(current, next, change.operation);
|
|
174
|
-
if (!new Set([
|
|
175
|
-
"active",
|
|
176
|
-
"paused",
|
|
177
|
-
"blocked"
|
|
178
|
-
]).has(current.phase) || next.phase !== "active" || state.roundsStarted >= next.maxGoalRounds) throw new Error("goal resume has an invalid phase transition or exhausted round budget");
|
|
179
|
-
break;
|
|
180
|
-
case "complete":
|
|
181
|
-
requireSameDefinition(current, next, change.operation);
|
|
182
|
-
if (current.phase === "complete" || next.phase !== "complete") throw new Error("goal complete has an invalid phase transition");
|
|
183
|
-
break;
|
|
184
|
-
case "block":
|
|
185
|
-
requireSameDefinition(current, next, change.operation);
|
|
186
|
-
if (current.phase !== "active" || next.phase !== "blocked") throw new Error("goal block has an invalid phase transition");
|
|
187
|
-
break;
|
|
188
|
-
/* v8 ignore start -- the caller excludes create and GoalOperation is closed; these arms retain fail-loud exhaustiveness */
|
|
189
|
-
case "create": throw new Error("goal create cannot be validated as a current-goal transition");
|
|
190
|
-
default:
|
|
191
|
-
change.operation;
|
|
192
|
-
throw new Error("unknown goal snapshot operation");
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
/**
|
|
196
|
-
* Return the revision identity carried by a snapshot or tombstone.
|
|
197
|
-
* @param change - decoded goal mutation.
|
|
198
|
-
* @returns stable identity used to reconcile a deferred change with its log event.
|
|
199
|
-
*/
|
|
200
|
-
function goalChangeRef(change) {
|
|
201
|
-
return change.operation === "clear" ? change.cleared : {
|
|
202
|
-
id: change.goal.id,
|
|
203
|
-
revision: change.goal.revision
|
|
204
|
-
};
|
|
205
|
-
}
|
|
206
|
-
/**
|
|
207
|
-
* Validate and apply one decoded change to a mutable accumulator.
|
|
208
|
-
* @param state - preceding durable goal projection.
|
|
209
|
-
* @param change - decoded full snapshot or clear tombstone.
|
|
210
|
-
*/
|
|
211
|
-
function applyGoalChange(state, change) {
|
|
212
|
-
const ref = goalChangeRef(change);
|
|
213
|
-
if (change.operation === "clear") {
|
|
214
|
-
const current = state.goal;
|
|
215
|
-
if (current === void 0) throw new Error("goal clear requires a current goal");
|
|
216
|
-
requireNextRevision(current, change.cleared, change.operation);
|
|
217
|
-
/* v8 ignore next -- a current goal established by this fold always has an updatedAt */
|
|
218
|
-
if (state.updatedAt === void 0) throw new Error("current goal fold lacks updatedAt");
|
|
219
|
-
if (change.clearedAt < state.updatedAt) throw new Error("goal clear timestamp cannot precede the current goal update");
|
|
220
|
-
state.goal = void 0;
|
|
221
|
-
state.roundsStarted = 0;
|
|
222
|
-
state.createdAt = void 0;
|
|
223
|
-
state.updatedAt = void 0;
|
|
224
|
-
state.lastRef = ref;
|
|
225
|
-
return;
|
|
226
|
-
}
|
|
227
|
-
if (change.operation === "create") {
|
|
228
|
-
if (change.goal.revision !== 1 || change.goal.phase !== "active" || change.roundsStarted !== 0 || state.goal !== void 0 && state.goal.phase !== "complete" || state.seenGoalIds.has(change.goal.id)) throw new Error("goal create requires a fresh active revision-one goal with zero rounds");
|
|
229
|
-
state.seenGoalIds.add(change.goal.id);
|
|
230
|
-
} else {
|
|
231
|
-
const current = state.goal;
|
|
232
|
-
if (current === void 0) throw new Error(`goal ${change.operation} requires a current goal`);
|
|
233
|
-
validateSnapshotTransition(state, change, current);
|
|
234
|
-
}
|
|
235
|
-
state.goal = change.goal;
|
|
236
|
-
state.roundsStarted = change.roundsStarted;
|
|
237
|
-
state.createdAt = change.createdAt;
|
|
238
|
-
state.updatedAt = change.updatedAt;
|
|
239
|
-
state.lastRef = ref;
|
|
240
|
-
}
|
|
241
|
-
/**
|
|
242
|
-
* Apply one session event to the strict durable goal fold.
|
|
243
|
-
* @param state - mutable fold accumulator.
|
|
244
|
-
* @param event - next event in sequence order.
|
|
245
|
-
*/
|
|
246
|
-
function applyGoalEvent(state, event) {
|
|
247
|
-
if (event.type === "goal/change") {
|
|
248
|
-
const change = decodeGoalChange(event.data);
|
|
249
|
-
/* v8 ignore next -- the event's declared payload always identifies itself as a goal change. */
|
|
250
|
-
if (change === void 0) throw new Error(`goal change at session event ${event.seq} has an invalid kind`);
|
|
251
|
-
applyGoalChange(state, change);
|
|
252
|
-
return;
|
|
253
|
-
}
|
|
254
|
-
if (event.type === "user/message") {
|
|
255
|
-
const source = goalSource(event.data.source);
|
|
256
|
-
if (source === void 0) return;
|
|
257
|
-
const current = state.goal;
|
|
258
|
-
if (current === void 0 || current.phase !== "active" || source.goalId !== current.id || source.revision !== current.revision || source.round !== state.roundsStarted + 1 || source.round > current.maxGoalRounds) throw new Error(`goal round at session event ${event.seq} is not the next admitted round of the active goal`);
|
|
259
|
-
state.roundsStarted = source.round;
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
//#endregion
|
|
263
|
-
//#region lib/types/invariant.js
|
|
264
|
-
/** Package-owned durable goal-stream invariants. @module @deepseek-ai/dsh-goal/invariant */
|
|
265
|
-
const PACKAGE_NAME = "@deepseek-ai/dsh-goal";
|
|
266
|
-
/** Cordis companion plugin name. */
|
|
267
|
-
const name = "goal-invariant";
|
|
268
|
-
/** Service required before the companion can reserve package ownership. */
|
|
269
|
-
const inject = ["invariants"];
|
|
270
|
-
/** Copy the independent fold before validating one candidate event. */
|
|
271
|
-
function cloneState(state) {
|
|
272
|
-
return {
|
|
273
|
-
goal: state.goal,
|
|
274
|
-
roundsStarted: state.roundsStarted,
|
|
275
|
-
createdAt: state.createdAt,
|
|
276
|
-
updatedAt: state.updatedAt,
|
|
277
|
-
lastRef: state.lastRef,
|
|
278
|
-
seenGoalIds: new Set(state.seenGoalIds)
|
|
279
|
-
};
|
|
280
|
-
}
|
|
281
|
-
/** Apply one event through the strict goal decoder and attribute failures. */
|
|
282
|
-
function applyChecked(state, event, fail) {
|
|
283
|
-
try {
|
|
284
|
-
applyGoalEvent(state, event);
|
|
285
|
-
} catch (error) {
|
|
286
|
-
/* v8 ignore next -- the strict goal decoder throws Error instances */
|
|
287
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
288
|
-
fail(`session event ${event.seq} violates the durable goal stream: ${message}`);
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
/** Install an independent incremental fold over every attached session. */
|
|
292
|
-
const install = Object.assign((ctx, fail) => {
|
|
293
|
-
const states = /* @__PURE__ */ new WeakMap();
|
|
294
|
-
const staged = /* @__PURE__ */ new WeakMap();
|
|
295
|
-
const seed = (session) => {
|
|
296
|
-
const state = emptyGoalFoldState();
|
|
297
|
-
for (const event of session.snapshotEvents()) applyChecked(state, event, fail);
|
|
298
|
-
states.set(session, state);
|
|
299
|
-
return state;
|
|
300
|
-
};
|
|
301
|
-
/* v8 ignore next -- session/event always follows list() or session/created seeding */
|
|
302
|
-
const stateFor = (session) => states.get(session) ?? seed(session);
|
|
303
|
-
for (const session of ctx.sessions.list()) seed(session);
|
|
304
|
-
ctx.on("session/created", (session) => {
|
|
305
|
-
seed(session);
|
|
306
|
-
}, { global: true });
|
|
307
|
-
ctx.on("internal/dispatch", (_mode, eventName, args) => {
|
|
308
|
-
if (eventName !== "session/event") return;
|
|
309
|
-
const [session, event] = args;
|
|
310
|
-
const state = cloneState(stateFor(session));
|
|
311
|
-
applyChecked(state, event, fail);
|
|
312
|
-
staged.set(event, {
|
|
313
|
-
session,
|
|
314
|
-
state
|
|
315
|
-
});
|
|
316
|
-
}, { global: true });
|
|
317
|
-
ctx.on("session/event", (session, event) => {
|
|
318
|
-
const candidate = staged.get(event);
|
|
319
|
-
/* v8 ignore next 2 -- internal/dispatch stages the exact callback arguments */
|
|
320
|
-
if (candidate === void 0 || candidate.session !== session) return fail("session/event reached publication without matching goal-fold validation");
|
|
321
|
-
staged.delete(event);
|
|
322
|
-
states.set(session, candidate.state);
|
|
323
|
-
}, { global: true });
|
|
324
|
-
}, { inject: ["sessions"] });
|
|
325
|
-
/**
|
|
326
|
-
* Register the goal-stream invariant companion.
|
|
327
|
-
* @param ctx - Cordis context carrying the invariant service.
|
|
328
|
-
* @returns the installed registration's disposer after setup succeeds.
|
|
329
|
-
*/
|
|
330
|
-
const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install));
|
|
331
|
-
//#endregion
|
|
332
|
-
export { apply, inject, name };
|
package/lib/types/invariant.d.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
/** Package-owned durable goal-stream invariants. @module @deepseek-ai/dsh-goal/invariant */
|
|
2
|
-
import type { Context } from '@deepseek-ai/cordis';
|
|
3
|
-
/** Cordis companion plugin name. */
|
|
4
|
-
export declare const name = "goal-invariant";
|
|
5
|
-
/** Service required before the companion can reserve package ownership. */
|
|
6
|
-
export declare const inject: string[];
|
|
7
|
-
/**
|
|
8
|
-
* Register the goal-stream invariant companion.
|
|
9
|
-
* @param ctx - Cordis context carrying the invariant service.
|
|
10
|
-
* @returns the installed registration's disposer after setup succeeds.
|
|
11
|
-
*/
|
|
12
|
-
export declare const apply: (ctx: Context) => Promise<() => void>;
|
|
13
|
-
//# sourceMappingURL=invariant.d.ts.map
|
package/lib/types/invariant.js
DELETED
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
/** Package-owned durable goal-stream invariants. @module @deepseek-ai/dsh-goal/invariant */
|
|
2
|
-
import { applyGoalEvent, emptyGoalFoldState } from "./fold.js";
|
|
3
|
-
const PACKAGE_NAME = '@deepseek-ai/dsh-goal';
|
|
4
|
-
/** Cordis companion plugin name. */
|
|
5
|
-
export const name = 'goal-invariant';
|
|
6
|
-
/** Service required before the companion can reserve package ownership. */
|
|
7
|
-
export const inject = ['invariants'];
|
|
8
|
-
/** Copy the independent fold before validating one candidate event. */
|
|
9
|
-
function cloneState(state) {
|
|
10
|
-
return {
|
|
11
|
-
goal: state.goal,
|
|
12
|
-
roundsStarted: state.roundsStarted,
|
|
13
|
-
createdAt: state.createdAt,
|
|
14
|
-
updatedAt: state.updatedAt,
|
|
15
|
-
lastRef: state.lastRef,
|
|
16
|
-
seenGoalIds: new Set(state.seenGoalIds),
|
|
17
|
-
};
|
|
18
|
-
}
|
|
19
|
-
/** Apply one event through the strict goal decoder and attribute failures. */
|
|
20
|
-
function applyChecked(state, event, fail) {
|
|
21
|
-
try {
|
|
22
|
-
applyGoalEvent(state, event);
|
|
23
|
-
}
|
|
24
|
-
catch (error) {
|
|
25
|
-
/* v8 ignore next -- the strict goal decoder throws Error instances */
|
|
26
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
27
|
-
fail(`session event ${event.seq} violates the durable goal stream: ${message}`);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
/** Install an independent incremental fold over every attached session. */
|
|
31
|
-
const install = Object.assign((ctx, fail) => {
|
|
32
|
-
const states = new WeakMap();
|
|
33
|
-
const staged = new WeakMap();
|
|
34
|
-
const seed = (session) => {
|
|
35
|
-
const state = emptyGoalFoldState();
|
|
36
|
-
// oxlint-disable-next-line typescript/no-deprecated -- Existing Session history read; migration deferred.
|
|
37
|
-
for (const event of session.snapshotEvents())
|
|
38
|
-
applyChecked(state, event, fail);
|
|
39
|
-
states.set(session, state);
|
|
40
|
-
return state;
|
|
41
|
-
};
|
|
42
|
-
/* v8 ignore next -- session/event always follows list() or session/created seeding */
|
|
43
|
-
const stateFor = (session) => states.get(session) ?? seed(session);
|
|
44
|
-
for (const session of ctx.sessions.list())
|
|
45
|
-
seed(session);
|
|
46
|
-
ctx.on('session/created', (session) => { seed(session); }, { global: true });
|
|
47
|
-
ctx.on('internal/dispatch', (_mode, eventName, args) => {
|
|
48
|
-
if (eventName !== 'session/event')
|
|
49
|
-
return;
|
|
50
|
-
const [session, event] = args;
|
|
51
|
-
const state = cloneState(stateFor(session));
|
|
52
|
-
applyChecked(state, event, fail);
|
|
53
|
-
staged.set(event, { session, state });
|
|
54
|
-
}, { global: true });
|
|
55
|
-
ctx.on('session/event', (session, event) => {
|
|
56
|
-
const candidate = staged.get(event);
|
|
57
|
-
/* v8 ignore next 2 -- internal/dispatch stages the exact callback arguments */
|
|
58
|
-
if (candidate === undefined || candidate.session !== session) {
|
|
59
|
-
return fail('session/event reached publication without matching goal-fold validation');
|
|
60
|
-
}
|
|
61
|
-
staged.delete(event);
|
|
62
|
-
states.set(session, candidate.state);
|
|
63
|
-
}, { global: true });
|
|
64
|
-
}, { inject: ['sessions'] });
|
|
65
|
-
/**
|
|
66
|
-
* Register the goal-stream invariant companion.
|
|
67
|
-
* @param ctx - Cordis context carrying the invariant service.
|
|
68
|
-
* @returns the installed registration's disposer after setup succeeds.
|
|
69
|
-
*/
|
|
70
|
-
export const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install));
|
|
71
|
-
//# sourceMappingURL=invariant.js.map
|