@logicseek/hello-cc 0.1.4 → 0.1.6
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/CHANGELOG.md +126 -0
- package/bin/hcc.mjs +2739 -6482
- package/docs/README.md +2 -0
- package/docs/README.zh-CN.md +3 -1
- package/docs/architecture-split-review.md +217 -0
- package/docs/architecture.md +385 -0
- package/docs/architecture.zh-CN.md +364 -0
- package/docs/commands.md +21 -9
- package/docs/commands.zh-CN.md +19 -9
- package/docs/layout-split-stack-audit.md +298 -0
- package/lib/automation.mjs +8 -0
- package/lib/cli-args.mjs +89 -0
- package/lib/cli-runtime.mjs +44 -0
- package/lib/coordination-state.mjs +218 -0
- package/lib/core/coordination/automation.mjs +222 -0
- package/lib/core/coordination/locks.mjs +46 -0
- package/lib/core/coordination/messages.mjs +116 -0
- package/lib/core/coordination/tasks.mjs +224 -0
- package/lib/core/coordination/teams.mjs +73 -0
- package/lib/core/coordination/timeline.mjs +187 -0
- package/lib/core/peers/bindings.mjs +83 -0
- package/lib/core/peers/format.mjs +13 -0
- package/lib/core/peers/identity.mjs +53 -0
- package/lib/core/peers/liveness.mjs +90 -0
- package/lib/core/peers/reconcile.mjs +238 -0
- package/lib/core/peers/session.mjs +14 -0
- package/lib/core/sessions/launch.mjs +89 -0
- package/lib/db/schema.mjs +324 -0
- package/lib/db/stores/peers.mjs +231 -0
- package/lib/db-schema.mjs +7 -0
- package/lib/errors.mjs +1 -0
- package/lib/format.mjs +39 -0
- package/lib/guidance.mjs +10 -2
- package/lib/handoff.mjs +26 -0
- package/lib/help.mjs +3 -0
- package/lib/integrations/hooks.mjs +171 -0
- package/lib/integrations/peers/identity.mjs +208 -0
- package/lib/integrations/peers/processes.mjs +151 -0
- package/lib/integrations/providers.mjs +282 -0
- package/lib/integrations/shims/script.mjs +384 -0
- package/lib/integrations/shims.mjs +106 -0
- package/lib/json-file.mjs +1 -0
- package/lib/locks.mjs +10 -0
- package/lib/messages.mjs +3 -0
- package/lib/package-meta.mjs +6 -24
- package/lib/peer-bindings.mjs +14 -0
- package/lib/peer-format.mjs +4 -0
- package/lib/peer-identity.mjs +15 -0
- package/lib/project-context.mjs +6 -0
- package/lib/project-registry.mjs +7 -0
- package/lib/provider-commands.mjs +13 -0
- package/lib/release/package-meta.mjs +31 -0
- package/lib/release/release-notes.mjs +40 -0
- package/lib/release-notes.mjs +6 -40
- package/lib/runtime/client.mjs +42 -0
- package/lib/runtime/paths.mjs +45 -0
- package/lib/runtime/project-context.mjs +32 -0
- package/lib/runtime/projects.mjs +76 -0
- package/lib/runtime/state.mjs +128 -0
- package/lib/runtime-client.mjs +3 -0
- package/lib/runtime-paths.mjs +11 -0
- package/lib/runtime-state.mjs +11 -0
- package/lib/session-launch.mjs +17 -0
- package/lib/setup.mjs +18 -765
- package/lib/shared/errors.mjs +7 -0
- package/lib/shared/json-file.mjs +14 -0
- package/lib/shell-path.mjs +69 -0
- package/lib/shim-script.mjs +1 -0
- package/lib/state-render.mjs +5 -0
- package/lib/task-cli.mjs +45 -0
- package/lib/task-liveness.mjs +8 -0
- package/lib/task-store.mjs +3 -0
- package/lib/team-planning.mjs +7 -0
- package/lib/terminal/tmux.mjs +372 -0
- package/lib/timeline.mjs +12 -0
- package/lib/tmux.mjs +18 -0
- package/lib/ui/help.mjs +419 -0
- package/lib/ui/state-render.mjs +61 -0
- package/lib/web/http.mjs +55 -0
- package/lib/web/peer-actions.mjs +270 -0
- package/lib/web/runtime.mjs +154 -0
- package/lib/web/ui-template.mjs +2055 -0
- package/lib/web-http.mjs +7 -0
- package/lib/web-peer-actions.mjs +3 -0
- package/lib/web-runtime.mjs +17 -0
- package/lib/web-ui-template.mjs +3 -0
- package/package.json +1 -1
- package/scripts/github-release.mjs +2 -2
- package/scripts/regression.mjs +2738 -22
- package/scripts/release-notes.mjs +2 -2
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
# Layout Split Stack Audit
|
|
2
|
+
|
|
3
|
+
Date: 2026-06-14
|
|
4
|
+
|
|
5
|
+
Audit branch: `audit/layout-split-stack-20260614`
|
|
6
|
+
|
|
7
|
+
Reviewed range: `origin/master..HEAD`
|
|
8
|
+
|
|
9
|
+
- Base: `4969100` (`origin/master`, published as `@logicseek/hello-cc@0.1.5`)
|
|
10
|
+
- Audited head: `4283234`
|
|
11
|
+
- Commit count: 40
|
|
12
|
+
|
|
13
|
+
This document audits the local architecture split stack before any push or npm
|
|
14
|
+
publish. It is intentionally on a dedicated audit branch/worktree so the active
|
|
15
|
+
`master` implementation stack is not rewritten during review.
|
|
16
|
+
|
|
17
|
+
## Review Standard
|
|
18
|
+
|
|
19
|
+
Each commit is classified against `docs/architecture.md`:
|
|
20
|
+
|
|
21
|
+
- `keep`: the commit directly moves code toward a documented product boundary.
|
|
22
|
+
- `keep-with-cleanup`: the direction is right, but package surface, shim policy,
|
|
23
|
+
or module placement still needs a cleanup decision before release.
|
|
24
|
+
- `squash/rebuild`: the code is useful, but the commit exists mostly as an
|
|
25
|
+
intermediate flat extraction and should be folded into a product-boundary
|
|
26
|
+
commit if a clean release branch is rebuilt.
|
|
27
|
+
- `decision-needed`: the final location or public surface is not settled.
|
|
28
|
+
- `docs-only`: documentation or process record.
|
|
29
|
+
|
|
30
|
+
The important distinction is code shape versus history shape. A commit can be
|
|
31
|
+
useful for reaching the current code state while still being a poor standalone
|
|
32
|
+
release-history commit.
|
|
33
|
+
|
|
34
|
+
## Team Review Split
|
|
35
|
+
|
|
36
|
+
Parent task: `#232`
|
|
37
|
+
|
|
38
|
+
- `#234 lead-audit`: maintain this matrix and merge review feedback.
|
|
39
|
+
- `#236 review-core-db`: core, coordination, db, peers, session semantics.
|
|
40
|
+
- `#235 review-runtime-web`: runtime, web, terminal, integrations, release,
|
|
41
|
+
shared helper placement.
|
|
42
|
+
- `#237 review-package-surface`: top-level `lib/*.mjs` compatibility shims,
|
|
43
|
+
npm package surface, and release-note risk.
|
|
44
|
+
|
|
45
|
+
## Summary
|
|
46
|
+
|
|
47
|
+
The current `HEAD` is not a random bad refactor. The final code shape has mostly
|
|
48
|
+
been corrected toward the target architecture:
|
|
49
|
+
|
|
50
|
+
- coordination logic under `lib/core/coordination`
|
|
51
|
+
- peer/session semantics under `lib/core/peers` and `lib/core/sessions`
|
|
52
|
+
- schema and stores under `lib/db`
|
|
53
|
+
- runtime state/client/project helpers under `lib/runtime`
|
|
54
|
+
- tmux under `lib/terminal`
|
|
55
|
+
- Web runtime helpers under `lib/web`
|
|
56
|
+
- provider/hooks/shims under `lib/integrations`
|
|
57
|
+
- small utilities under `lib/shared`
|
|
58
|
+
- text rendering/help under `lib/ui`
|
|
59
|
+
- release helpers under `lib/release`
|
|
60
|
+
|
|
61
|
+
The problem is the history shape. The first 25 local commits were mostly
|
|
62
|
+
"extract a helper from `bin/hcc.mjs` into a top-level `lib/*.mjs` file". That
|
|
63
|
+
was useful as a safety step, but it does not match the architecture design by
|
|
64
|
+
itself. Later commits then moved many of those flat files into real product
|
|
65
|
+
boundaries.
|
|
66
|
+
|
|
67
|
+
Therefore:
|
|
68
|
+
|
|
69
|
+
1. If the project keeps the current `master` history, do not keep making broad
|
|
70
|
+
split commits. Finish only package-surface cleanup, run full validation, bump
|
|
71
|
+
the version, and publish/sync with a clear changelog.
|
|
72
|
+
2. If the project wants clean history for this major refactor, create a rebuild
|
|
73
|
+
branch from `origin/master` and replay the final shape as fewer architectural
|
|
74
|
+
commits. Do not rewrite the active `master` while peers use it.
|
|
75
|
+
|
|
76
|
+
## Phase Classification
|
|
77
|
+
|
|
78
|
+
### Phase 1: Early Flat Extractions
|
|
79
|
+
|
|
80
|
+
These commits reduced `bin/hcc.mjs`, but mostly created top-level helper modules
|
|
81
|
+
before the design document existed. They should be treated as
|
|
82
|
+
`squash/rebuild` if a clean branch is made.
|
|
83
|
+
|
|
84
|
+
| Commit | Area | Classification | Reason |
|
|
85
|
+
| --- | --- | --- | --- |
|
|
86
|
+
| `1bb1967` | providers + tmux | `squash/rebuild` | Mixed two product boundaries in one top-level extraction; should become integrations/provider and terminal/tmux commits. |
|
|
87
|
+
| `e155d5a` | locks | `squash/rebuild` | Useful code, but final home is `lib/core/coordination/locks.mjs`, not top-level `lib/locks.mjs`. |
|
|
88
|
+
| `9ab464d` | team planning | `squash/rebuild` | Same pattern; final home is `lib/core/coordination/teams.mjs`. |
|
|
89
|
+
| `807fa96` | peer identity | `squash/rebuild` | Useful extraction, but identity is split between integration discovery and core peer semantics later. |
|
|
90
|
+
| `494d38f` | peer format | `squash/rebuild` | Good low-level helper, but should land with peer-boundary cleanup rather than a standalone flat helper commit. |
|
|
91
|
+
| `e2b745d` | project registry | `squash/rebuild` | Final boundary is runtime/project registry. |
|
|
92
|
+
| `e4c4497` | project context | `squash/rebuild` | Final boundary is runtime/project context. |
|
|
93
|
+
| `dec3e2e` | handoff | `decision-needed` | `lib/handoff.mjs` remains top-level; decide core coordination semantics versus CLI command helper. |
|
|
94
|
+
| `61b02a2` | timeline | `squash/rebuild` | Final boundary is core coordination timeline. |
|
|
95
|
+
| `62ede11` | runtime state | `squash/rebuild` | Final boundary is `lib/runtime/state.mjs`. |
|
|
96
|
+
| `7d885f1` | task liveness | `squash/rebuild` | Final boundary is core peer liveness. |
|
|
97
|
+
| `3f0cc7e` | session launch | `decision-needed` | Current compatibility file bridges core session launch and terminal/tmux helpers; keep an eye on dependency direction. |
|
|
98
|
+
| `b07e9b5` | automation | `squash/rebuild` | Final boundary is core coordination automation. |
|
|
99
|
+
| `428bbf3` | state render | `squash/rebuild` | Final boundary is UI state rendering. |
|
|
100
|
+
| `8a6120f` | tmux pane | `squash/rebuild` | Should be folded into terminal/tmux movement. |
|
|
101
|
+
| `3ec062b` | help text | `squash/rebuild` | Final boundary is UI help. |
|
|
102
|
+
| `7e8068c` | uninstall help | `squash/rebuild` | Should be folded into UI help extraction. |
|
|
103
|
+
| `9ed79b6` | message store | `squash/rebuild` | Final boundary is core coordination messages. |
|
|
104
|
+
| `07ddcc9` | runtime client | `squash/rebuild` | Final boundary is `lib/runtime/client.mjs`. |
|
|
105
|
+
| `c06e55d` | web runtime server helpers | `squash/rebuild` | Useful step, but final boundary is `lib/web/runtime.mjs`; route/session/server split still pending. |
|
|
106
|
+
| `fe36930` | task store | `squash/rebuild` | Final boundary is core coordination tasks. |
|
|
107
|
+
| `3bd0782` | task CLI parsing | `keep-with-cleanup` | This is a CLI-specific helper and can remain near CLI until `lib/cli/*` exists. |
|
|
108
|
+
| `61538fc` | peer bindings | `squash/rebuild` | Final split crosses core peer bindings and db peer store. |
|
|
109
|
+
| `787857f` | CLI runtime | `keep-with-cleanup` | Still not the final `lib/cli/context.mjs` layout, but it is a valid CLI/runtime entrypoint reduction. |
|
|
110
|
+
| `00ac7ba` | coordination state | `squash/rebuild` | Useful factory boundary, but should be evaluated with core coordination dependencies. |
|
|
111
|
+
|
|
112
|
+
### Phase 2: Architecture Documentation And First Boundary Correction
|
|
113
|
+
|
|
114
|
+
| Commit | Area | Classification | Reason |
|
|
115
|
+
| --- | --- | --- | --- |
|
|
116
|
+
| `94d63c0` | architecture docs | `docs-only` | Correctly establishes the target layout. |
|
|
117
|
+
| `76d5181` | web peer actions | `squash/rebuild` | Good product boundary direction, but final import path is corrected later under `lib/web/peer-actions.mjs`. |
|
|
118
|
+
| `265284a` | broad architecture alignment | `keep-with-cleanup` | Correct direction, but too broad for ideal history; should become several product-boundary commits on a rebuild branch. Also review whether SQL/transaction-heavy task code belongs in `lib/core/coordination/tasks.mjs` or should split pure task policy from a db store. |
|
|
119
|
+
|
|
120
|
+
### Phase 3: Product-Boundary Cleanup Commits
|
|
121
|
+
|
|
122
|
+
These commits are much closer to the target design. They are the model for the
|
|
123
|
+
rebuild branch if one is created.
|
|
124
|
+
|
|
125
|
+
| Commit | Area | Classification | Reason |
|
|
126
|
+
| --- | --- | --- | --- |
|
|
127
|
+
| `294eb2e` | peer layout boundaries | `keep` | Moves peer semantics toward `core/peers`, `db/stores`, and integrations boundaries. |
|
|
128
|
+
| `a3eabd8` | tmux adapter | `keep` | Clear terminal adapter boundary. |
|
|
129
|
+
| `fb9c35a` | shared JSON file helpers | `keep-with-cleanup` | Shared utility is appropriate; keep `lib/json-file.mjs` compat because it was already published in `0.1.5`. |
|
|
130
|
+
| `77c098d` | provider commands | `keep` | Correct integrations boundary. |
|
|
131
|
+
| `6bbe4a0` | project context | `keep` | Correct runtime boundary. |
|
|
132
|
+
| `be7c882` | session launch helpers | `decision-needed` | Direction is mostly correct, but compat surface exports both core session and terminal/tmux helpers. Review dependency direction before release. |
|
|
133
|
+
| `ffc42a7` | setup hook installers | `keep` | Correct integrations/hooks boundary. |
|
|
134
|
+
| `1bd110f` | setup shims | `keep` | Correct integrations/shims boundary. |
|
|
135
|
+
| `c191c72` | shim script generator | `keep` | Correct integrations/shims/script boundary. |
|
|
136
|
+
| `11fd4f6` | CLI errors | `keep` | Correct small shared utility boundary with compatibility re-export. |
|
|
137
|
+
|
|
138
|
+
### Phase 4: Review And Policy Docs
|
|
139
|
+
|
|
140
|
+
| Commit | Area | Classification | Reason |
|
|
141
|
+
| --- | --- | --- | --- |
|
|
142
|
+
| `19c0856` | split review | `docs-only` | Captures the historical concern and branch strategy. |
|
|
143
|
+
| `4283234` | package surface policy | `docs-only` | Captures npm `0.1.5` fact, version-bump requirement, and A/B/C shim policy. |
|
|
144
|
+
|
|
145
|
+
## Initial Recommendations
|
|
146
|
+
|
|
147
|
+
### Use A New Branch
|
|
148
|
+
|
|
149
|
+
Yes. This is a major refactor stack and should not be pushed or published
|
|
150
|
+
directly just because `master` is currently green. Use this audit branch for
|
|
151
|
+
review. If the team chooses clean history, create a separate rebuild branch from
|
|
152
|
+
`origin/master`, not from current `master`.
|
|
153
|
+
|
|
154
|
+
Suggested rebuild branch:
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
git worktree add ../hello-cc-layout-rebuild -b rebuild/layout-split-20260614 origin/master
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Suggested rebuilt commit order:
|
|
161
|
+
|
|
162
|
+
1. Architecture docs.
|
|
163
|
+
2. Core coordination modules: locks, teams, messages, tasks, timeline,
|
|
164
|
+
automation, liveness-related coordination state.
|
|
165
|
+
3. Core peer/session modules and db peer store.
|
|
166
|
+
4. Runtime modules: paths, state, client, project registry, project context.
|
|
167
|
+
5. Terminal adapter: tmux.
|
|
168
|
+
6. Web modules: runtime, HTTP, peer actions, UI template.
|
|
169
|
+
7. Integrations: providers, hooks, shims, shim script, peer identity.
|
|
170
|
+
8. Shared/release/ui helpers.
|
|
171
|
+
9. Compatibility shim policy and package-surface release notes.
|
|
172
|
+
|
|
173
|
+
### Do Not Revert The Final Shape Blindly
|
|
174
|
+
|
|
175
|
+
The final code shape is mostly aligned with the architecture document. The
|
|
176
|
+
problem is the noisy path taken to get there. A rebuild should preserve the
|
|
177
|
+
validated final behavior while changing the history granularity.
|
|
178
|
+
|
|
179
|
+
### Core/DB Review Findings
|
|
180
|
+
|
|
181
|
+
The core/db review from `#236` and the parallel read-only subagent agree on the
|
|
182
|
+
main shape:
|
|
183
|
+
|
|
184
|
+
- Keep the final direction of `lib/core/coordination/*`, `lib/core/peers/*`,
|
|
185
|
+
`lib/core/sessions/launch.mjs`, `lib/db/schema.mjs`,
|
|
186
|
+
`lib/db/stores/peers.mjs`, and `lib/shared/errors.mjs`.
|
|
187
|
+
- Rebuild the early top-level coordination/peer/session helper commits into
|
|
188
|
+
product-boundary commits if clean history is chosen.
|
|
189
|
+
- Do not treat `lib/handoff.mjs`, `lib/session-launch.mjs`, or
|
|
190
|
+
`lib/coordination-state.mjs` as settled final architecture.
|
|
191
|
+
|
|
192
|
+
Concrete cleanup items from that review:
|
|
193
|
+
|
|
194
|
+
- `lib/core/coordination/tasks.mjs` is currently SQL/transaction-heavy. Split
|
|
195
|
+
pure task lifecycle/takeover/team policy from DB store operations, or move the
|
|
196
|
+
store-style SQL operations under `lib/db/stores/tasks.mjs`.
|
|
197
|
+
- `lib/core/coordination/automation.mjs` and
|
|
198
|
+
`lib/core/coordination/timeline.mjs` depend on top-level `lib/format.mjs` for
|
|
199
|
+
`shellQuoteArg` / `compactText`. Move dependency-light text helpers to
|
|
200
|
+
`lib/shared/text.mjs` or keep rendering concerns in the UI/CLI layer.
|
|
201
|
+
- `lib/handoff.mjs` mixes CLI input normalization with runtime Git changed-file
|
|
202
|
+
discovery. Split handoff product semantics from CLI/runtime file inspection.
|
|
203
|
+
- `lib/session-launch.mjs` re-exports both core session helpers and
|
|
204
|
+
terminal/tmux helpers. That is acceptable only as a compatibility entrypoint;
|
|
205
|
+
do not let it become the conceptual module boundary.
|
|
206
|
+
- `lib/coordination-state.mjs` is useful as an interim assembler, but it mixes
|
|
207
|
+
DB queries, timeline, automation, hook context, status summary, and message
|
|
208
|
+
ack batching. Later split it into core state services plus CLI/Web adapters.
|
|
209
|
+
|
|
210
|
+
### Runtime/Web/Integrations Review Findings
|
|
211
|
+
|
|
212
|
+
The runtime/web/terminal/integrations review from `#235` and the parallel
|
|
213
|
+
read-only subagent agree on the main shape:
|
|
214
|
+
|
|
215
|
+
- Keep the final direction of `lib/terminal/tmux.mjs`.
|
|
216
|
+
- Keep the final direction of `lib/integrations/providers.mjs`,
|
|
217
|
+
`lib/integrations/hooks.mjs`, `lib/integrations/shims.mjs`, and
|
|
218
|
+
`lib/integrations/shims/script.mjs`.
|
|
219
|
+
- Keep the final direction of `lib/release/*`, `lib/shared/errors.mjs`, and
|
|
220
|
+
`lib/shared/json-file.mjs`.
|
|
221
|
+
- Keep the runtime and Web movement as directionally correct:
|
|
222
|
+
`lib/runtime/{paths,state,client,projects,project-context}.mjs` and
|
|
223
|
+
`lib/web/{http,runtime,ui-template,peer-actions}.mjs`.
|
|
224
|
+
|
|
225
|
+
Concrete cleanup items from that review:
|
|
226
|
+
|
|
227
|
+
- `lib/runtime/client.mjs` and `lib/runtime/state.mjs` import `runtimeApiUrl`
|
|
228
|
+
from `lib/web/runtime.mjs`. That creates a runtime -> web reverse dependency.
|
|
229
|
+
Move the URL helper into `lib/runtime`, `lib/shared`, or inject it from the
|
|
230
|
+
caller before claiming strict dependency direction.
|
|
231
|
+
- `lib/web/runtime.mjs` and `lib/web/peer-actions.mjs` import CLI parsing
|
|
232
|
+
helpers from `lib/cli-args.mjs`. Move shared option parsing such as
|
|
233
|
+
`intOpt`/`required` to a dependency-light shared helper, or inject parsing at
|
|
234
|
+
the route boundary.
|
|
235
|
+
- `lib/web/peer-actions.mjs` imports `normalizeStateResources` from
|
|
236
|
+
`lib/ui/state-render.mjs`. Move non-render normalization out of the UI layer,
|
|
237
|
+
or keep the dependency at a CLI/Web adapter edge.
|
|
238
|
+
- `cmdWeb()` in `bin/hcc.mjs` still owns server lifecycle, session manager,
|
|
239
|
+
WebSocket terminal transport, tmux/PTY orchestration, external-buffer
|
|
240
|
+
adoption, and shutdown cleanup. Future work should split this by subsystem;
|
|
241
|
+
do not continue random helper extraction from it.
|
|
242
|
+
|
|
243
|
+
No immediate runtime blocker was found. `#235` also reran `npm test` and got
|
|
244
|
+
`FULL_REGRESSION_OK`.
|
|
245
|
+
|
|
246
|
+
### Decide Shim Policy Before Release
|
|
247
|
+
|
|
248
|
+
Because `@logicseek/hello-cc@0.1.5` is already published from `4969100`, the
|
|
249
|
+
next package version must be new. Before that publish:
|
|
250
|
+
|
|
251
|
+
- Group A: already-published or CLI-facing top-level `lib/*.mjs` paths stay.
|
|
252
|
+
- Group B: migration compatibility paths stay one release if needed and are
|
|
253
|
+
documented as compatibility-only deep-import paths.
|
|
254
|
+
- Group C: unpublished top-level shims with no internal use or compatibility
|
|
255
|
+
value should be removed before release.
|
|
256
|
+
|
|
257
|
+
Initial package-surface inventory:
|
|
258
|
+
|
|
259
|
+
| Group | Paths | Current decision |
|
|
260
|
+
| --- | --- | --- |
|
|
261
|
+
| A: published in `0.1.5` | `lib/cli-args.mjs`, `lib/db-schema.mjs`, `lib/discover.mjs`, `lib/errors.mjs`, `lib/format.mjs`, `lib/guidance.mjs`, `lib/json-file.mjs`, `lib/package-meta.mjs`, `lib/release-notes.mjs`, `lib/runtime-paths.mjs`, `lib/setup.mjs`, `lib/shell-path.mjs`, `lib/shim-script.mjs`, `lib/web-http.mjs`, `lib/web-runtime.mjs`, `lib/web-ui-template.mjs` | Keep for the next release, even if some are now compatibility re-exports. Removing them would be a package-surface break. |
|
|
262
|
+
| A: current internal top-level runtime refs | `lib/cli-runtime.mjs`, `lib/coordination-state.mjs`, `lib/handoff.mjs`, `lib/project-context.mjs`, `lib/task-cli.mjs`, `lib/tmux.mjs` | Keep until a focused cleanup moves current internal imports to the target directories. Do not delete these as pure compatibility shims today. |
|
|
263
|
+
| B/C candidates: new re-export-only paths with no current runtime ref | `lib/automation.mjs`, `lib/help.mjs`, `lib/locks.mjs`, `lib/messages.mjs`, `lib/peer-bindings.mjs`, `lib/peer-format.mjs`, `lib/peer-identity.mjs`, `lib/project-registry.mjs`, `lib/provider-commands.mjs`, `lib/runtime-client.mjs`, `lib/runtime-state.mjs`, `lib/session-launch.mjs`, `lib/state-render.mjs`, `lib/task-liveness.mjs`, `lib/task-store.mjs`, `lib/team-planning.mjs`, `lib/timeline.mjs`, `lib/web-peer-actions.mjs` | Treat as C only if the project decides they have no migration compatibility value. Otherwise keep for one release as B and document them as compatibility-only deep imports. |
|
|
264
|
+
| C: remove before publish | None confirmed yet | Do not delete by guess. A candidate becomes C only after checking it was not in `0.1.5`, is not imported internally, and has no release compatibility value. |
|
|
265
|
+
|
|
266
|
+
### Watch Items
|
|
267
|
+
|
|
268
|
+
- `lib/handoff.mjs`: decide core coordination versus CLI command helper.
|
|
269
|
+
- `lib/session-launch.mjs`: review mixed core session and terminal/tmux
|
|
270
|
+
compatibility exports.
|
|
271
|
+
- `lib/core/coordination/tasks.mjs`: split pure task policy from DB store style
|
|
272
|
+
SQL/transactions.
|
|
273
|
+
- `lib/core/coordination/{automation,timeline}.mjs`: remove dependency on
|
|
274
|
+
top-level `lib/format.mjs`.
|
|
275
|
+
- `lib/coordination-state.mjs`: keep as interim assembler, but split before
|
|
276
|
+
claiming final architecture.
|
|
277
|
+
- `lib/runtime/{client,state}.mjs`: remove reverse dependency on
|
|
278
|
+
`lib/web/runtime.mjs`.
|
|
279
|
+
- `lib/web/{runtime,peer-actions}.mjs`: remove direct dependency on CLI parsing
|
|
280
|
+
helpers.
|
|
281
|
+
- `lib/web/peer-actions.mjs`: remove direct dependency on UI state-render
|
|
282
|
+
helpers for non-render normalization.
|
|
283
|
+
- `scripts/regression.mjs`: current test coverage is valuable, but its size
|
|
284
|
+
should be split after the architecture stack is stable.
|
|
285
|
+
- `bin/hcc.mjs`: still contains large command and Web orchestration areas; do
|
|
286
|
+
not continue extracting from it until this audit decides branch strategy.
|
|
287
|
+
|
|
288
|
+
## Current Status
|
|
289
|
+
|
|
290
|
+
Peer feedback from `#235`, `#236`, and `#237` has been merged into this audit.
|
|
291
|
+
The audit conclusion is:
|
|
292
|
+
|
|
293
|
+
- The final code shape is mostly reasonable.
|
|
294
|
+
- The early commit history is not clean architecture history.
|
|
295
|
+
- Use a new rebuild branch from `origin/master` if clean history matters.
|
|
296
|
+
- Keep the current `master` stack only if the project accepts noisy local
|
|
297
|
+
history and completes the release cleanup items above before publish.
|
|
298
|
+
- Do not resume release task `#233` until this audit decision is accepted.
|
package/lib/cli-args.mjs
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import process from 'node:process';
|
|
2
|
+
import { CliError } from './shared/errors.mjs';
|
|
3
|
+
|
|
4
|
+
export function splitGlobalArgs(argv) {
|
|
5
|
+
const global = { json: false, root: null, db: null };
|
|
6
|
+
const rest = [];
|
|
7
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
8
|
+
const arg = argv[i];
|
|
9
|
+
if (arg === '--json') {
|
|
10
|
+
global.json = true;
|
|
11
|
+
} else if (arg === '--root') {
|
|
12
|
+
global.root = argv[++i];
|
|
13
|
+
} else if (arg.startsWith('--root=')) {
|
|
14
|
+
global.root = arg.slice('--root='.length);
|
|
15
|
+
} else if (arg === '--db') {
|
|
16
|
+
global.db = argv[++i];
|
|
17
|
+
} else if (arg.startsWith('--db=')) {
|
|
18
|
+
global.db = arg.slice('--db='.length);
|
|
19
|
+
} else {
|
|
20
|
+
rest.push(arg);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return { global, rest };
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function parseOpts(args, spec = {}) {
|
|
27
|
+
const booleans = new Set(spec.booleans || []);
|
|
28
|
+
const arrays = new Set(spec.arrays || []);
|
|
29
|
+
const opts = { _: [] };
|
|
30
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
31
|
+
const arg = args[i];
|
|
32
|
+
if (!arg.startsWith('--') || arg === '--') {
|
|
33
|
+
opts._.push(arg);
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
let key;
|
|
37
|
+
let value;
|
|
38
|
+
const eq = arg.indexOf('=');
|
|
39
|
+
if (eq >= 0) {
|
|
40
|
+
key = arg.slice(2, eq);
|
|
41
|
+
value = arg.slice(eq + 1);
|
|
42
|
+
} else {
|
|
43
|
+
key = arg.slice(2);
|
|
44
|
+
if (booleans.has(key)) {
|
|
45
|
+
value = true;
|
|
46
|
+
} else {
|
|
47
|
+
value = args[++i];
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
if (!key) throw new CliError('BAD_ARGS', `Invalid option: ${arg}`);
|
|
51
|
+
if (value === undefined) throw new CliError('BAD_ARGS', `Missing value for --${key}`);
|
|
52
|
+
if (arrays.has(key)) {
|
|
53
|
+
if (!opts[key]) opts[key] = [];
|
|
54
|
+
opts[key].push(value);
|
|
55
|
+
} else {
|
|
56
|
+
opts[key] = value;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return opts;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function wantsHelp(args) {
|
|
63
|
+
const stop = args.indexOf('--');
|
|
64
|
+
const scan = stop >= 0 ? args.slice(0, stop) : args;
|
|
65
|
+
const index = scan.findIndex((arg) => arg === '--help' || arg === '-h');
|
|
66
|
+
if (index < 0) return false;
|
|
67
|
+
return index <= 1 || !String(scan[index - 1] || '').startsWith('--');
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function validateOpts(command, opts, allowed = []) {
|
|
71
|
+
const allowedSet = new Set(['_', ...allowed]);
|
|
72
|
+
for (const key of Object.keys(opts)) {
|
|
73
|
+
if (!allowedSet.has(key)) throw new CliError('BAD_ARGS', `${command}: unknown option --${key}`);
|
|
74
|
+
}
|
|
75
|
+
if (opts._?.length) throw new CliError('BAD_ARGS', `${command}: unexpected argument ${opts._[0]}`);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function required(opts, key, envName = null) {
|
|
79
|
+
const value = opts[key] || (envName ? process.env[envName] : null);
|
|
80
|
+
if (!value) throw new CliError('BAD_ARGS', `Missing --${key}${envName ? ` or $${envName}` : ''}`);
|
|
81
|
+
return value;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export function intOpt(opts, key, fallback = null) {
|
|
85
|
+
if (opts[key] === undefined || opts[key] === null || opts[key] === '') return fallback;
|
|
86
|
+
const value = Number.parseInt(String(opts[key]), 10);
|
|
87
|
+
if (!Number.isFinite(value)) throw new CliError('BAD_ARGS', `--${key} must be an integer`);
|
|
88
|
+
return value;
|
|
89
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import process from 'node:process';
|
|
4
|
+
import { projectDbPath } from './runtime/paths.mjs';
|
|
5
|
+
|
|
6
|
+
export function createContext(global = {}, deps = {}) {
|
|
7
|
+
const cwd = deps.cwd || process.cwd();
|
|
8
|
+
const detectRoot = deps.detectRoot;
|
|
9
|
+
if (typeof detectRoot !== 'function') throw new TypeError('createContext requires deps.detectRoot');
|
|
10
|
+
const root = detectRoot(cwd, global.root);
|
|
11
|
+
const dbPath = path.resolve(global.db || process.env.HCC_DB || projectDbPath(root));
|
|
12
|
+
return { cwd, root, dbPath, json: global.json, explicitRoot: Boolean(global.root || process.env.HCC_ROOT) };
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function shellCommand(args, quoteArg) {
|
|
16
|
+
if (typeof quoteArg !== 'function') throw new TypeError('shellCommand requires quoteArg');
|
|
17
|
+
return args.map(quoteArg).join(' ');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function tailFile(file, maxBytes = 12000) {
|
|
21
|
+
try {
|
|
22
|
+
const stat = fs.statSync(file);
|
|
23
|
+
const size = Math.min(stat.size, maxBytes);
|
|
24
|
+
const fd = fs.openSync(file, 'r');
|
|
25
|
+
try {
|
|
26
|
+
const buf = Buffer.alloc(size);
|
|
27
|
+
fs.readSync(fd, buf, 0, size, Math.max(0, stat.size - size));
|
|
28
|
+
return buf.toString('utf8').trim();
|
|
29
|
+
} finally {
|
|
30
|
+
fs.closeSync(fd);
|
|
31
|
+
}
|
|
32
|
+
} catch {
|
|
33
|
+
return '';
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function commandPath(argv = process.argv) {
|
|
38
|
+
try { return fs.realpathSync(argv[1]); }
|
|
39
|
+
catch { return path.resolve(argv[1]); }
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function packageRoot(argv = process.argv) {
|
|
43
|
+
return path.resolve(path.dirname(commandPath(argv)), '..');
|
|
44
|
+
}
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import {
|
|
2
|
+
deriveAutomation,
|
|
3
|
+
renderAutomationContext
|
|
4
|
+
} from './core/coordination/automation.mjs';
|
|
5
|
+
import {
|
|
6
|
+
annotateTasksWithLiveness,
|
|
7
|
+
formatOpenTaskLine
|
|
8
|
+
} from './core/peers/liveness.mjs';
|
|
9
|
+
import { lockLabel } from './core/coordination/locks.mjs';
|
|
10
|
+
import { timelineFromRows } from './core/coordination/timeline.mjs';
|
|
11
|
+
|
|
12
|
+
const DEFAULT_ACTIVE_PEER_TTL = 600;
|
|
13
|
+
const DEFAULT_LOCK_TTL = 900;
|
|
14
|
+
const DEFAULT_CLI_NAME = 'hcc';
|
|
15
|
+
|
|
16
|
+
function defaultNow() {
|
|
17
|
+
return Math.floor(Date.now() / 1000);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function requireFn(value, name) {
|
|
21
|
+
if (typeof value !== 'function') throw new TypeError(`createCoordinationState requires deps.${name}`);
|
|
22
|
+
return value;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function createCoordinationState(deps = {}) {
|
|
26
|
+
const activePeerTtl = Number(deps.activePeerTtl ?? DEFAULT_ACTIVE_PEER_TTL);
|
|
27
|
+
const cliName = deps.cliName || DEFAULT_CLI_NAME;
|
|
28
|
+
const connect = requireFn(deps.connect, 'connect');
|
|
29
|
+
const defaultLockTtl = Number(deps.defaultLockTtl ?? DEFAULT_LOCK_TTL);
|
|
30
|
+
const now = typeof deps.now === 'function' ? deps.now : defaultNow;
|
|
31
|
+
const queryInbox = requireFn(deps.queryInbox, 'queryInbox');
|
|
32
|
+
const queryOpenTasks = requireFn(deps.queryOpenTasks, 'queryOpenTasks');
|
|
33
|
+
const queryTimelineMessages = requireFn(deps.queryTimelineMessages, 'queryTimelineMessages');
|
|
34
|
+
const touchCurrentPeer = typeof deps.touchCurrentPeer === 'function'
|
|
35
|
+
? deps.touchCurrentPeer
|
|
36
|
+
: () => {};
|
|
37
|
+
|
|
38
|
+
function collectStateSnapshot(db, ctx, peer = null, opts = {}) {
|
|
39
|
+
const t = now();
|
|
40
|
+
const peers = db.prepare(`
|
|
41
|
+
SELECT id, kind, role, status, worktree, branch, pid, capabilities,
|
|
42
|
+
created_at, last_seen_at, (? - last_seen_at) AS age_sec
|
|
43
|
+
FROM peers
|
|
44
|
+
ORDER BY last_seen_at DESC, id ASC
|
|
45
|
+
LIMIT 200
|
|
46
|
+
`).all(t);
|
|
47
|
+
const taskRows = queryOpenTasks(db, 200);
|
|
48
|
+
const locks = db.prepare(`
|
|
49
|
+
SELECT resource, base_resource, scope, owner, task_id, reason, expires_at, created_at
|
|
50
|
+
FROM locks
|
|
51
|
+
WHERE expires_at > ?
|
|
52
|
+
ORDER BY resource ASC
|
|
53
|
+
LIMIT 200
|
|
54
|
+
`).all(t);
|
|
55
|
+
const tasks = annotateTasksWithLiveness(taskRows, peers, locks, t, activePeerTtl);
|
|
56
|
+
const messages = peer
|
|
57
|
+
? queryInbox(db, peer, false, 50)
|
|
58
|
+
: db.prepare(`
|
|
59
|
+
SELECT id, sender, recipient, task_id, kind, body, reply_to, thread_id, created_at
|
|
60
|
+
FROM messages
|
|
61
|
+
ORDER BY id DESC
|
|
62
|
+
LIMIT 50
|
|
63
|
+
`).all().reverse();
|
|
64
|
+
const timelineMessages = queryTimelineMessages(db, peer, 80);
|
|
65
|
+
const handoffs = db.prepare(`
|
|
66
|
+
SELECT id, task_id, from_peer, to_peer, summary, changed_files, tests, risks, created_at
|
|
67
|
+
FROM handoffs
|
|
68
|
+
ORDER BY id DESC
|
|
69
|
+
LIMIT 50
|
|
70
|
+
`).all().reverse();
|
|
71
|
+
const events = db.prepare(`
|
|
72
|
+
SELECT id, type, actor, task_id, payload, created_at
|
|
73
|
+
FROM events
|
|
74
|
+
ORDER BY id DESC
|
|
75
|
+
LIMIT 80
|
|
76
|
+
`).all().reverse();
|
|
77
|
+
const snapshot = {
|
|
78
|
+
root: ctx.root,
|
|
79
|
+
db: ctx.dbPath,
|
|
80
|
+
now: t,
|
|
81
|
+
active_peer_ttl: activePeerTtl,
|
|
82
|
+
peers,
|
|
83
|
+
tasks,
|
|
84
|
+
locks,
|
|
85
|
+
messages,
|
|
86
|
+
handoffs,
|
|
87
|
+
events
|
|
88
|
+
};
|
|
89
|
+
snapshot.timeline = timelineFromRows({ messages: timelineMessages, handoffs, tasks, locks, events }, peer);
|
|
90
|
+
snapshot.automation = deriveAutomation(snapshot, peer, opts, {
|
|
91
|
+
activePeerTtl,
|
|
92
|
+
defaultLockTtl,
|
|
93
|
+
cliName
|
|
94
|
+
});
|
|
95
|
+
return snapshot;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function buildHookCoordinationContext(db, ctx, peerId) {
|
|
99
|
+
const snapshot = collectStateSnapshot(db, ctx, peerId);
|
|
100
|
+
const openTasks = snapshot.tasks.slice(0, 8);
|
|
101
|
+
const unread = snapshot.messages.slice(0, 5);
|
|
102
|
+
const peers = snapshot.peers.slice(0, 8);
|
|
103
|
+
const parts = [
|
|
104
|
+
'[hello-cc coordination]',
|
|
105
|
+
`peer: ${peerId}`,
|
|
106
|
+
'This is live project coordination context injected by hello-cc.',
|
|
107
|
+
'You are not isolated for project coordination: hcc is the source of truth for other Claude/Codex/shell sessions in this project.',
|
|
108
|
+
'If the user asks what other sessions are doing, what tasks exist, or whether you can see other sessions, do not answer from generic model knowledge and do not say sessions are isolated. Run hcc status, hcc state, hcc peers, hcc task list, hcc msg inbox, and hcc lock list, then answer from those results.',
|
|
109
|
+
'Tasks are project work facts, not read/unread items. Open tasks stay relevant to every session until they are marked done or abandoned. Messages are the unread/ack notification channel.',
|
|
110
|
+
'If you already own a current task, continue that task until handoff/done/blocked; do not claim a different task just because a new prompt arrived.',
|
|
111
|
+
'When a hello-cc message asks for a response, reply with hcc msg reply --id <message-id> --body "<answer>" so the answer stays in the same thread.'
|
|
112
|
+
];
|
|
113
|
+
|
|
114
|
+
if (peers.length > 0) {
|
|
115
|
+
parts.push('[hello-cc known peers]');
|
|
116
|
+
parts.push(...peers.map((peer) => {
|
|
117
|
+
const age = Math.max(0, snapshot.now - Number(peer.last_seen_at || 0));
|
|
118
|
+
const active = age <= activePeerTtl ? 'active' : 'stale';
|
|
119
|
+
return `- ${peer.id} ${peer.kind || 'other'} ${peer.status || 'idle'} ${active}`;
|
|
120
|
+
}));
|
|
121
|
+
} else {
|
|
122
|
+
parts.push('[hello-cc known peers]\n(none)');
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (snapshot.automation.current_task) {
|
|
126
|
+
const task = snapshot.automation.current_task;
|
|
127
|
+
parts.push('[hello-cc current task]');
|
|
128
|
+
parts.push(`#${task.id} ${task.status}: ${task.title}`);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (openTasks.length > 0) {
|
|
132
|
+
parts.push('[hello-cc open tasks]');
|
|
133
|
+
parts.push(...openTasks.map((task) => `- ${formatOpenTaskLine(task)}`));
|
|
134
|
+
} else {
|
|
135
|
+
parts.push('[hello-cc open tasks]\n(none)');
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (unread.length > 0) {
|
|
139
|
+
parts.push('[hello-cc unread messages]');
|
|
140
|
+
parts.push(...unread.map((m) =>
|
|
141
|
+
`- #${m.id} from ${m.sender}${m.task_id ? ` task #${m.task_id}` : ''}${m.reply_to ? ` reply #${m.reply_to}` : ''}: ${m.body}`
|
|
142
|
+
));
|
|
143
|
+
} else {
|
|
144
|
+
parts.push('[hello-cc unread messages]\n(none)');
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (snapshot.locks.length > 0) {
|
|
148
|
+
parts.push('[hello-cc active locks]');
|
|
149
|
+
parts.push(...snapshot.locks.slice(0, 8).map((lock) =>
|
|
150
|
+
`- ${lockLabel(lock)} owner=${lock.owner}${lock.task_id ? ` task #${lock.task_id}` : ''}`));
|
|
151
|
+
} else {
|
|
152
|
+
parts.push('[hello-cc active locks]\n(none)');
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
parts.push(renderAutomationContext(snapshot.automation));
|
|
156
|
+
|
|
157
|
+
return { text: parts.join('\n'), messages: unread };
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function ackMessages(db, peerId, messages) {
|
|
161
|
+
if (!messages.length) return;
|
|
162
|
+
const t = now();
|
|
163
|
+
for (const m of messages) {
|
|
164
|
+
db.prepare(`
|
|
165
|
+
INSERT INTO message_reads(message_id, peer, read_at)
|
|
166
|
+
VALUES (?, ?, ?)
|
|
167
|
+
ON CONFLICT(message_id, peer) DO UPDATE SET read_at = excluded.read_at
|
|
168
|
+
`).run(m.id, peerId, t);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function statusSummary(ctx, peer = null, identity = null) {
|
|
173
|
+
const db = connect(ctx);
|
|
174
|
+
try {
|
|
175
|
+
if (identity) touchCurrentPeer(db, ctx, identity, null, 'shell');
|
|
176
|
+
const t = now();
|
|
177
|
+
const activePeers = db.prepare('SELECT COUNT(*) AS n FROM peers WHERE last_seen_at >= ?').get(t - activePeerTtl).n;
|
|
178
|
+
const stalePeers = db.prepare('SELECT COUNT(*) AS n FROM peers WHERE last_seen_at < ?').get(t - activePeerTtl).n;
|
|
179
|
+
const taskRows = db.prepare('SELECT status, COUNT(*) AS n FROM tasks GROUP BY status ORDER BY status').all();
|
|
180
|
+
const locks = db.prepare('SELECT COUNT(*) AS n FROM locks WHERE expires_at > ?').get(t).n;
|
|
181
|
+
const unread = peer ? queryInbox(db, peer, false, 1000).length : null;
|
|
182
|
+
const recent = db.prepare('SELECT * FROM events ORDER BY id DESC LIMIT 8').all().reverse();
|
|
183
|
+
return {
|
|
184
|
+
root: ctx.root,
|
|
185
|
+
db: ctx.dbPath,
|
|
186
|
+
active_peers: activePeers,
|
|
187
|
+
stale_peers: stalePeers,
|
|
188
|
+
tasks: taskRows,
|
|
189
|
+
active_locks: locks,
|
|
190
|
+
unread,
|
|
191
|
+
recent_events: recent
|
|
192
|
+
};
|
|
193
|
+
} finally {
|
|
194
|
+
db.close();
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function statusSnapshot(ctx, peer = null, opts = {}) {
|
|
199
|
+
const db = connect(ctx);
|
|
200
|
+
try {
|
|
201
|
+
return collectStateSnapshot(db, ctx, peer, opts);
|
|
202
|
+
} finally {
|
|
203
|
+
try {
|
|
204
|
+
db.close();
|
|
205
|
+
} catch {
|
|
206
|
+
// Ignore close failures for short-lived snapshots.
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return {
|
|
212
|
+
ackMessages,
|
|
213
|
+
buildHookCoordinationContext,
|
|
214
|
+
collectStateSnapshot,
|
|
215
|
+
statusSnapshot,
|
|
216
|
+
statusSummary
|
|
217
|
+
};
|
|
218
|
+
}
|