dsh-plugin-message-edit 1.0.0 → 1.1.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/LICENSE +24 -24
- package/README.en.md +18 -3
- package/README.md +14 -3
- package/cordis.patch.yml +7 -7
- package/docs/ARCHITECTURE.md +167 -155
- package/docs/DEVELOPMENT.md +143 -71
- package/docs/TREE_DATA_MODEL.md +96 -96
- package/lib/client.js +1666 -1642
- package/lib/index.js +832 -823
- package/lib/session-record.js +52 -0
- package/lib/tree-logic.js +343 -343
- package/package.json +22 -3
- package/plugin.client.js +1666 -1642
package/docs/DEVELOPMENT.md
CHANGED
|
@@ -1,75 +1,147 @@
|
|
|
1
|
-
# Development & Testing Guide
|
|
1
|
+
# Development & Testing Guide
|
|
2
|
+
|
|
3
|
+
This guide covers building, testing, packaging, and installing `dsh-plugin-message-edit`.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. Repository Structure
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
dsh-plugin-message-edit/
|
|
11
|
+
├── lib/
|
|
12
|
+
│ ├── index.js # Host-side Cordis plugin (routes, session log processing)
|
|
13
|
+
│ ├── tree-logic.js # Pure tree algorithms (shared with client and tests)
|
|
14
|
+
│ └── client.js # Generated client bundle (wrapped from plugin.client.js)
|
|
15
|
+
├── plugin.client.js # Source client-side UI and React components
|
|
16
|
+
├── scripts/
|
|
17
|
+
│ └── build-client.mjs # Build script wrapping plugin.client.js into lib/client.js
|
|
18
|
+
├── test/
|
|
19
|
+
│ └── tree.test.mjs # Automated test suite (36+ unit tests)
|
|
20
|
+
├── cordis.patch.yml # Service dependencies and injection metadata
|
|
21
|
+
├── docs/ # Technical architecture and data model documentation
|
|
22
|
+
└── package.json
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## 2. Build Pipeline
|
|
28
|
+
|
|
29
|
+
The client component [`plugin.client.js`](file:///D:/dsh-plugin-message-edit/plugin.client.js) is written in browser-compatible JavaScript. Before distribution or testing, it is wrapped with a Cordis module preamble into [`lib/client.js`](file:///D:/dsh-plugin-message-edit/lib/client.js).
|
|
30
|
+
|
|
31
|
+
### Build Client
|
|
32
|
+
```bash
|
|
33
|
+
npm run build
|
|
34
|
+
```
|
|
35
|
+
Executes `node scripts/build-client.mjs` to regenerate `lib/client.js`.
|
|
36
|
+
|
|
37
|
+
### Check Build Integrity
|
|
38
|
+
```bash
|
|
39
|
+
node scripts/build-client.mjs --check
|
|
40
|
+
```
|
|
41
|
+
Exits with code 1 if `lib/client.js` is out of date relative to `plugin.client.js`.
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## 3. Testing
|
|
46
|
+
|
|
47
|
+
The project includes an automated test suite verifying tree construction, sibling fan-out, ghost recovery, active path calculation, and ring index calculation.
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
npm test
|
|
51
|
+
```
|
|
52
|
+
Automatically builds the client first, checks that it matches the source, then
|
|
53
|
+
runs the Node test runner. Install development dependencies with `npm ci` on a
|
|
54
|
+
fresh checkout before running tests (Node 22.19+ or Node 24).
|
|
55
|
+
|
|
56
|
+
- `test/tree.test.mjs`: 36 assertions covering branch and version-tree behavior.
|
|
57
|
+
- `test/client-images.test.mjs`: loads the generated client through its module
|
|
58
|
+
loader, mounts its registered user-message component using React and jsdom,
|
|
59
|
+
and checks image delegation, multiple/image-only messages, old-host fallback,
|
|
60
|
+
text-only messages, and entering/cancelling an edit. Host services and the image
|
|
61
|
+
gallery are test doubles; these are not full DSH integration tests.
|
|
62
|
+
- `test/client-registration.test.mjs`: checks module dependencies and visible
|
|
63
|
+
failures when services or registrations are unavailable.
|
|
64
|
+
- `test/session-record.test.mjs` and `test/host-compatibility.test.mjs`: cover
|
|
65
|
+
legacy/current session shapes, live/resumed edit requests, retained images,
|
|
66
|
+
retry ancestry, nested version markers, and cache invalidation.
|
|
67
|
+
|
|
68
|
+
GitHub Actions runs these checks for pull requests and branch pushes, on
|
|
69
|
+
Linux (Node 22 and 24) and Windows (Node 22). It also runs:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
npm run check:package
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
This creates a real npm archive in a temporary directory, verifies that runtime
|
|
76
|
+
entry points are present and development-only directories are absent, checks
|
|
77
|
+
the host entry's syntax, and removes the temporary archive. `npm pack` and
|
|
78
|
+
`npm publish` now build the client automatically through `prepack`, preventing
|
|
79
|
+
an old or missing generated client from being shipped.
|
|
80
|
+
|
|
81
|
+
The workflow needs to be pushed to GitHub to run there. Making its checks
|
|
82
|
+
mandatory before merging is a separate repository ruleset/branch-protection
|
|
83
|
+
setting; adding the workflow alone does not block the Merge button.
|
|
84
|
+
|
|
85
|
+
Before accepting an image-rendering change, also check it in a running DSH:
|
|
86
|
+
send text with one/multiple images and an image-only message, open an image in
|
|
87
|
+
the native viewer, enter/cancel an edit, then verify the original attachments
|
|
88
|
+
survive an edit submission. CI's gallery double cannot verify native image
|
|
89
|
+
loading, lightbox behavior, or compatibility with DSH's module injection.
|
|
90
|
+
|
|
91
|
+
To add new tests, edit [`test/tree.test.mjs`](file:///D:/dsh-plugin-message-edit/test/tree.test.mjs).
|
|
92
|
+
|
|
93
|
+
### Optional real DSH acceptance
|
|
94
|
+
|
|
95
|
+
`test/fixtures/dsh-acceptance.mjs` is an offline model adapter and live/cold
|
|
96
|
+
session fixture for an installed official DSH `0.1.5-rc.2` runtime. Mount it
|
|
97
|
+
only in a new temporary home whose name contains `message-edit-dsh-qa-`.
|
|
98
|
+
Set `DSH_HOME` to that home and `DSH_QA_MODULES` to the official runtime's
|
|
99
|
+
`node_modules` directory. Use a separate Web profile with the base/Web bundles,
|
|
100
|
+
a built copy of this plugin, and a loader entry for the fixture. Never point
|
|
101
|
+
this fixture at an existing user's DSH home.
|
|
102
|
+
|
|
103
|
+
Once the isolated server prints its URL, run:
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
node scripts/verify-dsh-acceptance.mjs http://127.0.0.1:61587
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
The verifier exercises real HTTP edit/retry operations, local model execution,
|
|
110
|
+
image retention, unchanged source messages, and nested branch markers. Restart
|
|
111
|
+
the same isolated server and repeat to exercise persisted branches. The fixture
|
|
112
|
+
adds `/qa/state` and `/qa/followup` endpoints solely for this disposable test.
|
|
113
|
+
Browser acceptance additionally checks the settings entry, version switcher,
|
|
114
|
+
thumbnails, and native original-image viewer. No remote API key is needed.
|
|
115
|
+
|
|
116
|
+
For an automated fresh-boot and restart run, set `DSH_QA_MODULES` to the
|
|
117
|
+
official runtime's `node_modules` directory and run:
|
|
2
118
|
|
|
3
|
-
This guide covers building, testing, packaging, and installing `dsh-plugin-message-edit`.
|
|
4
|
-
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
## 1. Repository Structure
|
|
8
|
-
|
|
9
|
-
```
|
|
10
|
-
dsh-plugin-message-edit/
|
|
11
|
-
├── lib/
|
|
12
|
-
│ ├── index.js # Host-side Cordis plugin (routes, session log processing)
|
|
13
|
-
│ ├── tree-logic.js # Pure tree algorithms (shared with client and tests)
|
|
14
|
-
│ └── client.js # Generated client bundle (wrapped from plugin.client.js)
|
|
15
|
-
├── plugin.client.js # Source client-side UI and React components
|
|
16
|
-
├── scripts/
|
|
17
|
-
│ └── build-client.mjs # Build script wrapping plugin.client.js into lib/client.js
|
|
18
|
-
├── test/
|
|
19
|
-
│ └── tree.test.mjs # Automated test suite (36+ unit tests)
|
|
20
|
-
├── cordis.patch.yml # Service dependencies and injection metadata
|
|
21
|
-
├── docs/ # Technical architecture and data model documentation
|
|
22
|
-
└── package.json
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
---
|
|
26
|
-
|
|
27
|
-
## 2. Build Pipeline
|
|
28
|
-
|
|
29
|
-
The client component [`plugin.client.js`](file:///D:/dsh-plugin-message-edit/plugin.client.js) is written in browser-compatible JavaScript. Before distribution or testing, it is wrapped with a Cordis module preamble into [`lib/client.js`](file:///D:/dsh-plugin-message-edit/lib/client.js).
|
|
30
|
-
|
|
31
|
-
### Build Client
|
|
32
|
-
```bash
|
|
33
|
-
npm run build
|
|
34
|
-
```
|
|
35
|
-
Executes `node scripts/build-client.mjs` to regenerate `lib/client.js`.
|
|
36
|
-
|
|
37
|
-
### Check Build Integrity
|
|
38
|
-
```bash
|
|
39
|
-
node scripts/build-client.mjs --check
|
|
40
|
-
```
|
|
41
|
-
Exits with code 1 if `lib/client.js` is out of date relative to `plugin.client.js`.
|
|
42
|
-
|
|
43
|
-
---
|
|
44
|
-
|
|
45
|
-
## 3. Testing
|
|
46
|
-
|
|
47
|
-
The project includes an automated test suite verifying tree construction, sibling fan-out, ghost recovery, active path calculation, and ring index calculation.
|
|
48
|
-
|
|
49
|
-
```bash
|
|
50
|
-
npm test
|
|
51
|
-
```
|
|
52
|
-
Runs the build check and executes `test/tree.test.mjs`.
|
|
53
|
-
|
|
54
|
-
To add new tests, edit [`test/tree.test.mjs`](file:///D:/dsh-plugin-message-edit/test/tree.test.mjs).
|
|
55
|
-
|
|
56
|
-
---
|
|
57
|
-
|
|
58
|
-
## 4. Local Installation into DSH Desktop
|
|
59
|
-
|
|
60
|
-
### Step 1: Build and Package
|
|
61
|
-
```bash
|
|
62
|
-
npm run build
|
|
63
|
-
npm pack
|
|
64
|
-
```
|
|
65
|
-
This produces a tarball: `dsh-plugin-message-edit-0.1.0.tgz`.
|
|
66
|
-
|
|
67
|
-
### Step 2: Install into DSH Profile
|
|
68
|
-
To install into the DSH Desktop profile:
|
|
69
119
|
```bash
|
|
70
|
-
|
|
120
|
+
node scripts/run-dsh-acceptance.mjs
|
|
71
121
|
```
|
|
72
|
-
Or sync files directly into `~/.dsh/profiles/desktop/node_modules/dsh-plugin-message-edit/`.
|
|
73
122
|
|
|
74
|
-
|
|
75
|
-
|
|
123
|
+
The runner owns and removes a unique temporary home, boots the official CLI
|
|
124
|
+
on an OS-selected port, runs the verifier, restarts the host, and repeats.
|
|
125
|
+
The restart pass explicitly resumes and retries an already seeded branch.
|
|
126
|
+
CI runs this on Linux and Windows in addition to the regression suite.
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## 4. Local Installation into DSH Desktop
|
|
131
|
+
|
|
132
|
+
### Step 1: Build and Package
|
|
133
|
+
```bash
|
|
134
|
+
npm run build
|
|
135
|
+
npm pack
|
|
136
|
+
```
|
|
137
|
+
This produces a tarball: `dsh-plugin-message-edit-0.1.0.tgz`.
|
|
138
|
+
|
|
139
|
+
### Step 2: Install into DSH Profile
|
|
140
|
+
To install into the DSH Desktop profile:
|
|
141
|
+
```bash
|
|
142
|
+
dsh plugin --profile desktop add file:/path/to/dsh-plugin-message-edit-0.1.0.tgz
|
|
143
|
+
```
|
|
144
|
+
Or sync files directly into `~/.dsh/profiles/desktop/node_modules/dsh-plugin-message-edit/`.
|
|
145
|
+
|
|
146
|
+
### Step 3: Restart DSH Desktop
|
|
147
|
+
Restart DSH Desktop to reload the host-side plugin in the server process and mount the updated client interface.
|
package/docs/TREE_DATA_MODEL.md
CHANGED
|
@@ -1,96 +1,96 @@
|
|
|
1
|
-
# Tree Data Model & Algorithms
|
|
2
|
-
|
|
3
|
-
This document details how conversation versions and turns are represented, branched, and visualized in `dsh-plugin-message-edit`.
|
|
4
|
-
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
## 1. Dual-Level Representation
|
|
8
|
-
|
|
9
|
-
There are two distinct levels of data representation in the system:
|
|
10
|
-
|
|
11
|
-
1. **Storage Level (Session DAG)**:
|
|
12
|
-
- DSH enforces session-level isolation. Each branch is a distinct DSH session record with `parentSession` and `
|
|
13
|
-
- The host maintains durable `message-tree/version` markers detailing which turn was edited/retried and what changed.
|
|
14
|
-
|
|
15
|
-
2. **Presentation Level (Turn-Level Branching Tree)**:
|
|
16
|
-
- A user thinks of conversation branching at the **message/turn** level, not the session container level.
|
|
17
|
-
- `buildTurnTree` projects the session versions into individual turn nodes.
|
|
18
|
-
|
|
19
|
-
```
|
|
20
|
-
Session DAG (Storage):
|
|
21
|
-
Session A (Original) ──[edit turn 1]──> Session B (Fork)
|
|
22
|
-
|
|
23
|
-
Turn Tree (Visualization):
|
|
24
|
-
[Root Conversation]
|
|
25
|
-
/ \
|
|
26
|
-
[A: Turn 1 (1/2)] [B: Turn 1 (2/2) - Edited]
|
|
27
|
-
| |
|
|
28
|
-
[A: Turn 2] [B: Turn 2]
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
---
|
|
32
|
-
|
|
33
|
-
## 2. Core Algorithms
|
|
34
|
-
|
|
35
|
-
### 2.1 Turn Tree Construction (`buildTurnTree`)
|
|
36
|
-
*Location: [`lib/tree-logic.js`](file:///D:/dsh-plugin-message-edit/lib/tree-logic.js#L173), [`plugin.client.js`](file:///D:/dsh-plugin-message-edit/plugin.client.js#L415)*
|
|
37
|
-
|
|
38
|
-
Transforms `versions` into an array of turn nodes:
|
|
39
|
-
1. **Root Conversation Node (`${rootSessionId}#root`)**: Represents the origin anchor of the conversation.
|
|
40
|
-
2. **Root Session Turns**:
|
|
41
|
-
- Turn 1 hangs off `${rootSessionId}#root`.
|
|
42
|
-
- Turn $k$ ($k > 1$) hangs off `${rootSessionId}#t${k-1}`.
|
|
43
|
-
3. **Forked Session Turns**:
|
|
44
|
-
- For a session branched at `targetTurn = T`:
|
|
45
|
-
- If $T = 1$: Turn 1 hangs off `${rootSessionId}#root` (sibling of the original Turn 1).
|
|
46
|
-
- If $T > 1$: Turn $T$ hangs off `${parentSessionId}#t${T-1}` (sibling of parent's Turn $T$).
|
|
47
|
-
- Subsequent turns $T+1, T+2, \dots$ hang off the previous turn in the same session (`${sessionId}#t${k-1}`).
|
|
48
|
-
4. **Safety Fallback**: Any node whose computed `parentId` does not exist in the graph is automatically attached to `${rootSessionId}#root`, preventing disconnected subtrees.
|
|
49
|
-
|
|
50
|
-
### 2.2 Sibling Fan-Out (`attachParentId`)
|
|
51
|
-
*Location: [`lib/tree-logic.js`](file:///D:/dsh-plugin-message-edit/lib/tree-logic.js#L9)*
|
|
52
|
-
|
|
53
|
-
When a user edits Turn 1 repeatedly (e.g. Turn 1 $\rightarrow$ Edit 1 $\rightarrow$ Edit 2 while viewing Edit 1):
|
|
54
|
-
- Without fan-out, edits form a chain: $A \rightarrow B \rightarrow C$.
|
|
55
|
-
- `attachParentId` traverses up versions of the same turn and stops at the first session that is *not* an edit of that turn ($A$).
|
|
56
|
-
- Result: Both Edit 1 and Edit 2 hang off $A$ as sibling branches.
|
|
57
|
-
|
|
58
|
-
### 2.3 Ghost Ancestor Recovery (`ancestorChainFromLog` & `collectFamily`)
|
|
59
|
-
*Location: [`lib/tree-logic.js`](file:///D:/dsh-plugin-message-edit/lib/tree-logic.js#L110-L171)*
|
|
60
|
-
|
|
61
|
-
If an intermediate session in a family is deleted by the user in DSH:
|
|
62
|
-
- The deleted session's own event log is gone.
|
|
63
|
-
- However, its descendant sessions inherited its prefix log (including the `message-tree/version` marker describing the deleted parent).
|
|
64
|
-
- `ancestorChainFromLog` inspects the surviving descendant's seed events to reconstruct deleted ancestors as **ghost nodes** (`deleted: true`).
|
|
65
|
-
- `collectFamily` ensures the family graph remains fully connected even when intermediate nodes are deleted.
|
|
66
|
-
|
|
67
|
-
### 2.4 Active Path Calculation
|
|
68
|
-
*Location: [`lib/tree-logic.js`](file:///D:/dsh-plugin-message-edit/lib/tree-logic.js#L318-L339)*
|
|
69
|
-
|
|
70
|
-
To highlight only the active branch path without highlighting superseded sibling branches:
|
|
71
|
-
1. Locate the latest turn node in `currentSessionId`.
|
|
72
|
-
2. Walk upwards following `parentId` pointers until reaching `${rootSessionId}#root`.
|
|
73
|
-
3. Mark only nodes on this walk with `onCurrentPath = true`.
|
|
74
|
-
|
|
75
|
-
### 2.5 Bubble Version Ring (`ringFor`)
|
|
76
|
-
*Location: [`lib/tree-logic.js`](file:///D:/dsh-plugin-message-edit/lib/tree-logic.js#L30-L68)*
|
|
77
|
-
|
|
78
|
-
Calculates the `‹ n/m ›` counter under a message at `turn` while viewing `sessionId`:
|
|
79
|
-
- Walks parent links to find the common fork point for that turn.
|
|
80
|
-
- Filters out deleted/ghost sessions (renumbering over surviving versions).
|
|
81
|
-
- Returns `{ alternatives, index }`. If fewer than 2 alternatives exist, returns `null` (counter is hidden).
|
|
82
|
-
|
|
83
|
-
---
|
|
84
|
-
|
|
85
|
-
## 3. Graph Layout & Springs
|
|
86
|
-
|
|
87
|
-
*Location: [`plugin.client.js`](file:///D:/dsh-plugin-message-edit/plugin.client.js#L567-L612)*
|
|
88
|
-
|
|
89
|
-
- **Tidy Tree Layout (`layoutTurnTree`)**:
|
|
90
|
-
- Leaf nodes take successive horizontal slots (`cursor * SLOT_X`, where `SLOT_X = 206px`).
|
|
91
|
-
- Parent nodes center horizontally over their children (`(min_x + max_x) / 2`).
|
|
92
|
-
- Depths scale vertically (`depth * SLOT_Y`, where `SLOT_Y = 132px`).
|
|
93
|
-
- **Spring Physics (`springs.current`)**:
|
|
94
|
-
- Cards smoothly animate to their target coordinates using critically-damped spring equations ($k = 190, c = 24$).
|
|
95
|
-
- New cards spawn at their parent's coordinates and spring outward.
|
|
96
|
-
- Edges are rendered as cubic SVG bezier curves connecting parent card bottoms to child card tops.
|
|
1
|
+
# Tree Data Model & Algorithms
|
|
2
|
+
|
|
3
|
+
This document details how conversation versions and turns are represented, branched, and visualized in `dsh-plugin-message-edit`.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. Dual-Level Representation
|
|
8
|
+
|
|
9
|
+
There are two distinct levels of data representation in the system:
|
|
10
|
+
|
|
11
|
+
1. **Storage Level (Session DAG)**:
|
|
12
|
+
- DSH enforces session-level isolation. Each branch is a distinct DSH session record with `parentSession`, `isSeeded`, and a separate `inheritedEventCount`.
|
|
13
|
+
- The host maintains durable `message-tree/version` markers detailing which turn was edited/retried and what changed.
|
|
14
|
+
|
|
15
|
+
2. **Presentation Level (Turn-Level Branching Tree)**:
|
|
16
|
+
- A user thinks of conversation branching at the **message/turn** level, not the session container level.
|
|
17
|
+
- `buildTurnTree` projects the session versions into individual turn nodes.
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
Session DAG (Storage):
|
|
21
|
+
Session A (Original) ──[edit turn 1]──> Session B (Fork)
|
|
22
|
+
|
|
23
|
+
Turn Tree (Visualization):
|
|
24
|
+
[Root Conversation]
|
|
25
|
+
/ \
|
|
26
|
+
[A: Turn 1 (1/2)] [B: Turn 1 (2/2) - Edited]
|
|
27
|
+
| |
|
|
28
|
+
[A: Turn 2] [B: Turn 2]
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## 2. Core Algorithms
|
|
34
|
+
|
|
35
|
+
### 2.1 Turn Tree Construction (`buildTurnTree`)
|
|
36
|
+
*Location: [`lib/tree-logic.js`](file:///D:/dsh-plugin-message-edit/lib/tree-logic.js#L173), [`plugin.client.js`](file:///D:/dsh-plugin-message-edit/plugin.client.js#L415)*
|
|
37
|
+
|
|
38
|
+
Transforms `versions` into an array of turn nodes:
|
|
39
|
+
1. **Root Conversation Node (`${rootSessionId}#root`)**: Represents the origin anchor of the conversation.
|
|
40
|
+
2. **Root Session Turns**:
|
|
41
|
+
- Turn 1 hangs off `${rootSessionId}#root`.
|
|
42
|
+
- Turn $k$ ($k > 1$) hangs off `${rootSessionId}#t${k-1}`.
|
|
43
|
+
3. **Forked Session Turns**:
|
|
44
|
+
- For a session branched at `targetTurn = T`:
|
|
45
|
+
- If $T = 1$: Turn 1 hangs off `${rootSessionId}#root` (sibling of the original Turn 1).
|
|
46
|
+
- If $T > 1$: Turn $T$ hangs off `${parentSessionId}#t${T-1}` (sibling of parent's Turn $T$).
|
|
47
|
+
- Subsequent turns $T+1, T+2, \dots$ hang off the previous turn in the same session (`${sessionId}#t${k-1}`).
|
|
48
|
+
4. **Safety Fallback**: Any node whose computed `parentId` does not exist in the graph is automatically attached to `${rootSessionId}#root`, preventing disconnected subtrees.
|
|
49
|
+
|
|
50
|
+
### 2.2 Sibling Fan-Out (`attachParentId`)
|
|
51
|
+
*Location: [`lib/tree-logic.js`](file:///D:/dsh-plugin-message-edit/lib/tree-logic.js#L9)*
|
|
52
|
+
|
|
53
|
+
When a user edits Turn 1 repeatedly (e.g. Turn 1 $\rightarrow$ Edit 1 $\rightarrow$ Edit 2 while viewing Edit 1):
|
|
54
|
+
- Without fan-out, edits form a chain: $A \rightarrow B \rightarrow C$.
|
|
55
|
+
- `attachParentId` traverses up versions of the same turn and stops at the first session that is *not* an edit of that turn ($A$).
|
|
56
|
+
- Result: Both Edit 1 and Edit 2 hang off $A$ as sibling branches.
|
|
57
|
+
|
|
58
|
+
### 2.3 Ghost Ancestor Recovery (`ancestorChainFromLog` & `collectFamily`)
|
|
59
|
+
*Location: [`lib/tree-logic.js`](file:///D:/dsh-plugin-message-edit/lib/tree-logic.js#L110-L171)*
|
|
60
|
+
|
|
61
|
+
If an intermediate session in a family is deleted by the user in DSH:
|
|
62
|
+
- The deleted session's own event log is gone.
|
|
63
|
+
- However, its descendant sessions inherited its prefix log (including the `message-tree/version` marker describing the deleted parent).
|
|
64
|
+
- `ancestorChainFromLog` inspects the surviving descendant's seed events to reconstruct deleted ancestors as **ghost nodes** (`deleted: true`).
|
|
65
|
+
- `collectFamily` ensures the family graph remains fully connected even when intermediate nodes are deleted.
|
|
66
|
+
|
|
67
|
+
### 2.4 Active Path Calculation
|
|
68
|
+
*Location: [`lib/tree-logic.js`](file:///D:/dsh-plugin-message-edit/lib/tree-logic.js#L318-L339)*
|
|
69
|
+
|
|
70
|
+
To highlight only the active branch path without highlighting superseded sibling branches:
|
|
71
|
+
1. Locate the latest turn node in `currentSessionId`.
|
|
72
|
+
2. Walk upwards following `parentId` pointers until reaching `${rootSessionId}#root`.
|
|
73
|
+
3. Mark only nodes on this walk with `onCurrentPath = true`.
|
|
74
|
+
|
|
75
|
+
### 2.5 Bubble Version Ring (`ringFor`)
|
|
76
|
+
*Location: [`lib/tree-logic.js`](file:///D:/dsh-plugin-message-edit/lib/tree-logic.js#L30-L68)*
|
|
77
|
+
|
|
78
|
+
Calculates the `‹ n/m ›` counter under a message at `turn` while viewing `sessionId`:
|
|
79
|
+
- Walks parent links to find the common fork point for that turn.
|
|
80
|
+
- Filters out deleted/ghost sessions (renumbering over surviving versions).
|
|
81
|
+
- Returns `{ alternatives, index }`. If fewer than 2 alternatives exist, returns `null` (counter is hidden).
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## 3. Graph Layout & Springs
|
|
86
|
+
|
|
87
|
+
*Location: [`plugin.client.js`](file:///D:/dsh-plugin-message-edit/plugin.client.js#L567-L612)*
|
|
88
|
+
|
|
89
|
+
- **Tidy Tree Layout (`layoutTurnTree`)**:
|
|
90
|
+
- Leaf nodes take successive horizontal slots (`cursor * SLOT_X`, where `SLOT_X = 206px`).
|
|
91
|
+
- Parent nodes center horizontally over their children (`(min_x + max_x) / 2`).
|
|
92
|
+
- Depths scale vertically (`depth * SLOT_Y`, where `SLOT_Y = 132px`).
|
|
93
|
+
- **Spring Physics (`springs.current`)**:
|
|
94
|
+
- Cards smoothly animate to their target coordinates using critically-damped spring equations ($k = 190, c = 24$).
|
|
95
|
+
- New cards spawn at their parent's coordinates and spring outward.
|
|
96
|
+
- Edges are rendered as cubic SVG bezier curves connecting parent card bottoms to child card tops.
|