instar 1.3.199 → 1.3.201

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 (35) hide show
  1. package/.claude/skills/autonomous/hooks/autonomous-stop-hook.sh +21 -2
  2. package/dist/commands/init.d.ts.map +1 -1
  3. package/dist/commands/init.js +30 -0
  4. package/dist/commands/init.js.map +1 -1
  5. package/dist/core/AutonomousSessions.d.ts +2 -0
  6. package/dist/core/AutonomousSessions.d.ts.map +1 -1
  7. package/dist/core/AutonomousSessions.js +2 -0
  8. package/dist/core/AutonomousSessions.js.map +1 -1
  9. package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
  10. package/dist/core/PostUpdateMigrator.js +51 -10
  11. package/dist/core/PostUpdateMigrator.js.map +1 -1
  12. package/dist/core/SessionClock.d.ts +57 -0
  13. package/dist/core/SessionClock.d.ts.map +1 -0
  14. package/dist/core/SessionClock.js +128 -0
  15. package/dist/core/SessionClock.js.map +1 -0
  16. package/dist/core/SessionClockReader.d.ts +18 -0
  17. package/dist/core/SessionClockReader.d.ts.map +1 -0
  18. package/dist/core/SessionClockReader.js +35 -0
  19. package/dist/core/SessionClockReader.js.map +1 -0
  20. package/dist/scaffold/templates.d.ts.map +1 -1
  21. package/dist/scaffold/templates.js +5 -0
  22. package/dist/scaffold/templates.js.map +1 -1
  23. package/dist/server/routes.d.ts.map +1 -1
  24. package/dist/server/routes.js +19 -0
  25. package/dist/server/routes.js.map +1 -1
  26. package/package.json +1 -1
  27. package/src/data/builtin-manifest.json +71 -63
  28. package/src/scaffold/templates.ts +5 -0
  29. package/src/templates/scripts/emit-session-clock.sh +78 -0
  30. package/upgrades/1.3.200.md +25 -0
  31. package/upgrades/1.3.201.md +46 -0
  32. package/upgrades/side-effects/session-clock-step1.md +52 -0
  33. package/upgrades/side-effects/session-clock-step2a.md +52 -0
  34. package/upgrades/side-effects/session-clock-step2b.md +49 -0
  35. package/upgrades/side-effects/session-clock-step2c.md +32 -0
@@ -0,0 +1,25 @@
1
+ # Upgrade Guide — vNEXT
2
+
3
+ <!-- assembled-by: assemble-next-md -->
4
+ <!-- bump: patch -->
5
+
6
+ ## What Changed
7
+
8
+ Your agent can now answer "how long have I been running, and how much time is left?" instead of guessing.
9
+
10
+ For any active time-boxed (autonomous) session, a new read-only endpoint computes elapsed + remaining from the session's durable record. This is Step 1 of a fix for a real problem where an agent in a long autonomous run lost track of time and wound down far too early. (Step 2 — injecting that clock into every turn automatically — follows.)
11
+
12
+ ## What to Tell Your User
13
+
14
+ Nothing to configure. If you run timed autonomous sessions, your agent can now check its own elapsed/remaining time accurately (and you can see it too). A normal short chat is unaffected — the clock only appears when there's actually a timed session to report on.
15
+
16
+ ## Summary of New Capabilities
17
+
18
+ - New read-only `GET /session/clock` (optional `?topic=N`) returns, for each active time-boxed session, `{ label, kind, startedAt, endsAt, elapsedSeconds, remainingSeconds, elapsedHuman, remainingHuman, percentElapsed, status }`. Bearer-gated; `{ sessions: [] }` when nothing is time-boxed; per-machine.
19
+ - The clock is computed by a pure `SessionClock` module (clock-skew-clamped, never negative). The session's task text is sanitized + length-capped into a `label` before it's ever surfaced — the raw goal is never exposed (prompt-injection + leak safety).
20
+ - CLAUDE.md gains a "Session Clock" awareness entry (proactive trigger: quote the real numbers before reporting progress or deciding a session is done) — delivered to existing agents via migration.
21
+
22
+ ## Evidence
23
+
24
+ - All three test tiers green: 20 unit (`SessionClock` 14 + `SessionClockReader` 6), 4 integration (`session-clock-route`), 4 E2E (`session-clock-lifecycle`, real AgentServer boot — alive 200 not 503, Bearer-required, read-only, leak-bound). No regressions (AutonomousSessions 13, migrateClaudeMd 3). `tsc --noEmit` clean.
25
+ - Spec: `docs/specs/ROBUST-SESSION-TIME-AWARENESS-SPEC.md` (converged 3 rounds, approved). Side-effects: `upgrades/side-effects/session-clock-step1.md`.
@@ -0,0 +1,46 @@
1
+ # Upgrade Guide — vNEXT
2
+
3
+ <!-- assembled-by: assemble-next-md -->
4
+ <!-- bump: patch -->
5
+
6
+ ## What Changed
7
+
8
+ Ships the shared routine that renders your session clock, and installs it on every agent.
9
+
10
+ Step 1 added the `/session/clock` endpoint (how long have I been running / how much is left). This adds `emit-session-clock.sh` — the small routine that turns that into a one-line "⏱ SESSION CLOCK: Nh elapsed · Mh remaining (NN%)" string. It has a render mode (format already-computed values) and a query mode (ask the endpoint). The hooks that call it on every turn land next (tracked in issue #682).
11
+
12
+ Your autonomous agent now sees how much of its time window is left — on every turn.
13
+
14
+ This is the fix for the failure where an agent in a long autonomous run wound down far too early because it had lost track of time. The autonomous stop-hook now feeds back a rich `⏱ SESSION CLOCK: Nh elapsed · Mh remaining (NN%)` line on every continuation, rendered from the hook's own elapsed/remaining numbers, so the agent always knows where it is in the window before deciding anything.
15
+
16
+ The session clock now shows on your own messages too, not just autonomous turns.
17
+
18
+ Step 2b wired the clock into autonomous continuations; this wires the second site: when you message the agent, the UserPromptSubmit hook now also surfaces "⏱ SESSION CLOCK: Nh elapsed · Mh remaining (NN%)" if a time-boxed session is active. Both call sites of the shared routine (render + query) are now live — completing the per-turn, every-turn time awareness.
19
+
20
+ ## What to Tell Your User
21
+
22
+ Nothing to do. This is plumbing for the time-awareness feature — a small script that gets installed automatically. You'll see its effect once the per-turn hooks are wired (next step): your agent will quote real elapsed/remaining time instead of guessing.
23
+
24
+ Nothing to do. If you run timed autonomous sessions, the agent will now quote accurate elapsed/remaining time as it works instead of guessing — and won't conclude a session is "done" with hours left. Existing agents get the updated hook automatically on update.
25
+
26
+ Nothing to do. If a timed session is running, your agent now sees its elapsed/remaining time on your turns too, so "how far along are we?" always has a real answer.
27
+
28
+ ## Summary of New Capabilities
29
+
30
+ - New `.instar/scripts/emit-session-clock.sh` — renders the SESSION CLOCK line. `render` mode formats values the caller already computed (no re-resolution); `query` mode curls `GET /session/clock`. Signal-only (pure stdout, never blocks), and only ever echoes the already-sanitized label, never a raw goal.
31
+ - Installed on new agents (init) and existing agents (always-overwrite migration), so the whole fleet has the routine ready for the per-turn wiring.
32
+
33
+ - The autonomous stop-hook injects a SESSION CLOCK line into every blocked continuation, rendered by `emit-session-clock.sh` from the hook's own computed numbers (no re-resolution → it can never disagree with the hook's own duration-expiry check). Additive and fail-safe: unbounded runs or a missing script simply omit the segment.
34
+ - Delivered to existing agents via the autonomous-skill re-deploy migration (marker bumped to `CLOCK_SEG`); customized hooks are left untouched.
35
+
36
+ - `telegram-topic-context.sh` (built-in UserPromptSubmit hook) now calls `emit-session-clock.sh query` after resolving port/auth/topic, surfacing the SESSION CLOCK line on user turns. Signal-only; emits nothing when no time-boxed session is active or the server is unreachable. Delivered to existing agents via the always-overwrite built-in-hook migration.
37
+
38
+ ## Evidence
39
+
40
+ - 7 golden tests (render/percent/clamp/formatting/unbounded/query-unreachable/no-op) + 3 migration tests (installs, always-overwrite, executable) green; secret-drop migration regression (13) green; `tsc --noEmit` clean.
41
+ - Spec: `docs/specs/ROBUST-SESSION-TIME-AWARENESS-SPEC.md` (Component 2). Side-effects: `upgrades/side-effects/session-clock-step2a.md`. Call-site wiring: #682.
42
+
43
+ - Functional wiring test (`autonomous-stop-hook-session-clock.test.ts`): a blocked continuation of a timed run feeds back the SESSION CLOCK line (runs the real hook); fail-safe path with the script absent verified. `bash -n` clean; autonomous-stop-hook regression suites (P13/completion/topic-keyed, 23) green; `tsc --noEmit` clean.
44
+ - Spec: `docs/specs/ROBUST-SESSION-TIME-AWARENESS-SPEC.md` (Component 2). Side-effects: `upgrades/side-effects/session-clock-step2b.md`. The user-turn injection site: #682.
45
+
46
+ - `telegram-topic-context-session-clock.test.ts` (2): generated hook carries the query call + passes `bash -n` (escaping guard). Regression (12) green; lint clean. Spec: Component 2.
@@ -0,0 +1,52 @@
1
+ # Side-Effects Review — Session Clock Step 1 (SessionClock + GET /session/clock)
2
+
3
+ **Slug:** `session-clock-step1`
4
+ **Date:** `2026-06-02`
5
+ **Author:** `echo`
6
+ **Tier:** 2 (driven by the converged + approved spec `ROBUST-SESSION-TIME-AWARENESS-SPEC.md`)
7
+ **Spec:** `docs/specs/ROBUST-SESSION-TIME-AWARENESS-SPEC.md` (review-convergence iteration 3, approved)
8
+
9
+ ## Summary of the change
10
+
11
+ Step 1 of the time-awareness fix: the compute + query surface.
12
+ - `src/core/SessionClock.ts` — pure tier0 module: `computeSessionClock(input, nowMs)` (elapsed/remaining with clock-skew clamping + the status matrix), `deriveLabel(goal)` (the sanitized, cap-80, control-char/angle-bracket-stripped label that is the ONLY task text ever injected/served), `humanizeDuration`.
13
+ - `src/core/SessionClockReader.ts` — read-only I/O layer: maps ACTIVE autonomous-state records → computed clocks, with optional topic binding. Reuses `AutonomousSessions.activeAutonomousJobs()`.
14
+ - `src/core/AutonomousSessions.ts` — `AutonomousJobSummary` gains `durationSeconds` (parsed from the existing `duration_seconds` front-matter field). Additive.
15
+ - `src/server/routes.ts` — new read-only `GET /session/clock` (optional `?topic=N`). Bearer-gated (inherits app-wide auth). Leak-bounded: returns the computed clock + sanitized `label` only, never the raw `goal`.
16
+ - `src/scaffold/templates.ts` + `src/core/PostUpdateMigrator.ts` — CLAUDE.md "Session Clock" awareness (template for new agents; content-sniffed `migrateClaudeMd` block for existing agents).
17
+
18
+ ## Decision-point inventory
19
+ - route exposure: read vs write → read-only (GET only; POST → 404). No gate, no mutation.
20
+ - label: inject raw goal vs derived → derived + sanitized + capped. The raw goal never leaves the record.
21
+ - record field: `end_at` vs `started_at`+`duration_seconds` → the latter (canonical, matches the stop-hook + setup-autonomous.sh schema); `endsAt` is derived.
22
+
23
+ ## 1. Over-correction risk
24
+ None — purely additive observability. No existing behavior changes. A healthy agent with no time-boxed record gets `{ sessions: [] }`.
25
+
26
+ ## 2. Under-correction risk
27
+ Step 1 is the QUERY surface only; the per-turn INJECTION (the higher-impact fix for the incident) is Step 2 (emit-session-clock.sh + hooks), a separate PR. Documented in the spec sequencing.
28
+
29
+ ## 3. Level-of-abstraction fit
30
+ Compute is pure (SessionClock.ts, no I/O, fully unit-tested both sides of every boundary); I/O is isolated (SessionClockReader.ts); the route is a thin reader. The record-enumeration reuses the existing AutonomousSessions module rather than duplicating frontmatter parsing.
31
+
32
+ ## 4. Signal vs Authority
33
+ Tier0, deterministic, no LLM, no gate. Pure computation + a read route. Appropriate.
34
+
35
+ ## 5. External surfaces
36
+ One new read-only HTTP route (`GET /session/clock`), Bearer-gated like `/tokens/summary`. **Leak-bound:** the response carries the sanitized `label` only — never the raw `goal`/task text (verified by integration + E2E assertions). No config/schema change.
37
+
38
+ ## 6. Interactions with existing primitives
39
+ `AutonomousJobSummary.durationSeconds` is additive (existing consumers unaffected — AutonomousSessions unit tests still green). The route composes with the existing auth middleware. No change to the autonomous-state writer or the stop-hook.
40
+
41
+ ## 7. Rollback cost
42
+ Trivial: remove the route + the two new modules + the additive `durationSeconds` field + the CLAUDE.md block. No persistent state, no migration of data.
43
+
44
+ ## Migration parity
45
+ - New agents: the route ships in code; the CLAUDE.md template carries the awareness.
46
+ - Existing agents: the route reaches them on the normal dist update (code); `migrateClaudeMd` content-sniffs `/session/clock` and appends the awareness block (idempotent).
47
+
48
+ ## Tests (all three tiers)
49
+ - Unit: `SessionClock` (14 — full status matrix, clock-skew clamp, label derivation/sanitization incl. `<promise>`-token stripping + cap-80) + `SessionClockReader` (6 — record parsing, topic binding, goal→label end-to-end, missing dir).
50
+ - Integration: `session-clock-route` (4 — 200 with computed fields, `{sessions:[]}` when none, topic filter, leak-bound: raw goal never in the response).
51
+ - E2E: `session-clock-lifecycle` (4 — real AgentServer boot, route alive 200 not 503, leak-bound, Bearer required, read-only POST→404).
52
+ - No regressions: AutonomousSessions (13) + migrateClaudeMd (3) still green; `tsc --noEmit` clean.
@@ -0,0 +1,52 @@
1
+ # Side-Effects Review — Session Clock Step 2a (emit-session-clock.sh shared routine + delivery)
2
+
3
+ **Slug:** `session-clock-step2a`
4
+ **Date:** `2026-06-02`
5
+ **Author:** `echo`
6
+ **Tier:** 2 (driven by the converged + approved `ROBUST-SESSION-TIME-AWARENESS-SPEC.md`)
7
+ **Spec:** `docs/specs/ROBUST-SESSION-TIME-AWARENESS-SPEC.md` (Component 2 — the shared routine)
8
+
9
+ ## Summary of the change
10
+
11
+ Ships the **shared time-awareness routine** and its delivery to every agent. Step 1 (merged #683) added the compute + `/session/clock` query surface; this adds the bash routine that formats the SESSION CLOCK line, plus install-everywhere. Its call sites (the two hooks) are the next sequenced step, tracked in #682.
12
+
13
+ - `src/templates/scripts/emit-session-clock.sh` — the routine (a real template file, like `telegram-reply.sh`/`secret-drop-retrieve.mjs`; NOT an inline TS string, so no escaping risk). Two modes:
14
+ - **render** `<startedISO> <durationSec> <elapsedSec> <remainingSec> <label>` — formats ONE SESSION CLOCK line from values the caller already computed (no re-resolution → can never disagree with the caller's own clock).
15
+ - **query** `<topic> <port> <auth>` — curls `GET /session/clock` and formats the first active session; prints nothing if none / server unreachable.
16
+ - `src/core/PostUpdateMigrator.ts` — `migrateScripts` installs it to `.instar/scripts/` always-overwrite (existing agents, mirrors the secret-drop-retrieve.mjs block).
17
+ - `src/commands/init.ts` — `installEmitSessionClock` installs it at scaffold time (new agents).
18
+
19
+ ## Decision-point inventory
20
+ - install policy: install-if-missing vs always-overwrite → always-overwrite (new, non-user-customizable shared routine; must stay current). Custom forks live elsewhere and are untouched.
21
+ - routine value source: render (caller's numbers) vs re-resolve → render uses the caller's already-computed values (no double-resolution; adversarial round-2 fix in the spec).
22
+
23
+ ## 1. Over-correction risk
24
+ None — purely additive. The routine is a standalone script; until a hook calls it (the next step, #682), it has zero runtime effect. Installing it changes no behavior.
25
+
26
+ ## 2. Under-correction risk
27
+ The routine is shipped + delivered + tested but its call sites (the two hooks) land with #682; that is the sequenced wiring step. The routine is complete and independently testable.
28
+
29
+ ## 3. Level-of-abstraction fit
30
+ A single shared routine both call sites will use; render math lives in it, the compute-of-record stays in `SessionClock.compute()` (TS). The bash routine only formats.
31
+
32
+ ## 4. Signal vs Authority
33
+ Tier0, signal-only: pure stdout, never blocks, never mutates. Appropriate.
34
+
35
+ ## 5. External surfaces
36
+ None new. query mode calls the existing Bearer-gated `/session/clock`. The routine echoes only the already-sanitized `label` the route/caller supplies (never a raw goal).
37
+
38
+ ## 6. Interactions with existing primitives
39
+ The `migrateScripts` addition mirrors the secret-drop-retrieve.mjs install exactly (verified: that test suite stays green). No change to existing scripts/hooks.
40
+
41
+ ## 7. Rollback cost
42
+ Trivial: remove the script + the two install calls. No state, no data migration.
43
+
44
+ ## Migration parity
45
+ - New agents: `installEmitSessionClock` (init.ts).
46
+ - Existing agents: `migrateScripts` always-overwrite install on the normal dist update.
47
+ - Both verified by tests.
48
+
49
+ ## Tests
50
+ - Unit/golden (`emit-session-clock.test.ts`, 7): render formats elapsed/remaining/percent; omits the remaining clause when unbounded; clamps negative elapsed to 0s; minutes/seconds formatting; no-label; query-unreachable → empty exit 0; unknown mode → no-op.
51
+ - Migration (`PostUpdateMigrator-emitSessionClock.test.ts`, 3): migrateScripts installs the script, always-overwrite (restores a stale copy, idempotent), mode 0o755.
52
+ - Regression: secret-drop migration (13) stays green; `tsc --noEmit` clean.
@@ -0,0 +1,49 @@
1
+ # Side-Effects Review — Session Clock Step 2b (autonomous-continuation injection)
2
+
3
+ **Slug:** `session-clock-step2b`
4
+ **Date:** `2026-06-02`
5
+ **Author:** `echo`
6
+ **Tier:** 2 (converged+approved `ROBUST-SESSION-TIME-AWARENESS-SPEC.md`)
7
+ **Spec:** `docs/specs/ROBUST-SESSION-TIME-AWARENESS-SPEC.md` (Component 2 — the stop-hook render call site)
8
+
9
+ ## Summary of the change
10
+
11
+ Wires the time-awareness injection into the **autonomous stop-hook** — the actual fix for the wind-down-early incident. On every blocked continuation of a time-boxed run, the hook now feeds back a rich `⏱ SESSION CLOCK: Nh elapsed · Mh remaining (NN%)` line so the autonomous agent always SEES how much of its window remains.
12
+
13
+ - `.claude/skills/autonomous/hooks/autonomous-stop-hook.sh`: after the existing `(${REMAINING_MIN}m remaining)` slot (kept untouched), an additive `${CLOCK_SEG}` segment is rendered by `emit-session-clock.sh render` **from the hook's OWN already-computed `STARTED_AT`/`DURATION_SECONDS`/`ELAPSED`/`REMAINING`** — no re-resolution, so the injected clock can never disagree with the hook's own duration-expiry verdict (adversarial round-2 concern). Fail-safe: if the script is absent or the run is unbounded (no `ELAPSED`), the segment is simply omitted.
14
+ - `src/core/PostUpdateMigrator.ts`: the existing `migrateAutonomousStopHookTopicKeyed` marker is bumped `p13_stop_allowed → CLOCK_SEG`, re-deploying the wired hook to existing agents (Migration Parity; customized hooks with no stock fingerprint untouched).
15
+
16
+ The query-mode call site (user-turn injection via `telegram-topic-context.sh`) is the second, separate injection site, tracked in #682; the routine's query mode is shipped + tested and ready for it.
17
+
18
+ ## Decision-point inventory
19
+ - placement: enrich the `(...)` slot vs add a segment → add a separate `${CLOCK_SEG}` segment (the existing slot is untouched = lowest risk).
20
+ - value source: render from the hook's own numbers vs re-resolve → render (no double-resolution).
21
+
22
+ ## 1. Over-correction risk
23
+ None — additive. The existing `(${REMAINING_MIN}m remaining)` slot and the expiry logic are unchanged; only an extra informational segment is appended.
24
+
25
+ ## 2. Under-correction risk
26
+ The user-turn (query-mode) site is the separate injection point tracked in #682; this change covers the autonomous-continuation site, which is the incident's actual failure mode.
27
+
28
+ ## 3. Level-of-abstraction fit
29
+ The hook calls the single shared `emit-session-clock.sh render`; the format lives there, the numbers come from the hook. No duplication.
30
+
31
+ ## 4. Signal vs Authority
32
+ Signal-only: the injected line is informational; it never changes the block/exit decision (which is the unchanged expiry logic).
33
+
34
+ ## 5. External surfaces
35
+ None. The hook reads the locally-installed script; nothing new is exposed.
36
+
37
+ ## 6. Interactions with existing primitives
38
+ Reuses the established `migrateAutonomousStopHookTopicKeyed` re-deploy mechanism (marker bump) and the hook's own computed values. `bash -n` clean; the existing autonomous-stop-hook tests (P13, completion-condition, topic-keyed) stay green.
39
+
40
+ ## 7. Rollback cost
41
+ Trivial: remove the `CLOCK_SEG` block + the two `${CLOCK_SEG}` insertions + revert the marker. No state.
42
+
43
+ ## Migration parity
44
+ - New agents: `installBuiltinSkills`/`init` ship the wired hook.
45
+ - Existing agents: `migrateAutonomousStopHookTopicKeyed` (marker `CLOCK_SEG`) re-deploys the wired hook on update; customized hooks untouched.
46
+
47
+ ## Tests
48
+ - `autonomous-stop-hook-session-clock.test.ts` (2): a blocked continuation of a timed run feeds back the SESSION CLOCK line (functional, runs the real hook with the installed script); fail-safe with the script absent (continuation still fires, segment omitted).
49
+ - Regression: `bash -n` clean; PostUpdateMigrator-autonomousStopHook (8), autonomous-completion-condition + evaluate-stop (15) green; `tsc --noEmit` clean.
@@ -0,0 +1,32 @@
1
+ # Side-Effects Review — Session Clock Step 2c (user-turn query injection)
2
+
3
+ **Slug:** `session-clock-step2c` · **Date:** `2026-06-02` · **Author:** `echo` · **Tier:** 2
4
+ **Spec:** `docs/specs/ROBUST-SESSION-TIME-AWARENESS-SPEC.md` (Component 2 — the query call site)
5
+
6
+ ## Summary
7
+ Completes the time-awareness injection's SECOND call site: the `telegram-topic-context.sh`
8
+ UserPromptSubmit hook now, after resolving PORT + AUTH_TOKEN + TOPIC_ID, calls
9
+ `emit-session-clock.sh query` so the SESSION CLOCK line surfaces on the user's OWN turns too
10
+ (not just autonomous continuations). With Step 2b (the stop-hook render site), both call sites
11
+ of Component 2 are now wired — the routine's render AND query modes are both consumed.
12
+
13
+ - `src/core/PostUpdateMigrator.ts` `getTelegramTopicContextHook()`: an additive query call after
14
+ the existing CURRENT TIME block + AUTH resolution. Signal-only: emits nothing when no time-boxed
15
+ session is active or the server is unreachable. Guarded on the script existing.
16
+
17
+ ## 1-7 (brief)
18
+ Over/under-correction: additive; the CURRENT TIME block + history fetch are unchanged; emits only
19
+ when a clock exists. Abstraction: reuses the shared routine. Signal vs Authority: pure stdout, no
20
+ gate. External surfaces: calls the existing Bearer-gated `/session/clock`; only the already-sanitized
21
+ label is surfaced. Interactions: composes with the hook's existing AUTH/PORT/TOPIC resolution.
22
+ Rollback: remove the ~3-line block.
23
+
24
+ ## Migration parity
25
+ `telegram-topic-context.sh` is a BUILT-IN `instar/` hook → always-overwritten on every migration
26
+ (migrateHooks), so existing agents receive the query injection automatically. No new migration needed.
27
+
28
+ ## Tests
29
+ `telegram-topic-context-session-clock.test.ts` (2): the generated hook contains the
30
+ `query "$TOPIC_ID" "$PORT" "$AUTH_TOKEN"` call AND is syntactically valid bash (`bash -n` — guards
31
+ the TS-template escaping). Regression: migration-parity-hooks + neutralRelayPath + emit-session-clock
32
+ migration (12) green; `npm run lint` (tsc + custom linters) clean.