@logicseek/hello-cc 0.1.9 → 1.0.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.
Files changed (108) hide show
  1. package/CHANGELOG.md +59 -0
  2. package/README.md +18 -3
  3. package/README.zh-CN.md +17 -3
  4. package/bin/hcc.mjs +3 -5656
  5. package/docs/README.md +8 -0
  6. package/docs/README.zh-CN.md +6 -0
  7. package/docs/architecture.md +29 -18
  8. package/docs/architecture.zh-CN.md +20 -10
  9. package/docs/commands.md +13 -4
  10. package/docs/commands.zh-CN.md +13 -4
  11. package/docs/current-state-review-2026-08.md +341 -0
  12. package/docs/defect-review-2026-07.md +382 -0
  13. package/docs/guide.md +39 -3
  14. package/docs/guide.zh-CN.md +34 -2
  15. package/docs/superpowers/plans/2026-08-03-runtime-safety-plan.md +294 -0
  16. package/docs/superpowers/plans/2026-08-03-v1-data-identity-plan.md +400 -0
  17. package/docs/superpowers/plans/2026-08-03-v1-release-verification-plan.md +284 -0
  18. package/docs/superpowers/plans/2026-08-03-web-api-hardening-plan.md +303 -0
  19. package/docs/superpowers/plans/2026-08-04-runtime-buffer-gc-two-phase.md +71 -0
  20. package/docs/superpowers/specs/2026-08-03-runtime-safety-design.md +117 -0
  21. package/docs/superpowers/specs/2026-08-03-v1-data-identity-design.md +120 -0
  22. package/docs/superpowers/specs/2026-08-03-v1-release-verification-design.md +117 -0
  23. package/docs/superpowers/specs/2026-08-03-web-api-hardening-design.md +104 -0
  24. package/lib/cli/app.mjs +642 -0
  25. package/lib/cli/commands/coordination.mjs +247 -0
  26. package/lib/cli/commands/doctor.mjs +81 -0
  27. package/lib/cli/commands/gc.mjs +852 -0
  28. package/lib/cli/commands/hook.mjs +205 -0
  29. package/lib/cli/commands/install.mjs +294 -0
  30. package/lib/cli/commands/lifecycle.mjs +101 -0
  31. package/lib/cli/commands/lock.mjs +197 -0
  32. package/lib/cli/commands/misc.mjs +61 -0
  33. package/lib/cli/commands/msg.mjs +152 -0
  34. package/lib/cli/commands/peer.mjs +233 -0
  35. package/lib/cli/commands/query.mjs +96 -0
  36. package/lib/cli/commands/run.mjs +463 -0
  37. package/lib/cli/commands/task.mjs +405 -0
  38. package/lib/cli/commands/team.mjs +131 -0
  39. package/lib/cli/commands/tmux.mjs +838 -0
  40. package/lib/cli/commands/up.mjs +135 -0
  41. package/lib/cli-args.mjs +16 -2
  42. package/lib/coordination-state.mjs +112 -51
  43. package/lib/core/coordination/automation.mjs +5 -8
  44. package/lib/core/coordination/clock-safety.mjs +323 -0
  45. package/lib/core/coordination/event-retention.mjs +17 -0
  46. package/lib/core/coordination/gc-plan.mjs +614 -0
  47. package/lib/core/coordination/lease-renewal.mjs +102 -0
  48. package/lib/core/coordination/lock-evidence.mjs +77 -0
  49. package/lib/core/coordination/optimistic-evidence.mjs +26 -0
  50. package/lib/core/coordination/tasks.mjs +156 -36
  51. package/lib/core/peers/evidence-runtime.mjs +312 -0
  52. package/lib/core/peers/evidence.mjs +103 -0
  53. package/lib/core/peers/hook-owner.mjs +32 -0
  54. package/lib/core/peers/liveness.mjs +44 -4
  55. package/lib/core/peers/peer-helpers.mjs +121 -0
  56. package/lib/core/peers/session.mjs +8 -2
  57. package/lib/core/peers/tmux-safety.mjs +290 -0
  58. package/lib/core/sessions/launch.mjs +13 -1
  59. package/lib/db/connection.mjs +104 -0
  60. package/lib/db/events.mjs +34 -0
  61. package/lib/db/migration-backup.mjs +225 -0
  62. package/lib/db/schema.mjs +102 -5
  63. package/lib/db/stores/peers.mjs +34 -0
  64. package/lib/integrations/peers/identity.mjs +62 -16
  65. package/lib/integrations/shims/script.mjs +111 -9
  66. package/lib/process/identity.mjs +192 -0
  67. package/lib/process/pty-lifecycle.mjs +149 -0
  68. package/lib/runtime/buffer-directory-lease.mjs +47 -0
  69. package/lib/runtime/buffer-evidence.mjs +336 -0
  70. package/lib/runtime/buffer-gc-protocol.mjs +167 -0
  71. package/lib/runtime/buffer-gc.mjs +270 -0
  72. package/lib/runtime/client.mjs +60 -7
  73. package/lib/runtime/fatal-shutdown.mjs +54 -0
  74. package/lib/runtime/project-path.mjs +139 -0
  75. package/lib/runtime/projects.mjs +320 -40
  76. package/lib/runtime/state.mjs +227 -27
  77. package/lib/shared/cleanup-error.mjs +54 -0
  78. package/lib/shared/clock-grace.mjs +106 -0
  79. package/lib/shared/errors.mjs +9 -0
  80. package/lib/shared/file-lock.mjs +370 -0
  81. package/lib/shared/json-file.mjs +6 -2
  82. package/lib/shared/redact.mjs +60 -0
  83. package/lib/shared/socket-lock-worker.mjs +201 -0
  84. package/lib/terminal/tmux.mjs +78 -4
  85. package/lib/tmux.mjs +4 -0
  86. package/lib/ui/help.mjs +53 -15
  87. package/lib/web/api-version.mjs +42 -0
  88. package/lib/web/auto-attach.mjs +185 -0
  89. package/lib/web/buffer-gc-runtime.mjs +175 -0
  90. package/lib/web/cookie-auth.mjs +119 -0
  91. package/lib/web/external-sessions.mjs +254 -0
  92. package/lib/web/http-routes.mjs +542 -0
  93. package/lib/web/http.mjs +135 -6
  94. package/lib/web/liveness-reaper.mjs +145 -0
  95. package/lib/web/peer-actions.mjs +132 -23
  96. package/lib/web/project-contexts.mjs +178 -0
  97. package/lib/web/pty-sessions.mjs +203 -0
  98. package/lib/web/runtime-main.mjs +714 -0
  99. package/lib/web/runtime.mjs +91 -36
  100. package/lib/web/session-serialize.mjs +0 -0
  101. package/lib/web/startup.mjs +333 -0
  102. package/lib/web/tls.mjs +365 -0
  103. package/lib/web/tmux-sessions.mjs +1361 -0
  104. package/lib/web/tmux-stream.mjs +166 -0
  105. package/lib/web/ui-template.mjs +152 -20
  106. package/package.json +5 -2
  107. package/scripts/check-free-identifiers.mjs +290 -0
  108. package/scripts/regression.mjs +5397 -263
@@ -0,0 +1,117 @@
1
+ # Runtime Safety, Clock, GC, and Registry Design
2
+
3
+ Status: approved in conversation on 2026-08-03.
4
+
5
+ ## Purpose
6
+
7
+ Close destructive-operation and ownership races without forcing every project
8
+ to wait after normal idle time. Verified process evidence is authoritative;
9
+ clock grace is reserved for unknown evidence.
10
+
11
+ ## Clock Observation
12
+
13
+ The meta table stores a last-observed wall-clock watermark and the active grace
14
+ deadline. Observation runs before ownership-changing or destructive operations,
15
+ including lock acquisition, takeover, hook/heartbeat recovery, reaping, and GC.
16
+ Pure read-only commands do not update the watermark, preserving read-only DB
17
+ behavior.
18
+
19
+ A clock observation transaction:
20
+
21
+ 1. reads the previous watermark and current grace deadline;
22
+ 2. evaluates backward movement and long forward gaps;
23
+ 3. for ownership operations, checks whether the gap crossed a peer or lock
24
+ expiry boundary whose owner is currently `unknown`;
25
+ 4. for GC, checks whether suspicious backward/forward movement or a long gap
26
+ crossed the requested age cutoff for any deletion category, independent of
27
+ owner evidence;
28
+ 5. atomically extends grace to `max(existing, now + 120 seconds)` when needed;
29
+ 6. writes the new watermark only after the safety decision succeeds.
30
+
31
+ A verified live owner is renewed immediately from persisted `ttl_sec`. A
32
+ verified dead owner may expire immediately. Only unknown evidence is delayed by
33
+ grace. Failure to persist a required grace blocks the current destructive or
34
+ ownership-changing operation and returns an observable error.
35
+
36
+ The Web runtime also compares wall-clock movement with its monotonic probe and
37
+ uses the same database transaction. Concurrent probes can extend but never
38
+ shorten grace.
39
+
40
+ ## Grace Semantics
41
+
42
+ While grace is active, every age-based deletion is deferred:
43
+
44
+ - expired or apparently expired locks;
45
+ - stale peers and peer bindings;
46
+ - events, completed tasks, messages, and handoffs;
47
+ - buffer files selected only by mtime.
48
+
49
+ Explicit `exited` peers and artifacts proven dead by identity may still be
50
+ cleaned. Results expose separate `deleted`, `protected`, and `deferred` counts.
51
+
52
+ ## Buffer GC Arbitration
53
+
54
+ The buffer pruning policy is a shared helper that receives a fixed cutoff,
55
+ dry-run flag, project context, and protected absolute paths. It never recomputes
56
+ the cutoff during a run.
57
+
58
+ When a healthy compatible runtime exists, manual GC calls an authenticated
59
+ internal API. The runtime computes protection from the actual files referenced
60
+ by its session map and performs synchronous pruning in its event loop. Session
61
+ creation and replacement cannot interleave with that synchronous decision. New
62
+ files created after the fixed cutoff are not eligible.
63
+
64
+ If a runtime pointer exists but the runtime is unreachable or API-incompatible,
65
+ buffer deletion fails closed and reports deferred files. Safe database cleanup
66
+ may continue.
67
+
68
+ Without a runtime, local GC protects:
69
+
70
+ - external file groups whose wrapper or child identity is live or unknown;
71
+ - tmux pipes belonging to verified live or unknown managed panes;
72
+ - any legacy artifact whose ownership cannot be proved dead.
73
+
74
+ Only old artifacts with definitive dead or orphan evidence are deleted.
75
+
76
+ ## GC Command Contract
77
+
78
+ `--older-than` must be zero or greater. Invalid values fail before opening a
79
+ write connection or deleting any file.
80
+
81
+ `hcc gc` remains dry-run by default. `--yes` removes technical state only.
82
+ Business history removal requires both `--history` and `--yes`. Open-task
83
+ handoffs, live-owner records, and unknown session artifacts are never removed
84
+ only because of age. Dry-run and apply execute the same planner.
85
+
86
+ A WAL checkpoint runs only after successful applied database cleanup. A busy
87
+ checkpoint is reported without converting successful safe cleanup into failure.
88
+
89
+ ## Project Registry Lock
90
+
91
+ Registry read-modify-write is guarded by an atomic lock directory adjacent to
92
+ `projects.json`. Lock owner metadata includes process identity and creation
93
+ time. Acquisition uses bounded retry. A lock is reclaimed only when its owner is
94
+ definitively dead; unknown ownership times out with an error rather than being
95
+ stolen.
96
+
97
+ After acquiring the lock, the writer re-reads the registry, merges by canonical
98
+ real root, and writes with the existing atomic temp-and-rename helper. A changed
99
+ DB path updates immediately. The 60-second throttle applies only when root and
100
+ DB are both unchanged.
101
+
102
+ Authenticated Web users may continue registering arbitrary existing server
103
+ directories. This is an explicitly accepted product risk, not an isolation
104
+ guarantee.
105
+
106
+ ## Acceptance Criteria
107
+
108
+ - CLI-only wake with a live process renews ownership without a blanket delay.
109
+ - CLI-only wake with unknown evidence enters grace before takeover or GC.
110
+ - A GC after a suspicious clock gap defers age-based history deletion even when
111
+ no peer or lock candidate exists.
112
+ - Grace never shrinks under concurrent writers.
113
+ - Manual GC preserves live external and tmux artifacts with old mtimes.
114
+ - Unreachable runtime state defers buffer deletion.
115
+ - Negative retention is rejected without mutation.
116
+ - Grace defers every wall-clock-based history deletion.
117
+ - Concurrent registry writers retain both projects and update changed DB paths.
@@ -0,0 +1,120 @@
1
+ # hello-cc v1 Data and Identity Design
2
+
3
+ Status: approved in conversation on 2026-08-03.
4
+
5
+ ## Purpose
6
+
7
+ Define the breaking v1 data contract, schema migration, process identity model,
8
+ and provider peer identity semantics. This specification intentionally does not
9
+ provide downgrade compatibility or map pre-v1 provider peer IDs to v1 IDs.
10
+
11
+ ## Product Decisions
12
+
13
+ - Release the result as package version `1.0.0`.
14
+ - Use database schema version 7.
15
+ - A schema v7 database is not supported by pre-v1 binaries.
16
+ - Provider peer IDs use the v1 full-value hash algorithm for every provider ID,
17
+ including UUIDs and user-defined session names.
18
+ - Pre-v1 peer IDs, tasks, locks, messages, and bindings are not merged into the
19
+ new v1 identity automatically.
20
+ - Migration must create a consistent database backup before the first v7 write.
21
+
22
+ ## Migration Contract
23
+
24
+ Before migrating a v5 or v6 database, hello-cc must create a SQLite-consistent
25
+ snapshot next to the source database. The backup name includes the source
26
+ schema version and a collision-resistant timestamp suffix. It must never
27
+ overwrite an existing file.
28
+
29
+ The backup is produced through the open SQLite connection with `VACUUM INTO`,
30
+ not by copying `mesh.db` while WAL frames may still be pending. Migration stops
31
+ without changing the source database if backup creation or backup integrity
32
+ validation fails. A successful backup is opened read-only and must pass
33
+ `PRAGMA quick_check` before schema migration begins.
34
+
35
+ Registered sibling projects follow the same contract independently. A failed
36
+ sibling backup or migration is reported and isolated; it must not partially
37
+ migrate that sibling or fail the active project's command.
38
+
39
+ ## Schema v7
40
+
41
+ Schema v7 adds process identity fields to `peers`:
42
+
43
+ - `pid_start_token TEXT`: opaque platform-derived process start identity.
44
+ - `pid_command_hash TEXT`: hash of the normalized executable/command identity.
45
+
46
+ Both fields are nullable. Missing or unreadable identity evidence means
47
+ `unknown`; it never means live or dead.
48
+
49
+ Existing v6 `locks.ttl_sec` remains required. Invalid or absent historical TTL
50
+ values are repaired to the documented default, capped at one hour when derived
51
+ from historical timestamps.
52
+
53
+ The schema migration history records v7 exactly once. `doctor` reports the
54
+ current schema, supported schema, backup location when known, and the explicit
55
+ no-downgrade contract.
56
+
57
+ ## Process Identity
58
+
59
+ A shared process identity helper returns one of:
60
+
61
+ - a verified identity `{ pid, startToken, commandHash }`;
62
+ - `null` when the process does not exist;
63
+ - `unknown` when the process cannot be inspected safely.
64
+
65
+ Linux identity combines boot ID, `/proc/<pid>/stat` start ticks, and normalized
66
+ executable identity. macOS identity combines boot time, `ps` process start time,
67
+ PID, and normalized command identity. Inspection failures, permission errors,
68
+ or malformed output return `unknown`.
69
+
70
+ A stored identity is live only when the current identity matches every stored
71
+ component. A missing PID is dead only when the OS definitively reports that the
72
+ PID does not exist. A reused PID with a different start token or command hash is
73
+ dead for the stored peer.
74
+
75
+ External session metadata stores separate wrapper and child identities. New
76
+ metadata is written atomically. Legacy metadata without fingerprints is treated
77
+ as unknown unless both referenced PIDs are definitively absent.
78
+
79
+ tmux identity requires all of the following:
80
+
81
+ - the managed session name matches the hello-cc naming contract;
82
+ - the pane still exists;
83
+ - `HCC_ROOT` resolves to the expected project root;
84
+ - the pane process identity matches the stored identity when one is available.
85
+
86
+ ## Liveness Precedence
87
+
88
+ All ownership, lock, reaper, and GC decisions consume one shared resolver with
89
+ the result `live`, `dead`, or `unknown`.
90
+
91
+ 1. Explicit administrative `exited` status is dead.
92
+ 2. Verified tmux or process identity is live.
93
+ 3. `detached` is not dead by itself; a detached tmux session may still be live.
94
+ 4. Definitive process absence plus definitive tmux absence is dead.
95
+ 5. Conflicting, missing, legacy, or unreadable evidence is unknown.
96
+
97
+ Wall-clock age never overrides verified live or dead evidence.
98
+
99
+ ## Provider Peer IDs
100
+
101
+ JavaScript and generated shims derive the same first eight lowercase SHA-1 hex
102
+ characters from the complete provider ID. Hash output is accepted only when it
103
+ is exactly 40 lowercase hexadecimal characters. When no supported hash command
104
+ can produce a valid digest, a shim starts the real provider without hello-cc
105
+ coordination rather than creating an ambiguous ID.
106
+
107
+ The v1 release notes must show examples of old and new IDs and explain that old
108
+ coordination history remains queryable in the backup but is not attached to the
109
+ new peer automatically.
110
+
111
+ ## Acceptance Criteria
112
+
113
+ - A v5 and a development v6 fixture each produce a validated backup and migrate
114
+ once to v7.
115
+ - A forced backup failure leaves the source schema and data unchanged.
116
+ - A pre-v1 binary rejects v7 with the documented error.
117
+ - PID reuse is classified as dead for the stored identity.
118
+ - A live tmux pane remains live across sleep-sized wall-clock gaps.
119
+ - A detached but live tmux session is not made takeover-ready.
120
+ - JavaScript and every generated shim produce identical v1 peer IDs.
@@ -0,0 +1,117 @@
1
+ # hello-cc v1 Release and Verification Design
2
+
3
+ Status: approved in conversation on 2026-08-03.
4
+
5
+ ## Purpose
6
+
7
+ Define code ownership boundaries, fatal error behavior, packaging, documentation,
8
+ and evidence required before the remaining hardening work can be called complete.
9
+
10
+ ## Module Boundaries
11
+
12
+ New focused modules own these policies:
13
+
14
+ - process identity inspection and comparison;
15
+ - clock observation and liveness resolution;
16
+ - project registry locking;
17
+ - buffer GC planning and arbitration;
18
+ - Runtime API version negotiation;
19
+ - secret redaction.
20
+
21
+ `bin/hcc.mjs` remains the command and runtime orchestrator. It calls these
22
+ modules but does not duplicate their decision logic. Existing repository
23
+ patterns are retained; unrelated restructuring is out of scope.
24
+
25
+ Every imported production module must be tracked and included by the package
26
+ `files` contract. Docker test files are tracked but remain outside the npm
27
+ package.
28
+
29
+ ## Fatal Error Behavior
30
+
31
+ Expected poller, watcher, sibling-project, and transient runtime failures are
32
+ caught at their ownership boundary, logged with redaction, and isolated.
33
+
34
+ An uncaught exception or unhandled rejection initiates one idempotent fatal
35
+ shutdown. Shutdown stops timers and watchers, closes sessions and sockets using
36
+ the documented detach/exit semantics, clears only runtime pointers owned by the
37
+ current process identity, closes the server and database resources, then exits
38
+ nonzero. The runtime must not continue after an unknown exception.
39
+
40
+ A second fatal signal during shutdown forces termination without attempting a
41
+ second cleanup pass.
42
+
43
+ ## Release Contract
44
+
45
+ The package version becomes `1.0.0`. Changelog, README files, bilingual command
46
+ documentation, help output, and the defect review describe:
47
+
48
+ - schema v7 and no downgrade support;
49
+ - the pre-migration backup;
50
+ - provider peer ID changes;
51
+ - Runtime API v2 and session token delivery changes;
52
+ - safe GC defaults and `--history`;
53
+ - process-evidence-first liveness and unknown-only grace;
54
+ - optional TLS and trusted proxy usage;
55
+ - accepted plaintext LAN and arbitrary-root risks.
56
+
57
+ The defect report uses evidence-backed status counts and the actual branch. It
58
+ must not label accepted risks or partial controls as completely fixed.
59
+
60
+ The Dockerfile uses `npm ci`, records Node and tmux versions in test output, and
61
+ builds from the complete current source tree. `.dockerignore` excludes host
62
+ runtime state and secrets without excluding production source.
63
+
64
+ ## Test Architecture
65
+
66
+ Pure policies use Node's built-in test runner in focused test files. Real CLI,
67
+ SQLite, tmux, HTTP, HTTPS, and WebSocket boundaries remain integration tests.
68
+ Tests do not add production-only backdoors or test-only public APIs.
69
+
70
+ Each behavior change follows red-green-refactor:
71
+
72
+ 1. add the smallest regression that demonstrates the missing invariant;
73
+ 2. run it and record the expected failure;
74
+ 3. implement the minimum production change;
75
+ 4. rerun the focused test and relevant neighboring tests;
76
+ 5. refactor only while green.
77
+
78
+ Required regressions cover:
79
+
80
+ - v5/v6 backup and migration failure atomicity;
81
+ - PID reuse and platform process inspection;
82
+ - live, dead, and unknown tmux/external peers;
83
+ - CLI-only sleep-sized gaps and concurrent grace writers;
84
+ - manual/automatic GC, negative retention, history opt-in, and runtime failure;
85
+ - concurrent registry writers and same-root DB changes;
86
+ - API v2, cookie lifecycle, action-token scope, CSP, and redaction;
87
+ - realpath and symlink containment;
88
+ - fatal shutdown cleanup;
89
+ - package content and tracked-file completeness.
90
+
91
+ TTL renewal tests use the renewal operation's recorded timestamp rather than
92
+ assuming wall-clock readings in separate processes are monotonic. This retains
93
+ strict TTL inflation checks without the observed one-second container flake.
94
+
95
+ ## Verification Gates
96
+
97
+ Completion requires fresh evidence, in this order:
98
+
99
+ 1. final diff and tracked production import audit;
100
+ 2. syntax/import/package-content checks;
101
+ 3. focused unit and security regression tests;
102
+ 4. original vulnerable-path reproductions and alternate bypass inputs;
103
+ 5. preserved legitimate behavior tests;
104
+ 6. complete local regression;
105
+ 7. a freshly built Node 24/Linux image;
106
+ 8. three consecutive complete container regressions;
107
+ 9. final `origin/master..worktree` review and documentation consistency check.
108
+
109
+ A failed gate blocks a completion claim. Accepted risks are reported separately
110
+ and are not represented as test gaps or fixed findings.
111
+
112
+ ## Definition of Done
113
+
114
+ The work is complete only when every approved non-accepted-risk requirement in
115
+ the four v1 design specifications has a passing test or a documented reason the
116
+ check is inapplicable, all required verification gates pass, and the final
117
+ working tree contains no untracked production dependency.
@@ -0,0 +1,104 @@
1
+ # Web and Runtime API v2 Hardening Design
2
+
3
+ Status: approved in conversation on 2026-08-03.
4
+
5
+ ## Purpose
6
+
7
+ Define the v1 Web authentication, Runtime API v2, browser policy, path safety,
8
+ and log-redaction contract while preserving two explicitly accepted risks.
9
+
10
+ ## Accepted Risks
11
+
12
+ - The default Web listener remains `0.0.0.0` over HTTP for LAN access.
13
+ - An authenticated administrator may select any existing server project root.
14
+
15
+ These choices permit passive LAN observation of HTTP traffic and broad access
16
+ to server project directories by anyone holding the administrator credential.
17
+ Documentation must state these risks and must not mark transport confidentiality
18
+ or project scoping as fully remediated.
19
+
20
+ ## Authentication Roles
21
+
22
+ The stable runtime token is the administrator credential. An HttpOnly browser
23
+ cookie issued after successful token login represents the same administrator
24
+ role. Both may create, stop, attach, and inject managed sessions.
25
+
26
+ A session action token is narrower. It authorizes terminal WebSocket input for
27
+ one managed session and is delivered only in that session's terminal snapshot.
28
+ It is never returned by the session list. Session action token comparisons use
29
+ the shared constant-time token helper.
30
+
31
+ Cookie sessions have a server-side expiry, a bounded count, explicit logout,
32
+ and tracked WebSocket membership. Expiry, eviction, or logout closes associated
33
+ WebSockets immediately. Cookie-authenticated mutations require a same-origin
34
+ request.
35
+
36
+ Non-loopback listeners require a non-empty administrator token. Tokenless mode
37
+ is accepted only from a loopback socket.
38
+
39
+ ## Runtime API v2
40
+
41
+ Runtime metadata advertises API version 2. CLI and browser HTTP requests send
42
+ `X-HCC-API-Version: 2`. Browser WebSocket handshakes send `api_version=2` in the
43
+ query because the WebSocket browser API cannot set an arbitrary request header.
44
+ Protected API requests with a missing or unsupported version receive HTTP 426
45
+ with `API_VERSION_UNSUPPORTED` and the supported version.
46
+
47
+ Public login and static bootstrap routes remain reachable without the API
48
+ version header. The v1 release notes identify removal of `action_token` from
49
+ `GET /api/sessions` as a breaking API change.
50
+
51
+ ## Browser Policy
52
+
53
+ HTML responses use a per-response nonce. The Content Security Policy permits
54
+ scripts only from self and the response nonce, denies objects and framing,
55
+ restricts base URIs, and permits only the same-origin HTTP/WebSocket connections
56
+ needed by the console. Styles allow the current xterm and inline-style contract;
57
+ script policy must not require `unsafe-inline`.
58
+
59
+ Responses retain no-store, no-referrer, and nosniff headers. Secure requests may
60
+ add transport-only headers without applying HSTS to accepted plaintext mode.
61
+
62
+ ## Path Safety
63
+
64
+ Arbitrary existing roots remain supported, but lexical containment is not
65
+ enough. The selected root is canonicalized with `realpath`. The `.hello-cc`
66
+ directory is created with owner-only permissions when absent and canonicalized
67
+ when present. A symlinked `.hello-cc` or DB parent that resolves outside the
68
+ canonical state directory is rejected.
69
+
70
+ The selected database must resolve to `mesh.db` or another path below the real
71
+ `.hello-cc` directory. Pseudo-files, non-regular database targets, and symlink
72
+ escapes are rejected before SQLite opens the target.
73
+
74
+ ## TLS and Proxy Modes
75
+
76
+ Direct `--tls` mode validates certificate dates, SAN coverage, key pairing, file
77
+ permissions, and generation publication before listening. CLI requests trust
78
+ only the runtime's stored self-signed certificate.
79
+
80
+ `--trust-proxy --proxy-origin https://host[:port]` accepts forwarded host/proto
81
+ only from a loopback peer and only when both exactly match the pinned public
82
+ origin. Either option without the other is rejected. Forwarded headers from any
83
+ non-loopback peer are ignored. Cookie `Secure` state and origin checks consume
84
+ the same trusted-proxy decision.
85
+
86
+ ## Secret Redaction
87
+
88
+ All startup and error logging passes through one redactor. It removes or replaces
89
+ values for `--token`, Authorization, cookies, session action tokens, runtime
90
+ tokens, and URL `token` query parameters. The redactor handles both structured
91
+ objects and command-line strings. Runtime pointer files remain owner-readable
92
+ only because local CLI operation requires the administrator token.
93
+
94
+ ## Acceptance Criteria
95
+
96
+ - Old or missing API versions receive 426 on protected API routes.
97
+ - Admin token and admin cookie retain documented management behavior.
98
+ - Session action tokens are absent from lists and required for WS input.
99
+ - Logout and expiry close existing cookie-authenticated WebSockets.
100
+ - CSP blocks an injected inline script without the nonce.
101
+ - Logs contain no supplied administrator, cookie, or session token value.
102
+ - Symlink DB escape is rejected while a normal arbitrary project root works.
103
+ - Direct TLS, loopback trusted proxy, and accepted plaintext LAN modes pass
104
+ independent integration tests.