@cuongtran001/kanna 1.3.0 → 1.4.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/client/assets/{arc-CAysfmX5.js → arc-BHj370W7.js} +1 -1
- package/dist/client/assets/{architectureDiagram-3BPJPVTR-BKqRYsm4.js → architectureDiagram-3BPJPVTR-1G88q1PY.js} +1 -1
- package/dist/client/assets/{blockDiagram-GPEHLZMM-Ce7Eorec.js → blockDiagram-GPEHLZMM-D0L3Co5v.js} +1 -1
- package/dist/client/assets/{c4Diagram-AAUBKEIU-CJ77zauH.js → c4Diagram-AAUBKEIU-CQtERl3H.js} +1 -1
- package/dist/client/assets/channel-BP9IMEvd.js +1 -0
- package/dist/client/assets/{chunk-2J33WTMH-Rk_3zLxJ.js → chunk-2J33WTMH-DxOwt09f.js} +1 -1
- package/dist/client/assets/{chunk-4BX2VUAB-DPIz6Nvf.js → chunk-4BX2VUAB-Wry66y9R.js} +1 -1
- package/dist/client/assets/{chunk-55IACEB6-D-TkbGh2.js → chunk-55IACEB6-D6p-Hi4x.js} +1 -1
- package/dist/client/assets/{chunk-727SXJPM-B4NOSIZV.js → chunk-727SXJPM-CRQZt23N.js} +1 -1
- package/dist/client/assets/{chunk-AQP2D5EJ-Cm_TGLYm.js → chunk-AQP2D5EJ-BzgTKOM9.js} +1 -1
- package/dist/client/assets/{chunk-FMBD7UC4-Bu45BUVh.js → chunk-FMBD7UC4-CKfD-91C.js} +1 -1
- package/dist/client/assets/{chunk-ND2GUHAM-C1Bw8_gg.js → chunk-ND2GUHAM-a71B27wc.js} +1 -1
- package/dist/client/assets/{chunk-QZHKN3VN-DueG15o0.js → chunk-QZHKN3VN-vv9gJwx0.js} +1 -1
- package/dist/client/assets/classDiagram-4FO5ZUOK--W6Wt7FF.js +1 -0
- package/dist/client/assets/classDiagram-v2-Q7XG4LA2--W6Wt7FF.js +1 -0
- package/dist/client/assets/{cose-bilkent-S5V4N54A-YgpMurXf.js → cose-bilkent-S5V4N54A-Cu-dCCaI.js} +1 -1
- package/dist/client/assets/{dagre-BM42HDAG-Dop7Oq67.js → dagre-BM42HDAG-D8coOWLK.js} +1 -1
- package/dist/client/assets/{diagram-2AECGRRQ-unMfBEJH.js → diagram-2AECGRRQ-NIwZ65jE.js} +1 -1
- package/dist/client/assets/{diagram-5GNKFQAL-D9EJ9qMI.js → diagram-5GNKFQAL-d46aE_le.js} +1 -1
- package/dist/client/assets/{diagram-KO2AKTUF-C5IykOIR.js → diagram-KO2AKTUF-xdm2UxWc.js} +1 -1
- package/dist/client/assets/{diagram-LMA3HP47-DJAuPngz.js → diagram-LMA3HP47-hDbLwC5K.js} +1 -1
- package/dist/client/assets/{diagram-OG6HWLK6-B3wHFtS-.js → diagram-OG6HWLK6-MHUGG7ki.js} +1 -1
- package/dist/client/assets/{erDiagram-TEJ5UH35-Dm7kt9o5.js → erDiagram-TEJ5UH35-Ro6n9X70.js} +1 -1
- package/dist/client/assets/{flowDiagram-I6XJVG4X-s9Lds3ny.js → flowDiagram-I6XJVG4X-DOZqvRMu.js} +1 -1
- package/dist/client/assets/{ganttDiagram-6RSMTGT7-CRQNYdAf.js → ganttDiagram-6RSMTGT7-Bn2NXYIy.js} +1 -1
- package/dist/client/assets/{gitGraphDiagram-PVQCEYII-DhYjK4Jb.js → gitGraphDiagram-PVQCEYII-DK44bfbC.js} +1 -1
- package/dist/client/assets/{index-C0U2kwuB.js → index-CWJpHyQy.js} +115 -115
- package/dist/client/assets/{index-CLsOWXff.css → index-Cyzd4zZx.css} +1 -1
- package/dist/client/assets/{index-CbSY9HfS.js → index-DU56d4oC.js} +1 -1
- package/dist/client/assets/{infoDiagram-5YYISTIA-CRKJ0PSH.js → infoDiagram-5YYISTIA-C2tW_Dwj.js} +1 -1
- package/dist/client/assets/{ishikawaDiagram-YF4QCWOH-CEAkB0IY.js → ishikawaDiagram-YF4QCWOH-C__4Z1wz.js} +1 -1
- package/dist/client/assets/{journeyDiagram-JHISSGLW-CyOK5_DG.js → journeyDiagram-JHISSGLW-Bbn5EawR.js} +1 -1
- package/dist/client/assets/{kanban-definition-UN3LZRKU-BfKjiJSo.js → kanban-definition-UN3LZRKU-RgS5IRWl.js} +1 -1
- package/dist/client/assets/{linear-DLR6miy3.js → linear-DfI0qBO_.js} +1 -1
- package/dist/client/assets/{mermaid.core-D7AdC_lE.js → mermaid.core-BiN10VHc.js} +4 -4
- package/dist/client/assets/{mindmap-definition-RKZ34NQL-zYyJtDSa.js → mindmap-definition-RKZ34NQL-BQhibhh3.js} +1 -1
- package/dist/client/assets/{pieDiagram-4H26LBE5-BgP8PFlo.js → pieDiagram-4H26LBE5-BEfLRn7a.js} +1 -1
- package/dist/client/assets/{quadrantDiagram-W4KKPZXB-Di8h7J96.js → quadrantDiagram-W4KKPZXB-ba641Y2x.js} +1 -1
- package/dist/client/assets/{requirementDiagram-4Y6WPE33-DuTzFl3R.js → requirementDiagram-4Y6WPE33-BGtl-tVO.js} +1 -1
- package/dist/client/assets/{sankeyDiagram-5OEKKPKP-DBRoMm_T.js → sankeyDiagram-5OEKKPKP-DyziaSFr.js} +1 -1
- package/dist/client/assets/{sequenceDiagram-3UESZ5HK-Bmb-1HUN.js → sequenceDiagram-3UESZ5HK-BfYBAYga.js} +1 -1
- package/dist/client/assets/{stateDiagram-AJRCARHV-fnv5ayn-.js → stateDiagram-AJRCARHV-BfUfmLYA.js} +1 -1
- package/dist/client/assets/stateDiagram-v2-BHNVJYJU-CdGcgYEq.js +1 -0
- package/dist/client/assets/{timeline-definition-PNZ67QCA-ByWRdpQX.js → timeline-definition-PNZ67QCA-T6z7dEFl.js} +1 -1
- package/dist/client/assets/{vennDiagram-CIIHVFJN--2WGpVXW.js → vennDiagram-CIIHVFJN-BAwQbFFd.js} +1 -1
- package/dist/client/assets/{wardley-L42UT6IY-24zlnzxK.js → wardley-L42UT6IY-DF1cRKsP.js} +1 -1
- package/dist/client/assets/{wardleyDiagram-YWT4CUSO-Cllvqb3K.js → wardleyDiagram-YWT4CUSO-BRtAZ8za.js} +1 -1
- package/dist/client/assets/{xychartDiagram-2RQKCTM6-ZcdC6nPE.js → xychartDiagram-2RQKCTM6-Brb-q76h.js} +1 -1
- package/dist/client/index.html +2 -2
- package/package.json +1 -1
- package/src/server/agent-coordinator-types.ts +158 -0
- package/src/server/agent-coordinator.ts +919 -0
- package/src/server/agent-deps-builders.ts +425 -0
- package/src/server/agent.test.ts +22 -6
- package/src/server/agent.ts +35 -4987
- package/src/server/chat-op-log.test.ts +63 -0
- package/src/server/chat-op-log.ts +71 -0
- package/src/server/chat-ops-diff.test.ts +120 -0
- package/src/server/chat-ops-diff.ts +97 -0
- package/src/server/chat-ops-parity.test.ts +140 -0
- package/src/server/claude-autocontinue-commands.test.ts +494 -0
- package/src/server/claude-autocontinue-commands.ts +256 -0
- package/src/server/claude-cancel-handler.test.ts +472 -0
- package/src/server/claude-cancel-handler.ts +241 -0
- package/src/server/claude-chat-management.test.ts +395 -0
- package/src/server/claude-chat-management.ts +251 -0
- package/src/server/claude-harness-stream.test.ts +273 -0
- package/src/server/claude-harness-stream.ts +158 -0
- package/src/server/claude-loop-orch-commands.test.ts +579 -0
- package/src/server/claude-loop-orch-commands.ts +466 -0
- package/src/server/claude-message-normalizer.test.ts +213 -0
- package/src/server/claude-message-normalizer.ts +436 -0
- package/src/server/claude-prompt-helpers.test.ts +248 -0
- package/src/server/claude-prompt-helpers.ts +139 -0
- package/src/server/claude-sdk-queue.test.ts +169 -0
- package/src/server/claude-sdk-queue.ts +82 -0
- package/src/server/claude-send-command.test.ts +414 -0
- package/src/server/claude-send-command.ts +420 -0
- package/src/server/claude-session-config-helpers.test.ts +279 -0
- package/src/server/claude-session-config-helpers.ts +151 -0
- package/src/server/claude-session-config.test.ts +250 -0
- package/src/server/claude-session-config.ts +159 -0
- package/src/server/claude-session-error-handler.test.ts +498 -0
- package/src/server/claude-session-error-handler.ts +361 -0
- package/src/server/claude-session-lifecycle.test.ts +669 -0
- package/src/server/claude-session-lifecycle.ts +283 -0
- package/src/server/claude-session-rebuild.test.ts +224 -0
- package/src/server/claude-session-rebuild.ts +101 -0
- package/src/server/claude-session-runner.test.ts +523 -0
- package/src/server/claude-session-runner.ts +521 -0
- package/src/server/claude-session-spawner.test.ts +401 -0
- package/src/server/claude-session-spawner.ts +401 -0
- package/src/server/claude-session-start.test.ts +205 -0
- package/src/server/claude-session-start.ts +277 -0
- package/src/server/claude-session-state-queries.test.ts +344 -0
- package/src/server/claude-session-state-queries.ts +160 -0
- package/src/server/claude-session-state.ts +104 -0
- package/src/server/claude-slash-commands.test.ts +277 -0
- package/src/server/claude-slash-commands.ts +234 -0
- package/src/server/claude-spawn-helpers.test.ts +221 -0
- package/src/server/claude-spawn-helpers.ts +179 -0
- package/src/server/claude-steer-log.test.ts +243 -0
- package/src/server/claude-steer-log.ts +58 -0
- package/src/server/claude-subagent-tool-response.test.ts +213 -0
- package/src/server/claude-subagent-tool-response.ts +165 -0
- package/src/server/claude-subagent-wiring.test.ts +263 -0
- package/src/server/claude-subagent-wiring.ts +324 -0
- package/src/server/claude-tool-respond.test.ts +321 -0
- package/src/server/claude-tool-respond.ts +142 -0
- package/src/server/claude-turn-runner.test.ts +310 -0
- package/src/server/claude-turn-runner.ts +228 -0
- package/src/server/claude-turn-starter.test.ts +266 -0
- package/src/server/claude-turn-starter.ts +566 -0
- package/src/server/claude-usage-math.test.ts +169 -0
- package/src/server/claude-usage-math.ts +132 -0
- package/src/server/diff-store-branch-ops.adapter.test.ts +332 -0
- package/src/server/diff-store-branch-ops.adapter.ts +602 -0
- package/src/server/diff-store-commit-ops.adapter.test.ts +358 -0
- package/src/server/diff-store-commit-ops.adapter.ts +258 -0
- package/src/server/diff-store-errors.ts +85 -0
- package/src/server/diff-store-file-ops.adapter.ts +212 -0
- package/src/server/diff-store-git-branch.adapter.ts +686 -0
- package/src/server/diff-store-io.adapter.ts +27 -0
- package/src/server/diff-store-parse.test.ts +212 -0
- package/src/server/diff-store-parse.ts +122 -0
- package/src/server/diff-store-state.ts +82 -0
- package/src/server/diff-store.ts +76 -1854
- package/src/server/event-store-apply.test.ts +280 -0
- package/src/server/event-store-apply.ts +132 -0
- package/src/server/event-store-chat-lifecycle.test.ts +408 -0
- package/src/server/event-store-chat-lifecycle.ts +441 -0
- package/src/server/event-store-entity-write.ts +356 -0
- package/src/server/event-store-helpers.test.ts +230 -0
- package/src/server/event-store-helpers.ts +235 -0
- package/src/server/event-store-init.ts +276 -0
- package/src/server/event-store-messages.adapter.test.ts +532 -0
- package/src/server/event-store-messages.adapter.ts +455 -0
- package/src/server/event-store-orch-subscription.ts +124 -0
- package/src/server/event-store-orch.test.ts +462 -0
- package/src/server/event-store-orch.ts +312 -0
- package/src/server/event-store-peripheral-events.adapter.test.ts +254 -0
- package/src/server/event-store-peripheral-events.adapter.ts +105 -0
- package/src/server/event-store-snapshot.test.ts +597 -0
- package/src/server/event-store-snapshot.ts +658 -0
- package/src/server/event-store-subagent.test.ts +408 -0
- package/src/server/event-store-subagent.ts +198 -0
- package/src/server/event-store-tool-requests.test.ts +210 -0
- package/src/server/event-store-tool-requests.ts +131 -0
- package/src/server/event-store-transcript-write.adapter.ts +291 -0
- package/src/server/event-store-write-ops.test.ts +554 -0
- package/src/server/event-store-write-ops.ts +529 -0
- package/src/server/event-store.test.ts +75 -0
- package/src/server/event-store.ts +257 -2285
- package/src/server/events.ts +1 -1
- package/src/server/harness-types.ts +15 -1
- package/src/server/oauth-errors.ts +19 -0
- package/src/server/storage/backend.ts +7 -0
- package/src/server/storage/fs-storage.adapter.ts +21 -1
- package/src/server/storage/in-memory-storage.ts +12 -0
- package/src/server/ws-router-agent-ctrl.test.ts +187 -0
- package/src/server/ws-router-agent-ctrl.ts +137 -0
- package/src/server/ws-router-broadcast.ts +560 -0
- package/src/server/ws-router-chat.test.ts +461 -0
- package/src/server/ws-router-chat.ts +279 -0
- package/src/server/ws-router-defaults.test.ts +283 -0
- package/src/server/ws-router-defaults.ts +434 -0
- package/src/server/ws-router-diff.test.ts +167 -0
- package/src/server/ws-router-diff.ts +250 -0
- package/src/server/ws-router-envelope.ts +360 -0
- package/src/server/ws-router-misc.test.ts +422 -0
- package/src/server/ws-router-misc.ts +265 -0
- package/src/server/ws-router-orch.test.ts +190 -0
- package/src/server/ws-router-orch.ts +93 -0
- package/src/server/ws-router-project.test.ts +403 -0
- package/src/server/ws-router-project.ts +256 -0
- package/src/server/ws-router-push.test.ts +193 -0
- package/src/server/ws-router-push.ts +120 -0
- package/src/server/ws-router-settings.test.ts +173 -0
- package/src/server/ws-router-settings.ts +416 -0
- package/src/server/ws-router-skills.test.ts +194 -0
- package/src/server/ws-router-skills.ts +204 -0
- package/src/server/ws-router-utils.ts +238 -0
- package/src/server/ws-router.test.ts +90 -0
- package/src/server/ws-router.ts +340 -2254
- package/src/shared/app-settings-types.ts +365 -0
- package/src/shared/chat-ops.test.ts +138 -0
- package/src/shared/chat-ops.ts +71 -0
- package/src/shared/core-types.ts +27 -0
- package/src/shared/git-diff-types.ts +165 -0
- package/src/shared/mcp-types.ts +105 -0
- package/src/shared/protocol.ts +3 -2
- package/src/shared/provider-model-types.ts +437 -0
- package/src/shared/subagent-types.ts +198 -0
- package/src/shared/tool-call-types.ts +314 -0
- package/src/shared/transcript-types.ts +270 -0
- package/src/shared/types.ts +31 -1711
- package/dist/client/assets/channel-KQhRwDzJ.js +0 -1
- package/dist/client/assets/classDiagram-4FO5ZUOK-ChxT1GNq.js +0 -1
- package/dist/client/assets/classDiagram-v2-Q7XG4LA2-ChxT1GNq.js +0 -1
- package/dist/client/assets/stateDiagram-v2-BHNVJYJU-D4X-ZnLV.js +0 -1
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test"
|
|
2
|
+
import { STORE_VERSION } from "../shared/types"
|
|
3
|
+
import type { ToolRequest } from "../shared/permission-policy"
|
|
4
|
+
import { AUTO_CONTINUE_EVENT_VERSION } from "./auto-continue/events"
|
|
5
|
+
import type { AutoContinueEvent } from "./auto-continue/events"
|
|
6
|
+
import { createEmptyState } from "./events"
|
|
7
|
+
import type { TranscriptEntry } from "../shared/types"
|
|
8
|
+
import { applyStoreEvent } from "./event-store-apply"
|
|
9
|
+
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
// Helpers
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
|
|
14
|
+
const TS = 1_700_000_000_000
|
|
15
|
+
|
|
16
|
+
function makeState() {
|
|
17
|
+
return createEmptyState()
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function makeBaseChat() {
|
|
21
|
+
return {
|
|
22
|
+
id: "chat-1",
|
|
23
|
+
projectId: "proj-1",
|
|
24
|
+
title: "C",
|
|
25
|
+
createdAt: TS,
|
|
26
|
+
updatedAt: TS,
|
|
27
|
+
unread: false,
|
|
28
|
+
provider: null as null,
|
|
29
|
+
planMode: false,
|
|
30
|
+
sessionTokensByProvider: {} as Record<string, string | null>,
|
|
31
|
+
sourceHash: null as null,
|
|
32
|
+
pendingForkSessionToken: null as null,
|
|
33
|
+
hasMessages: false,
|
|
34
|
+
lastTurnOutcome: null as null,
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function makeToolRequest(): ToolRequest {
|
|
39
|
+
return {
|
|
40
|
+
id: "req-1",
|
|
41
|
+
chatId: "chat-1",
|
|
42
|
+
sessionId: "sess-1",
|
|
43
|
+
toolUseId: "tool-use-1",
|
|
44
|
+
toolName: "AskUserQuestion",
|
|
45
|
+
arguments: {},
|
|
46
|
+
canonicalArgsHash: "hash",
|
|
47
|
+
policyVerdict: "ask",
|
|
48
|
+
status: "pending",
|
|
49
|
+
createdAt: TS,
|
|
50
|
+
expiresAt: TS + 600_000,
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// ---------------------------------------------------------------------------
|
|
55
|
+
// Project events
|
|
56
|
+
// ---------------------------------------------------------------------------
|
|
57
|
+
|
|
58
|
+
describe("applyStoreEvent — project events", () => {
|
|
59
|
+
test("project_opened populates projectsById and projectIdsByPath", () => {
|
|
60
|
+
const state = makeState()
|
|
61
|
+
applyStoreEvent(
|
|
62
|
+
{
|
|
63
|
+
v: STORE_VERSION,
|
|
64
|
+
type: "project_opened",
|
|
65
|
+
timestamp: TS,
|
|
66
|
+
projectId: "proj-1",
|
|
67
|
+
localPath: "/tmp/repo",
|
|
68
|
+
title: "Repo",
|
|
69
|
+
},
|
|
70
|
+
state,
|
|
71
|
+
new Map(),
|
|
72
|
+
new Map(),
|
|
73
|
+
)
|
|
74
|
+
expect(state.projectsById.has("proj-1")).toBe(true)
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
test("project_removed soft-deletes", () => {
|
|
78
|
+
const state = makeState()
|
|
79
|
+
state.projectsById.set("proj-1", {
|
|
80
|
+
id: "proj-1", localPath: "/tmp/repo", title: "R", createdAt: TS, updatedAt: TS,
|
|
81
|
+
})
|
|
82
|
+
state.projectIdsByPath.set("/tmp/repo", "proj-1")
|
|
83
|
+
applyStoreEvent(
|
|
84
|
+
{ v: STORE_VERSION, type: "project_removed", timestamp: TS + 1, projectId: "proj-1" },
|
|
85
|
+
state,
|
|
86
|
+
new Map(),
|
|
87
|
+
new Map(),
|
|
88
|
+
)
|
|
89
|
+
expect(state.projectsById.get("proj-1")?.deletedAt).toBeDefined()
|
|
90
|
+
})
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
// ---------------------------------------------------------------------------
|
|
94
|
+
// Chat lifecycle events
|
|
95
|
+
// ---------------------------------------------------------------------------
|
|
96
|
+
|
|
97
|
+
describe("applyStoreEvent — chat events", () => {
|
|
98
|
+
test("chat_created populates chatsById and chatTimingsByChatId", () => {
|
|
99
|
+
const state = makeState()
|
|
100
|
+
applyStoreEvent(
|
|
101
|
+
{
|
|
102
|
+
v: STORE_VERSION,
|
|
103
|
+
type: "chat_created",
|
|
104
|
+
timestamp: TS,
|
|
105
|
+
chatId: "chat-1",
|
|
106
|
+
projectId: "proj-1",
|
|
107
|
+
title: "New Chat",
|
|
108
|
+
},
|
|
109
|
+
state,
|
|
110
|
+
new Map(),
|
|
111
|
+
new Map(),
|
|
112
|
+
)
|
|
113
|
+
expect(state.chatsById.has("chat-1")).toBe(true)
|
|
114
|
+
expect(state.chatTimingsByChatId.has("chat-1")).toBe(true)
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
test("chat_renamed updates title", () => {
|
|
118
|
+
const state = makeState()
|
|
119
|
+
state.chatsById.set("chat-1", makeBaseChat())
|
|
120
|
+
applyStoreEvent(
|
|
121
|
+
{ v: STORE_VERSION, type: "chat_renamed", timestamp: TS + 1, chatId: "chat-1", title: "New" },
|
|
122
|
+
state,
|
|
123
|
+
new Map(),
|
|
124
|
+
new Map(),
|
|
125
|
+
)
|
|
126
|
+
expect(state.chatsById.get("chat-1")?.title).toBe("New")
|
|
127
|
+
})
|
|
128
|
+
|
|
129
|
+
test("chat_provider_set updates provider in chatsById and replayChatProvider", () => {
|
|
130
|
+
const state = makeState()
|
|
131
|
+
state.chatsById.set("chat-1", makeBaseChat())
|
|
132
|
+
const replay = new Map<string, "claude" | null>([["chat-1", null]])
|
|
133
|
+
applyStoreEvent(
|
|
134
|
+
{ v: STORE_VERSION, type: "chat_provider_set", timestamp: TS + 1, chatId: "chat-1", provider: "claude" },
|
|
135
|
+
state,
|
|
136
|
+
new Map(),
|
|
137
|
+
replay,
|
|
138
|
+
)
|
|
139
|
+
expect(state.chatsById.get("chat-1")?.provider).toBe("claude")
|
|
140
|
+
expect(replay.get("chat-1")).toBe("claude")
|
|
141
|
+
})
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
// ---------------------------------------------------------------------------
|
|
145
|
+
// message_appended
|
|
146
|
+
// ---------------------------------------------------------------------------
|
|
147
|
+
|
|
148
|
+
describe("applyStoreEvent — message_appended", () => {
|
|
149
|
+
test("appends to legacyMessagesByChatId and marks hasMessages", () => {
|
|
150
|
+
const state = makeState()
|
|
151
|
+
state.chatsById.set("chat-1", makeBaseChat())
|
|
152
|
+
const legacy = new Map<string, TranscriptEntry[]>()
|
|
153
|
+
applyStoreEvent(
|
|
154
|
+
{
|
|
155
|
+
v: STORE_VERSION,
|
|
156
|
+
type: "message_appended",
|
|
157
|
+
timestamp: TS,
|
|
158
|
+
chatId: "chat-1",
|
|
159
|
+
entry: { kind: "user_prompt", content: "hello", createdAt: TS, _id: "entry-1" } as TranscriptEntry,
|
|
160
|
+
},
|
|
161
|
+
state,
|
|
162
|
+
legacy,
|
|
163
|
+
new Map(),
|
|
164
|
+
)
|
|
165
|
+
expect(legacy.get("chat-1")?.length).toBe(1)
|
|
166
|
+
expect(state.chatsById.get("chat-1")?.hasMessages).toBe(true)
|
|
167
|
+
})
|
|
168
|
+
|
|
169
|
+
test("multiple appends accumulate entries", () => {
|
|
170
|
+
const state = makeState()
|
|
171
|
+
state.chatsById.set("chat-1", makeBaseChat())
|
|
172
|
+
const legacy = new Map<string, TranscriptEntry[]>()
|
|
173
|
+
for (let i = 0; i < 3; i++) {
|
|
174
|
+
applyStoreEvent(
|
|
175
|
+
{
|
|
176
|
+
v: STORE_VERSION,
|
|
177
|
+
type: "message_appended",
|
|
178
|
+
timestamp: TS + i,
|
|
179
|
+
chatId: "chat-1",
|
|
180
|
+
entry: {
|
|
181
|
+
kind: "user_prompt",
|
|
182
|
+
content: `msg-${i}`,
|
|
183
|
+
createdAt: TS + i,
|
|
184
|
+
_id: `entry-${i}`,
|
|
185
|
+
} as TranscriptEntry,
|
|
186
|
+
},
|
|
187
|
+
state,
|
|
188
|
+
legacy,
|
|
189
|
+
new Map(),
|
|
190
|
+
)
|
|
191
|
+
}
|
|
192
|
+
expect(legacy.get("chat-1")?.length).toBe(3)
|
|
193
|
+
})
|
|
194
|
+
})
|
|
195
|
+
|
|
196
|
+
// ---------------------------------------------------------------------------
|
|
197
|
+
// Stack events
|
|
198
|
+
// ---------------------------------------------------------------------------
|
|
199
|
+
|
|
200
|
+
describe("applyStoreEvent — stack events", () => {
|
|
201
|
+
test("stack_added creates a stack", () => {
|
|
202
|
+
const state = makeState()
|
|
203
|
+
applyStoreEvent(
|
|
204
|
+
{
|
|
205
|
+
v: STORE_VERSION,
|
|
206
|
+
type: "stack_added",
|
|
207
|
+
timestamp: TS,
|
|
208
|
+
stackId: "stack-1",
|
|
209
|
+
title: "My Stack",
|
|
210
|
+
projectIds: ["proj-1", "proj-2"],
|
|
211
|
+
},
|
|
212
|
+
state,
|
|
213
|
+
new Map(),
|
|
214
|
+
new Map(),
|
|
215
|
+
)
|
|
216
|
+
expect(state.stacksById.has("stack-1")).toBe(true)
|
|
217
|
+
const stack = state.stacksById.get("stack-1")
|
|
218
|
+
if (stack) {
|
|
219
|
+
expect(stack.title).toBe("My Stack")
|
|
220
|
+
}
|
|
221
|
+
})
|
|
222
|
+
|
|
223
|
+
test("stack_removed soft-deletes", () => {
|
|
224
|
+
const state = makeState()
|
|
225
|
+
state.stacksById.set("stack-1", {
|
|
226
|
+
id: "stack-1", title: "S", projectIds: ["p1", "p2"], createdAt: TS, updatedAt: TS,
|
|
227
|
+
})
|
|
228
|
+
applyStoreEvent(
|
|
229
|
+
{ v: STORE_VERSION, type: "stack_removed", timestamp: TS + 1, stackId: "stack-1" },
|
|
230
|
+
state,
|
|
231
|
+
new Map(),
|
|
232
|
+
new Map(),
|
|
233
|
+
)
|
|
234
|
+
expect(state.stacksById.get("stack-1")?.deletedAt).toBeDefined()
|
|
235
|
+
})
|
|
236
|
+
})
|
|
237
|
+
|
|
238
|
+
// ---------------------------------------------------------------------------
|
|
239
|
+
// Auto-continue events (kind-based dispatch)
|
|
240
|
+
// ---------------------------------------------------------------------------
|
|
241
|
+
|
|
242
|
+
describe("applyStoreEvent — auto-continue events", () => {
|
|
243
|
+
test("auto_continue_accepted is routed to autoContinueEventsByChatId", () => {
|
|
244
|
+
const state = makeState()
|
|
245
|
+
const event: AutoContinueEvent = {
|
|
246
|
+
v: AUTO_CONTINUE_EVENT_VERSION,
|
|
247
|
+
kind: "auto_continue_accepted",
|
|
248
|
+
chatId: "chat-1",
|
|
249
|
+
scheduleId: "sched-1",
|
|
250
|
+
timestamp: TS,
|
|
251
|
+
scheduledAt: TS,
|
|
252
|
+
tz: "UTC",
|
|
253
|
+
source: "subagent_background",
|
|
254
|
+
resetAt: TS + 60_000,
|
|
255
|
+
detectedAt: TS - 1_000,
|
|
256
|
+
prompt: "do next thing",
|
|
257
|
+
}
|
|
258
|
+
applyStoreEvent(event, state, new Map(), new Map())
|
|
259
|
+
expect(state.autoContinueEventsByChatId.has("chat-1")).toBe(true)
|
|
260
|
+
expect(state.autoContinueEventsByChatId.get("chat-1")?.length).toBe(1)
|
|
261
|
+
})
|
|
262
|
+
})
|
|
263
|
+
|
|
264
|
+
// ---------------------------------------------------------------------------
|
|
265
|
+
// Tool-request events
|
|
266
|
+
// ---------------------------------------------------------------------------
|
|
267
|
+
|
|
268
|
+
describe("applyStoreEvent — tool request events", () => {
|
|
269
|
+
test("tool_request_put adds to toolRequestsById", () => {
|
|
270
|
+
const state = makeState()
|
|
271
|
+
const req = makeToolRequest()
|
|
272
|
+
applyStoreEvent(
|
|
273
|
+
{ v: STORE_VERSION, type: "tool_request_put", timestamp: TS, request: req },
|
|
274
|
+
state,
|
|
275
|
+
new Map(),
|
|
276
|
+
new Map(),
|
|
277
|
+
)
|
|
278
|
+
expect(state.toolRequestsById.has("req-1")).toBe(true)
|
|
279
|
+
})
|
|
280
|
+
})
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure event dispatch — applies any StoreEvent to the in-memory state.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from EventStore.applyEvent() to reduce event-store.ts file size.
|
|
5
|
+
* All functions are pure state mutations — no IO, no side effects
|
|
6
|
+
* (side-effect seal: IO lives in *.adapter.ts files).
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { AgentProvider, TranscriptEntry } from "../shared/types"
|
|
10
|
+
import type { AutoContinueEvent } from "./auto-continue/events"
|
|
11
|
+
import type { StoreEvent, StoreState } from "./events"
|
|
12
|
+
import {
|
|
13
|
+
applyChatLifecycleEvent,
|
|
14
|
+
applyChatMessageMetadata,
|
|
15
|
+
applyAutoContinueToState,
|
|
16
|
+
applyProjectEvent,
|
|
17
|
+
applyStackEvent,
|
|
18
|
+
} from "./event-store-chat-lifecycle"
|
|
19
|
+
import { applySubagentEvent } from "./event-store-subagent"
|
|
20
|
+
import { applyToolRequestEvent } from "./event-store-tool-requests"
|
|
21
|
+
import { applyOrchEvent } from "./event-store-orch"
|
|
22
|
+
|
|
23
|
+
function isAutoContinueEvent(event: StoreEvent): event is AutoContinueEvent {
|
|
24
|
+
return "kind" in event
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Apply a single StoreEvent to the full in-memory state.
|
|
29
|
+
*
|
|
30
|
+
* @param event - the event to apply
|
|
31
|
+
* @param state - full StoreState (mutated in-place)
|
|
32
|
+
* @param legacyMessagesByChatId - legacy transcript store (mutated for `message_appended`)
|
|
33
|
+
* @param replayChatProvider - provider-replay tracking map
|
|
34
|
+
*/
|
|
35
|
+
export function applyStoreEvent(
|
|
36
|
+
event: StoreEvent,
|
|
37
|
+
state: StoreState,
|
|
38
|
+
legacyMessagesByChatId: Map<string, TranscriptEntry[]>,
|
|
39
|
+
replayChatProvider: Map<string, AgentProvider | null>,
|
|
40
|
+
): void {
|
|
41
|
+
if (isAutoContinueEvent(event)) {
|
|
42
|
+
applyAutoContinueToState(state.autoContinueEventsByChatId, event)
|
|
43
|
+
return
|
|
44
|
+
}
|
|
45
|
+
const e: Exclude<StoreEvent, AutoContinueEvent> = event
|
|
46
|
+
switch (e.type) {
|
|
47
|
+
case "project_opened":
|
|
48
|
+
case "project_removed":
|
|
49
|
+
case "sidebar_project_order_set":
|
|
50
|
+
case "project_star_set": {
|
|
51
|
+
applyProjectEvent(state, e)
|
|
52
|
+
break
|
|
53
|
+
}
|
|
54
|
+
case "chat_created":
|
|
55
|
+
case "chat_renamed":
|
|
56
|
+
case "chat_deleted":
|
|
57
|
+
case "chat_archived":
|
|
58
|
+
case "chat_unarchived":
|
|
59
|
+
case "chat_provider_set":
|
|
60
|
+
case "chat_plan_mode_set":
|
|
61
|
+
case "chat_read_state_set":
|
|
62
|
+
case "chat_source_hash_set":
|
|
63
|
+
case "chat_policy_override_set":
|
|
64
|
+
case "chat_compact_failures_set": {
|
|
65
|
+
applyChatLifecycleEvent(state, replayChatProvider, e)
|
|
66
|
+
break
|
|
67
|
+
}
|
|
68
|
+
case "message_appended": {
|
|
69
|
+
applyChatMessageMetadata(state.chatsById, e.chatId, e.entry)
|
|
70
|
+
const existing = legacyMessagesByChatId.get(e.chatId) ?? []
|
|
71
|
+
existing.push({ ...e.entry })
|
|
72
|
+
legacyMessagesByChatId.set(e.chatId, existing)
|
|
73
|
+
break
|
|
74
|
+
}
|
|
75
|
+
case "queued_message_enqueued":
|
|
76
|
+
case "queued_message_removed":
|
|
77
|
+
case "turn_started":
|
|
78
|
+
case "turn_finished":
|
|
79
|
+
case "turn_failed":
|
|
80
|
+
case "turn_cancelled":
|
|
81
|
+
case "session_token_set":
|
|
82
|
+
case "session_commands_loaded":
|
|
83
|
+
case "pending_fork_session_token_set": {
|
|
84
|
+
applyChatLifecycleEvent(state, replayChatProvider, e)
|
|
85
|
+
break
|
|
86
|
+
}
|
|
87
|
+
case "stack_added":
|
|
88
|
+
case "stack_removed":
|
|
89
|
+
case "stack_renamed":
|
|
90
|
+
case "stack_project_added":
|
|
91
|
+
case "stack_project_removed": {
|
|
92
|
+
applyStackEvent(state.stacksById, e)
|
|
93
|
+
break
|
|
94
|
+
}
|
|
95
|
+
case "subagent_run_started":
|
|
96
|
+
case "subagent_message_delta":
|
|
97
|
+
case "subagent_entry_appended":
|
|
98
|
+
case "subagent_run_completed":
|
|
99
|
+
case "subagent_run_failed":
|
|
100
|
+
case "subagent_run_cancelled":
|
|
101
|
+
case "subagent_tool_pending":
|
|
102
|
+
case "subagent_tool_resolved": {
|
|
103
|
+
applySubagentEvent(state.subagentRunsByChatId, e)
|
|
104
|
+
break
|
|
105
|
+
}
|
|
106
|
+
case "tool_request_put":
|
|
107
|
+
case "tool_request_resolved": {
|
|
108
|
+
applyToolRequestEvent(state.toolRequestsById, e)
|
|
109
|
+
break
|
|
110
|
+
}
|
|
111
|
+
case "orch_run_created":
|
|
112
|
+
case "orch_worktree_provisioned":
|
|
113
|
+
case "orch_worktree_init_started":
|
|
114
|
+
case "orch_worktree_init_completed":
|
|
115
|
+
case "orch_task_claimed":
|
|
116
|
+
case "orch_phase_started":
|
|
117
|
+
case "orch_phase_completed":
|
|
118
|
+
case "orch_gate_opened":
|
|
119
|
+
case "orch_gate_resolved":
|
|
120
|
+
case "orch_scope_overlap_flagged":
|
|
121
|
+
case "orch_config_warning":
|
|
122
|
+
case "orch_verify_started":
|
|
123
|
+
case "orch_verify_completed":
|
|
124
|
+
case "orch_task_committed":
|
|
125
|
+
case "orch_task_failed":
|
|
126
|
+
case "orch_task_requeued":
|
|
127
|
+
case "orch_run_completed":
|
|
128
|
+
case "orch_run_cancelled":
|
|
129
|
+
applyOrchEvent(state.orchRunsById, e)
|
|
130
|
+
break
|
|
131
|
+
}
|
|
132
|
+
}
|