instar 0.28.73 → 0.28.74

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 (43) hide show
  1. package/dist/commands/server.d.ts.map +1 -1
  2. package/dist/commands/server.js +51 -23
  3. package/dist/commands/server.js.map +1 -1
  4. package/dist/core/SessionManager.d.ts +4 -0
  5. package/dist/core/SessionManager.d.ts.map +1 -1
  6. package/dist/core/SessionManager.js +15 -4
  7. package/dist/core/SessionManager.js.map +1 -1
  8. package/dist/core/types.d.ts +15 -0
  9. package/dist/core/types.d.ts.map +1 -1
  10. package/dist/core/types.js.map +1 -1
  11. package/dist/lifeline/TelegramLifeline.d.ts +8 -0
  12. package/dist/lifeline/TelegramLifeline.d.ts.map +1 -1
  13. package/dist/lifeline/TelegramLifeline.js +31 -1
  14. package/dist/lifeline/TelegramLifeline.js.map +1 -1
  15. package/dist/messaging/TelegramAdapter.d.ts +28 -0
  16. package/dist/messaging/TelegramAdapter.d.ts.map +1 -1
  17. package/dist/messaging/TelegramAdapter.js +79 -1
  18. package/dist/messaging/TelegramAdapter.js.map +1 -1
  19. package/dist/messaging/TelegramMarkdownFormatter.d.ts +76 -0
  20. package/dist/messaging/TelegramMarkdownFormatter.d.ts.map +1 -0
  21. package/dist/messaging/TelegramMarkdownFormatter.js +493 -0
  22. package/dist/messaging/TelegramMarkdownFormatter.js.map +1 -0
  23. package/dist/messaging/imessage/IMessageAdapter.d.ts +3 -6
  24. package/dist/messaging/imessage/IMessageAdapter.d.ts.map +1 -1
  25. package/dist/messaging/imessage/IMessageAdapter.js +20 -21
  26. package/dist/messaging/imessage/IMessageAdapter.js.map +1 -1
  27. package/dist/messaging/imessage/NativeBackend.d.ts +26 -0
  28. package/dist/messaging/imessage/NativeBackend.d.ts.map +1 -1
  29. package/dist/messaging/imessage/NativeBackend.js +133 -0
  30. package/dist/messaging/imessage/NativeBackend.js.map +1 -1
  31. package/dist/messaging/telegramFormatMetrics.d.ts +22 -0
  32. package/dist/messaging/telegramFormatMetrics.d.ts.map +1 -0
  33. package/dist/messaging/telegramFormatMetrics.js +38 -0
  34. package/dist/messaging/telegramFormatMetrics.js.map +1 -0
  35. package/dist/messaging/types.d.ts +7 -0
  36. package/dist/messaging/types.d.ts.map +1 -1
  37. package/dist/messaging/types.js.map +1 -1
  38. package/package.json +1 -1
  39. package/src/data/builtin-manifest.json +5 -5
  40. package/src/templates/scripts/telegram-reply.sh +52 -8
  41. package/upgrades/0.28.74.md +48 -0
  42. package/upgrades/side-effects/telegram-markdown-renderer-pr1.md +124 -0
  43. /package/upgrades/side-effects/{capability-map-user-provenance-fallback.md → 0.28.73.md} +0 -0
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "$schema": "./builtin-manifest.schema.json",
3
3
  "schemaVersion": 1,
4
- "generatedAt": "2026-04-23T00:33:11.313Z",
5
- "instarVersion": "0.28.73",
4
+ "generatedAt": "2026-04-25T00:12:18.203Z",
5
+ "instarVersion": "0.28.74",
6
6
  "entryCount": 186,
7
7
  "entries": {
8
8
  "hook:session-start": {
@@ -1112,7 +1112,7 @@
1112
1112
  "type": "template",
1113
1113
  "domain": "operations",
1114
1114
  "sourcePath": "src/templates/scripts/telegram-reply.sh",
1115
- "contentHash": "4f8787df1bf6384545dd7f19093fd77daa1bf993ed48a8ab02b6598d41a2007c",
1115
+ "contentHash": "3d08c63c6280d0a7ba94a345c259673a461ee5c1d116cb47c95c7626c67cee23",
1116
1116
  "since": "2025-01-01"
1117
1117
  },
1118
1118
  "template:whatsapp-reply.sh": {
@@ -1408,7 +1408,7 @@
1408
1408
  "type": "subsystem",
1409
1409
  "domain": "sessions",
1410
1410
  "sourcePath": "src/core/SessionManager.ts",
1411
- "contentHash": "07b0ed1f402436fe88c81c05aecca43d375788fdac63a832f59cdaa7c9c32e86",
1411
+ "contentHash": "b47fdc0040c512bada61574b4fd1505da3c9bbe2adc793915d6f5bd479faad06",
1412
1412
  "since": "2025-01-01"
1413
1413
  },
1414
1414
  "subsystem:auto-updater": {
@@ -1464,7 +1464,7 @@
1464
1464
  "type": "subsystem",
1465
1465
  "domain": "communication",
1466
1466
  "sourcePath": "src/lifeline/TelegramLifeline.ts",
1467
- "contentHash": "c9c7fd786bbab2bfefff986a3882a6267b6d5c1f2efb6a386626e65eeefc0fb8",
1467
+ "contentHash": "22d7d3827ba85d345862e55457fd2cca83e4f38201da61e20a7f0e539052322b",
1468
1468
  "since": "2025-01-01"
1469
1469
  },
1470
1470
  "subsystem:orphan-process-reaper": {
@@ -3,18 +3,52 @@
3
3
  #
4
4
  # Usage:
5
5
  # ./telegram-reply.sh TOPIC_ID "message text"
6
+ # ./telegram-reply.sh --format markdown TOPIC_ID "**bold**"
6
7
  # echo "message text" | ./telegram-reply.sh TOPIC_ID
7
8
  # cat <<'EOF' | ./telegram-reply.sh TOPIC_ID
8
9
  # Multi-line message here
9
10
  # EOF
10
11
  #
12
+ # Flags:
13
+ # --format <mode> Override server-side format mode for this send.
14
+ # Valid: plain, code, markdown, legacy-passthrough
15
+ # ('html' is reserved for trusted internal callers.)
16
+ # When absent, the server's configured default applies.
17
+ #
11
18
  # Reads INSTAR_PORT from environment (default: 4040).
12
19
 
20
+ FORMAT=""
21
+
22
+ # Parse leading flags before positional args.
23
+ while [ $# -gt 0 ]; do
24
+ case "$1" in
25
+ --format)
26
+ FORMAT="$2"
27
+ shift 2
28
+ ;;
29
+ --format=*)
30
+ FORMAT="${1#--format=}"
31
+ shift
32
+ ;;
33
+ --)
34
+ shift
35
+ break
36
+ ;;
37
+ -*)
38
+ echo "Unknown flag: $1" >&2
39
+ exit 1
40
+ ;;
41
+ *)
42
+ break
43
+ ;;
44
+ esac
45
+ done
46
+
13
47
  TOPIC_ID="$1"
14
48
  shift
15
49
 
16
50
  if [ -z "$TOPIC_ID" ]; then
17
- echo "Usage: telegram-reply.sh TOPIC_ID [message]" >&2
51
+ echo "Usage: telegram-reply.sh [--format MODE] TOPIC_ID [message]" >&2
18
52
  exit 1
19
53
  fi
20
54
 
@@ -38,22 +72,32 @@ if [ -f ".instar/config.json" ]; then
38
72
  AUTH_TOKEN=$(python3 -c "import json; print(json.load(open('.instar/config.json')).get('authToken',''))" 2>/dev/null)
39
73
  fi
40
74
 
41
- # Escape for JSON
42
- JSON_MSG=$(printf '%s' "$MSG" | python3 -c 'import sys,json; print(json.dumps(sys.stdin.read()))' 2>/dev/null)
43
- if [ -z "$JSON_MSG" ]; then
44
- # Fallback if python3 not available: basic escape
45
- JSON_MSG="\"$(printf '%s' "$MSG" | sed 's/\\/\\\\/g; s/"/\\"/g; s/\n/\\n/g')\""
75
+ # Build JSON body (text + optional format).
76
+ JSON_BODY=$(python3 -c '
77
+ import sys, json
78
+ msg = sys.argv[1]
79
+ fmt = sys.argv[2]
80
+ body = {"text": msg}
81
+ if fmt:
82
+ body["format"] = fmt
83
+ print(json.dumps(body))
84
+ ' "$MSG" "$FORMAT" 2>/dev/null)
85
+
86
+ if [ -z "$JSON_BODY" ]; then
87
+ # Fallback if python3 not available: basic escape, no format override.
88
+ ESCAPED=$(printf '%s' "$MSG" | sed 's/\\/\\\\/g; s/"/\\"/g; s/\n/\\n/g')
89
+ JSON_BODY="{\"text\":\"${ESCAPED}\"}"
46
90
  fi
47
91
 
48
92
  if [ -n "$AUTH_TOKEN" ]; then
49
93
  RESPONSE=$(curl -s -w "\n%{http_code}" -X POST "http://localhost:${PORT}/telegram/reply/${TOPIC_ID}" \
50
94
  -H 'Content-Type: application/json' \
51
95
  -H "Authorization: Bearer ${AUTH_TOKEN}" \
52
- -d "{\"text\":${JSON_MSG}}")
96
+ -d "$JSON_BODY")
53
97
  else
54
98
  RESPONSE=$(curl -s -w "\n%{http_code}" -X POST "http://localhost:${PORT}/telegram/reply/${TOPIC_ID}" \
55
99
  -H 'Content-Type: application/json' \
56
- -d "{\"text\":${JSON_MSG}}")
100
+ -d "$JSON_BODY")
57
101
  fi
58
102
 
59
103
  HTTP_CODE=$(echo "$RESPONSE" | tail -1)
@@ -0,0 +1,48 @@
1
+ # Upgrade Guide — v0.28.74
2
+
3
+ <!-- bump: patch -->
4
+
5
+ ## What Changed
6
+
7
+ The scope-coherence stop hook (`scope-coherence-checkpoint.js`) previously
8
+ suggested running `/grounding` as the only recovery path when the
9
+ implementation-depth threshold was crossed. `/grounding` is a Claude-Code-side
10
+ skill convention; Instar does not ship it, so agents whose harness lacks that
11
+ skill saw a dead-end suggestion with no working manual reset path.
12
+
13
+ The checkpoint message now lists three real options: read the relevant
14
+ spec/proposal, invoke `/grounding` if the harness has it, or reset directly via
15
+ the local Instar server's reset endpoint. The endpoint already exists and is
16
+ what `session-start.sh` invokes automatically — this release just surfaces it
17
+ as a manual fallback in the message agents see when they hit the checkpoint.
18
+
19
+ No code paths changed beyond the human-readable message string. The reset
20
+ endpoint and the depth-accumulation logic are unchanged.
21
+
22
+ ## What to Tell Your User
23
+
24
+ - The scope-coherence checkpoint now points to a manual reset path that always works, so if the suggested skill is not installed in your setup you still have a one-line recovery I can run for you.
25
+
26
+ ## Summary of New Capabilities
27
+
28
+ | Capability | How to Use |
29
+ |-----------|-----------|
30
+ | Manual scope-coherence reset surfaced in checkpoint message | `curl -X POST http://localhost:4040/scope-coherence/reset` |
31
+
32
+ ## Evidence
33
+
34
+ Cluster `cluster-scope-coherence-hook-counter-never-resets-across-sessions`
35
+ flagged that `/grounding` is not a registered skill or command in Instar and
36
+ that there is no user-facing reset path shown in the checkpoint message.
37
+
38
+ Verification: `ls skills/` confirms no `grounding` skill ships with Instar.
39
+ The reset endpoint is implemented at `src/server/routes.ts:2925` and is
40
+ invoked by `.instar/hooks/instar/session-start.sh` when the local server is
41
+ healthy — so the underlying counter reset already works on every session
42
+ start; this release makes the manual fallback path discoverable from the
43
+ hook's own message.
44
+
45
+ Reproduction: trigger the checkpoint (implementation depth ≥ 20, cooldown
46
+ elapsed, server running) and inspect the `reason` field in the hook's
47
+ output. Before: ends with `or /grounding`. After: ends with the three-option
48
+ block including the explicit curl command for manual reset.
@@ -0,0 +1,124 @@
1
+ # Side-Effects Review — Telegram markdown renderer (PR1: formatter module, disabled)
2
+
3
+ **Version / slug:** `telegram-markdown-renderer-pr1`
4
+ **Date:** `2026-04-24`
5
+ **Author:** `echo`
6
+ **Second-pass reviewer:** `not required (no block/allow surface, no wiring into send paths, shipped disabled)`
7
+
8
+ ## Summary of the change
9
+
10
+ PR1 of the two-PR plan in `docs/specs/TELEGRAM-MARKDOWN-RENDERER-SPEC.md` (approved 2026-04-24 by Justin via Telegram topic 8183). Adds a new pure-function module `src/messaging/TelegramMarkdownFormatter.ts` that ports Dawn's `telegram_format.py` (the-portal) to TypeScript, plus a Vitest test suite `tests/unit/telegram-markdown-formatter.test.ts` with 105 passing tests.
11
+
12
+ The module exports `formatForTelegram(text, mode)`, `format(text, mode)`, `lintTelegramMarkdown(text)`, and primitives (`escapeHtmlText`, `escapeHtmlAttribute`, `isSafeUrl`). It implements the spec's full 12-step markdown→Telegram-HTML pipeline, a balanced-paren URL scanner (Wikipedia-style parens), WHATWG URL scheme allowlist, distinct HTML-text vs HTML-attribute escapers, NUL + Supplementary-PUA-B stripping for sentinel-collision safety, a 32KB input guard that falls back to plain mode without byte loss (`conversionSkipped: true`), and a `legacy-passthrough` mode that returns input byte-for-byte unchanged with `parseMode: undefined` so callers retain their historical `parse_mode`.
13
+
14
+ **Critically, no send path is wired to this module.** `TelegramAdapter.ts` and `TelegramLifeline.ts` are untouched. The module is dead code at runtime until PR2 wires `apiCall()` behind the `telegramFormatMode` config accessor. PR2 ships with `legacy-passthrough` as the default, so PR1 has zero behavioral effect on any agent even after PR2 merges.
15
+
16
+ ## Decision-point inventory
17
+
18
+ This PR contains no runtime decision points — the module is not called by anything. The future decision points it enables (documented here for completeness; all are PR2 scope):
19
+
20
+ - `TelegramAdapter.apiCall` — formatter invocation conditional on `method === 'sendMessage' || method === 'editMessageText'`. **Not in this PR.**
21
+ - `TelegramLifeline.apiCall` — same. **Not in this PR.**
22
+ - Trusted-internal-caller allowlist for `html` mode. **Not in this PR.**
23
+
24
+ Decision points inside the module itself (pure functions, no runtime authority):
25
+
26
+ - `isSafeUrl(raw)` — scheme allowlist (http/https/tg/mailto). Pure function; refuses unsafe schemes by returning `null`. Caller decides what to do with the rejection (emit literal text).
27
+ - `lintTelegramMarkdown(text)` — pure detector returning string array. Advisory-only; no blocking authority in this PR.
28
+ - 32KB length guard in `formatForTelegram` — falls back to plain mode on oversized input. Pure transformation; no network/storage side effect.
29
+
30
+ ---
31
+
32
+ ## 1. Over-block
33
+
34
+ **What legitimate inputs does this change reject that it shouldn't?**
35
+
36
+ No block/allow surface in PR1 — module is not wired. Future-facing concerns the module itself introduces:
37
+
38
+ - `legacy-passthrough` mode emits no lint issues (by design — it's the rollback target and must be behaviorally identical to pre-cutover). A future operator might want lint-as-observation in passthrough mode; noted as open question for PR2.
39
+ - `isSafeUrl` rejects `javascript:`, `data:`, `file:`, `vbscript:`, and any non-allowlisted scheme. Rejected links become literal text (`[click](javascript:...)` rendered verbatim) — a legitimate agent-authored `tg://resolve?domain=foo` link is permitted (mode allowed). Wikipedia-style `https://...wiki/X_(y)` URLs parse correctly via the balanced-paren scanner (covered by fixture test).
40
+
41
+ ---
42
+
43
+ ## 2. Under-block
44
+
45
+ **What failure modes does this still miss?**
46
+
47
+ No block/allow surface in PR1. Module-internal known gaps (documented in spec, accepted as v1):
48
+
49
+ - Italic between emoji (`🎉*bold*🎉`) renders literal asterisks because the punctuation-class lookaround doesn't include emoji — accepted v1 per spec iteration-2 L4.
50
+ - `tg://` deep links are permitted (spec allowlists them); future spec may tighten.
51
+ - PUA-B range is stripped from input before sentinels are inserted — this means a user message legitimately containing PUA-B codepoints will lose those bytes. Near-zero real-world usage; accepted trade-off per spec. Not flagged as `truncated` because "byte loss" in the spec is reserved for the oversized-`<pre>` fallback.
52
+
53
+ ---
54
+
55
+ ## 3. Level-of-abstraction fit
56
+
57
+ **Is this at the right layer?**
58
+
59
+ Yes. The module is a pure string-transform library at the same layer as `MessageFormatter.ts`. It owns no I/O, no config reading, no network, no logging. It does not hold blocking authority. The decision "should this send happen at all?" stays with the adapter/lifeline chokepoints; the formatter only answers "given this text and mode, what bytes go on the wire?"
60
+
61
+ This is consistent with the spec's architectural intent: the formatter is a detector+transformer producing `{ text, parseMode, lintIssues }`, consumed downstream by the adapter which holds the authoritative send/no-send decision.
62
+
63
+ ---
64
+
65
+ ## 4. Signal vs authority compliance
66
+
67
+ Per `docs/signal-vs-authority.md`:
68
+
69
+ - **Lint is a signal, not an authority.** `lintTelegramMarkdown` returns canonical prose-string issues. It does not reject a send. The spec specifies lint-strict mode (which a downstream authority can consume to return 422) as PR2 scope; PR1's lint is purely observational.
70
+ - **Scheme allowlist is a deterministic transform, not a policy decision.** `isSafeUrl` is brittle-by-design (WHATWG URL + scheme set). It does not block a send — it causes a link to render as literal text. The outbound send still happens. This satisfies the "brittle logic must not hold blocking authority" rule: brittle logic (regex/parse) produces a transformation, not a decision to refuse a user action.
71
+ - **No sentinel, gate, watchdog, or sentinel-class name is introduced by this PR.**
72
+
73
+ Compliance: PASS.
74
+
75
+ ---
76
+
77
+ ## 5. Interactions
78
+
79
+ - No shadow/shadowed interactions in PR1 — module is not called by anything. Search confirms no existing import site.
80
+ - Module name collision check: `src/messaging/` contains `MessageFormatter.ts` (different purpose: envelope formatting) and no `TelegramMarkdownFormatter.ts` prior to this PR. No collision.
81
+ - Test file name: `tests/unit/telegram-markdown-formatter.test.ts`. No existing test file of that name.
82
+ - PR2 will introduce interactions with `TelegramAdapter.apiCall`, `TelegramLifeline.apiCall`, `MessageStore` (raw/sent fields), and `GitSyncTransport` (envelope flag). Those interactions get their own artifact at PR2 time.
83
+
84
+ ---
85
+
86
+ ## 6. External surfaces
87
+
88
+ **Does it change anything visible to other agents, other users, other systems?**
89
+
90
+ No. PR1 ships dead code. No route changes, no message format changes on the wire, no config schema changes applied (config fields `telegramFormatMode` / `telegramLintStrict` are spec'd but deliberately not added in PR1 — they land in PR2 alongside the wiring), no database changes, no envelope changes.
91
+
92
+ - Bot API: untouched — adapter still sends exactly the bytes it sends today with exactly the `parse_mode` it uses today.
93
+ - MessageStore: untouched.
94
+ - GitSyncTransport: untouched.
95
+ - Shell-script `.claude/scripts/telegram-reply.sh`: untouched.
96
+ - Agent dashboards / self-knowledge: untouched.
97
+
98
+ No timing dependencies, no conversation state dependencies.
99
+
100
+ ---
101
+
102
+ ## 7. Rollback cost
103
+
104
+ **If this turns out wrong in production, what's the back-out?**
105
+
106
+ Trivial. PR1 is a code-only addition with no runtime invocation. Rollback options in order of cost:
107
+
108
+ 1. **Do nothing.** The module is not on any call path; a latent bug is invisible until PR2.
109
+ 2. **Revert the merge commit.** Standard `git revert` — affects only two new files. No data migration, no agent state repair, no config flip.
110
+ 3. **Fix forward.** The module is pure functions with 105 unit tests; most fixes ship as deltas.
111
+
112
+ PR2 itself is governed by the spec's staged-rollout (ships with `legacy-passthrough` default; canary via config flip). That's PR2's rollback story — out of scope for this artifact.
113
+
114
+ ---
115
+
116
+ ## Second-pass review
117
+
118
+ Not required. PR1 has no block/allow surface, no session-lifecycle surface, no sentinel/gate/watchdog, no coherence/idempotency/trust change, and is shipped disabled. High-risk criteria from Phase 5 are not met.
119
+
120
+ ## Spec linkage
121
+
122
+ - Approved spec: `docs/specs/TELEGRAM-MARKDOWN-RENDERER-SPEC.md` (approved 2026-04-24T20:53:47Z by Justin via Telegram topic 8183).
123
+ - Convergence report: `docs/specs/reports/telegram-markdown-renderer-convergence.md`.
124
+ - Dawn reference impl: `the-portal/.claude/scripts/telegram_format.py` (merged 2026-04-24T17:57Z).