instar 1.3.296 → 1.3.298
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/dist/commands/server.d.ts.map +1 -1
- package/dist/commands/server.js +8 -0
- package/dist/commands/server.js.map +1 -1
- package/dist/core/SessionManager.d.ts.map +1 -1
- package/dist/core/SessionManager.js +25 -1
- package/dist/core/SessionManager.js.map +1 -1
- package/dist/core/paneText.d.ts +9 -0
- package/dist/core/paneText.d.ts.map +1 -1
- package/dist/core/paneText.js +53 -0
- package/dist/core/paneText.js.map +1 -1
- package/package.json +1 -1
- package/scripts/decision-audit-presence-check.mjs +132 -0
- package/src/data/builtin-manifest.json +3 -3
- package/upgrades/1.3.297.md +21 -0
- package/upgrades/1.3.298.md +20 -0
- package/upgrades/decision-audit-presence.eli16.md +5 -0
- package/upgrades/gemini-final-pane-relay.eli16.md +9 -0
- package/upgrades/side-effects/decision-audit-presence.md +47 -0
- package/upgrades/side-effects/gemini-final-pane-relay.md +42 -0
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// safe-git-allow: CI-only gate script — single read-only `git diff --name-status`
|
|
3
|
+
// against the Actions checkout; runs on ubuntu runners where the TS
|
|
4
|
+
// SafeGitExecutor is not importable from a standalone .mjs.
|
|
5
|
+
/**
|
|
6
|
+
* decision-audit-presence-check — gate-bypass detector (task #81 close-out).
|
|
7
|
+
*
|
|
8
|
+
* Every commit that touches in-scope files (src/, scripts/, .husky/, skills/
|
|
9
|
+
* code) is supposed to pass through the local instar-dev pre-commit gate,
|
|
10
|
+
* which writes + stages a decision-audit record. When the gate is silently
|
|
11
|
+
* absent — the live case: a worktree created with raw `git worktree add` has
|
|
12
|
+
* no husky shim, so `git commit` runs ZERO hooks — the commits arrive with no
|
|
13
|
+
* audit record, and nothing notices. CI re-runs the substantive checks, but
|
|
14
|
+
* the audit trail has holes and gate-block UX (tier floors, deferral
|
|
15
|
+
* detection) never fired for those commits.
|
|
16
|
+
*
|
|
17
|
+
* Structure > Willpower: this check makes the bypass VISIBLE at the PR
|
|
18
|
+
* boundary. A PR whose changes include in-scope files must also carry gate
|
|
19
|
+
* evidence — a per-entry decision file (post-#827: one
|
|
20
|
+
* `.instar/instar-dev-decisions/<ts>-<slug>.json` added per gate run) or, as
|
|
21
|
+
* transition grace for PRs authored under the pre-#827 writer, a modification
|
|
22
|
+
* to the legacy `.instar/instar-dev-decisions.jsonl`.
|
|
23
|
+
*
|
|
24
|
+
* Exemptions mirror the eli16 PR gate: bot authors and the automated
|
|
25
|
+
* release-cut PR.
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
import { execFileSync } from 'node:child_process';
|
|
29
|
+
|
|
30
|
+
// Keep in sync with inScope() in scripts/instar-dev-precommit.js — the gate
|
|
31
|
+
// this check detects bypasses OF. (A drift here only weakens detection, never
|
|
32
|
+
// blocks a legitimate PR: extra in-scope prefixes would require evidence from
|
|
33
|
+
// PRs the local gate also covers.)
|
|
34
|
+
export function isInScopeFile(file) {
|
|
35
|
+
if (file.startsWith('src/')) return true;
|
|
36
|
+
if (file.startsWith('scripts/')) return true;
|
|
37
|
+
if (file.startsWith('.husky/')) return true;
|
|
38
|
+
if (file.startsWith('skills/') && file.endsWith('SKILL.md')) return true;
|
|
39
|
+
if (file.startsWith('skills/') && (file.endsWith('.sh') || file.endsWith('.mjs') || file.endsWith('.js'))) return true;
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function isGateEvidence(change) {
|
|
44
|
+
// Post-#827 per-entry file (added per gate evaluation)…
|
|
45
|
+
if (/^\.instar\/instar-dev-decisions\/.+\.json$/.test(change.file)) return true;
|
|
46
|
+
// …or the pre-#827 legacy JSONL append (transition grace for in-flight PRs).
|
|
47
|
+
if (change.file === '.instar/instar-dev-decisions.jsonl') return true;
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Pure evaluation — exported for unit tests.
|
|
53
|
+
* @param {{ changes: Array<{status: string, file: string}>, title?: string, authorType?: string }} input
|
|
54
|
+
* @returns {{ ok: boolean, exempt?: string, reason?: string, inScopeFiles?: string[] }}
|
|
55
|
+
*/
|
|
56
|
+
export function evaluateDecisionAuditPresence(input) {
|
|
57
|
+
const title = String(input?.title ?? '');
|
|
58
|
+
if (String(input?.authorType ?? '') === 'Bot') return { ok: true, exempt: 'bot-author' };
|
|
59
|
+
if (/^chore:\s*release\b/i.test(title)) return { ok: true, exempt: 'release-cut' };
|
|
60
|
+
|
|
61
|
+
const changes = Array.isArray(input?.changes) ? input.changes : [];
|
|
62
|
+
const inScopeFiles = changes.map((c) => c.file).filter(isInScopeFile);
|
|
63
|
+
if (inScopeFiles.length === 0) {
|
|
64
|
+
return { ok: true, reason: 'no in-scope changes — local gate not required' };
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const hasEvidence = changes.some(isGateEvidence);
|
|
68
|
+
if (hasEvidence) {
|
|
69
|
+
return { ok: true, reason: 'gate evidence present', inScopeFiles };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return {
|
|
73
|
+
ok: false,
|
|
74
|
+
inScopeFiles,
|
|
75
|
+
reason:
|
|
76
|
+
`This PR changes ${inScopeFiles.length} in-scope file(s) but carries NO decision-audit record — ` +
|
|
77
|
+
`the local instar-dev pre-commit gate did not run for these commits. The usual cause is a build ` +
|
|
78
|
+
`worktree without the husky shim (created with raw 'git worktree add' instead of 'instar worktree ` +
|
|
79
|
+
`create'). Fix: in the worktree run 'npm run prepare' (wires .husky/_), then re-commit so the gate ` +
|
|
80
|
+
`evaluates the change and its audit entry (.instar/instar-dev-decisions/<ts>-<slug>.json) rides the ` +
|
|
81
|
+
`commit. See tasks #81/#80 and PRs #827/#829.`,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** Parse `git diff --name-status base...head` output into change records. */
|
|
86
|
+
export function parseNameStatus(text) {
|
|
87
|
+
const changes = [];
|
|
88
|
+
for (const line of String(text).split('\n')) {
|
|
89
|
+
const t = line.trim();
|
|
90
|
+
if (!t) continue;
|
|
91
|
+
// Format: "<STATUS>\t<path>" (renames: "R100\t<old>\t<new>" — take the new path).
|
|
92
|
+
const parts = t.split('\t');
|
|
93
|
+
if (parts.length < 2) continue;
|
|
94
|
+
const status = parts[0];
|
|
95
|
+
const file = parts[parts.length - 1];
|
|
96
|
+
changes.push({ status, file });
|
|
97
|
+
}
|
|
98
|
+
return changes;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// ── CLI entrypoint (CI) ────────────────────────────────────────────────────
|
|
102
|
+
const invokedDirectly = process.argv[1] && import.meta.url.endsWith(process.argv[1].split('/').pop());
|
|
103
|
+
if (invokedDirectly) {
|
|
104
|
+
const baseSha = process.env.BASE_SHA;
|
|
105
|
+
const headSha = process.env.HEAD_SHA;
|
|
106
|
+
if (!baseSha || !headSha) {
|
|
107
|
+
console.error('decision-audit gate: BASE_SHA and HEAD_SHA env vars are required.');
|
|
108
|
+
process.exit(2);
|
|
109
|
+
}
|
|
110
|
+
let diffOut;
|
|
111
|
+
try {
|
|
112
|
+
diffOut = execFileSync('git', ['diff', '--name-status', `${baseSha}...${headSha}`], { encoding: 'utf8' });
|
|
113
|
+
} catch (err) {
|
|
114
|
+
console.error(`decision-audit gate: git diff failed — ${err instanceof Error ? err.message : String(err)}`);
|
|
115
|
+
process.exit(2);
|
|
116
|
+
}
|
|
117
|
+
const res = evaluateDecisionAuditPresence({
|
|
118
|
+
changes: parseNameStatus(diffOut),
|
|
119
|
+
title: process.env.PR_TITLE,
|
|
120
|
+
authorType: process.env.PR_AUTHOR_TYPE,
|
|
121
|
+
});
|
|
122
|
+
if (res.ok) {
|
|
123
|
+
console.log(`decision-audit gate: OK — ${res.exempt ? `exempt (${res.exempt})` : res.reason}`);
|
|
124
|
+
process.exit(0);
|
|
125
|
+
}
|
|
126
|
+
console.error('decision-audit gate: FAIL');
|
|
127
|
+
console.error(res.reason);
|
|
128
|
+
console.error('');
|
|
129
|
+
console.error('In-scope files without gate evidence:');
|
|
130
|
+
for (const f of res.inScopeFiles ?? []) console.error(` - ${f}`);
|
|
131
|
+
process.exit(1);
|
|
132
|
+
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "./builtin-manifest.schema.json",
|
|
3
3
|
"schemaVersion": 1,
|
|
4
|
-
"generatedAt": "2026-06-05T13:
|
|
5
|
-
"instarVersion": "1.3.
|
|
4
|
+
"generatedAt": "2026-06-05T13:55:19.961Z",
|
|
5
|
+
"instarVersion": "1.3.298",
|
|
6
6
|
"entryCount": 198,
|
|
7
7
|
"entries": {
|
|
8
8
|
"hook:session-start": {
|
|
@@ -1506,7 +1506,7 @@
|
|
|
1506
1506
|
"type": "subsystem",
|
|
1507
1507
|
"domain": "sessions",
|
|
1508
1508
|
"sourcePath": "src/core/SessionManager.ts",
|
|
1509
|
-
"contentHash": "
|
|
1509
|
+
"contentHash": "4798aa00b08d4697ccaa2fbdba6224289b7bd21290dad9c4a911c0bfd9bc657f",
|
|
1510
1510
|
"since": "2025-01-01"
|
|
1511
1511
|
},
|
|
1512
1512
|
"subsystem:auto-updater": {
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Upgrade Guide — vNEXT
|
|
2
|
+
|
|
3
|
+
<!-- assembled-by: assemble-next-md -->
|
|
4
|
+
<!-- bump: patch -->
|
|
5
|
+
|
|
6
|
+
## What Changed
|
|
7
|
+
|
|
8
|
+
New `scripts/decision-audit-presence-check.mjs` (pure evaluator + CLI) and `.github/workflows/decision-audit-gate.yml`. The in-scope predicate mirrors `scripts/instar-dev-precommit.js`.
|
|
9
|
+
|
|
10
|
+
## What to Tell Your User
|
|
11
|
+
|
|
12
|
+
Nothing user-visible — contributor CI. Pull requests that change gate-scoped code now fail fast if the local pre-commit gate never ran for them (the silent-bypass case), with a message that says exactly how to fix it.
|
|
13
|
+
|
|
14
|
+
## Summary of New Capabilities
|
|
15
|
+
|
|
16
|
+
- `decision-audit-gate` CI check: a PR touching src/scripts/.husky/skills code must include a decision-audit record (per-entry file post-#827, or a legacy jsonl modification as transition grace). Bot + release-cut PRs exempt.
|
|
17
|
+
- `.gitignore` now ignores a symlinked `node_modules` too (trailing-slash patterns only match real directories).
|
|
18
|
+
|
|
19
|
+
## Evidence
|
|
20
|
+
|
|
21
|
+
Live bypass this detects (2026-06-05): three build worktrees created with raw `git worktree add` had no husky shim — `git commit` ran zero hooks, so a full night's worktree commits carried no decision-audit records and nothing noticed (root fixed in #829; this is the structural backstop). Pinned by `tests/unit/decision-audit-presence-check.test.ts` (9 tests: scope predicate both sides, name-status parsing incl. renames, per-entry evidence passes, legacy-grace passes, the bypass shape FAILS with the actionable husky/`npm run prepare` message, docs-only passes, bot/release exemptions). CLI self-test green on an empty diff.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Upgrade Guide — vNEXT
|
|
2
|
+
|
|
3
|
+
<!-- assembled-by: assemble-next-md -->
|
|
4
|
+
<!-- bump: patch -->
|
|
5
|
+
|
|
6
|
+
## What Changed
|
|
7
|
+
|
|
8
|
+
Added a Gemini-specific fallback for topic sessions that finish a Telegram turn in the live pane without running the Telegram reply script. When a Gemini CLI session still has a pending Telegram injection, SessionManager now recognizes the completed final assistant block after the matching Telegram prompt and emits a detected reply once Gemini has returned to its input footer. Server wiring sends that reply back to the original Telegram topic.
|
|
9
|
+
|
|
10
|
+
## What to Tell Your User
|
|
11
|
+
|
|
12
|
+
Gemini topic sessions can now relay a completed final pane answer back to Telegram instead of leaving you with silence after the work finishes.
|
|
13
|
+
|
|
14
|
+
## Summary of New Capabilities
|
|
15
|
+
|
|
16
|
+
- Gemini final pane answers are detected and relayed for topic sessions with an unanswered Telegram message.
|
|
17
|
+
|
|
18
|
+
## Evidence
|
|
19
|
+
|
|
20
|
+
Live repro before the fix: Gemini topic session gemini-topic-1 showed GEMI_TASK_REPORT_1780640360 in its completed pane output, while Telegram only received the acknowledgement/status/gate messages and no final report. After the fix, focused unit coverage verifies the Gemini pane extractor and the pending-injection monitor path that clears the tracker and emits the detected reply for Telegram delivery.
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# A new PR check catches commits that skipped the local safety gate
|
|
2
|
+
|
|
3
|
+
Every code commit in this repo is supposed to pass through a local pre-commit gate that runs lint, tier checks, and writes a small audit record of the decision. That gate is wired up by husky, a tool that activates git hooks when dependencies are installed. We discovered (the hard way, across three build folders in one night) that folders created with raw git commands never get that wiring — so commits sail through with zero local checks and no audit record, and nothing anywhere notices. CI still re-runs the big checks on the pull request, but the gate's own protections (tier floors, deferral detection, the audit trail) silently never happened.
|
|
4
|
+
|
|
5
|
+
The root cause in the worktree-creation command is fixed separately. This change adds the structural backstop: a pull-request check that looks at what the PR changes. If it touches gate-scoped code (src, scripts, hooks, skills) it must ALSO carry the gate's audit record — the small decision file the gate stages into every commit it evaluates. A code PR with no record means the gate never ran for those commits, and the check fails with a message that names the likely cause (a worktree without hook wiring) and the exact fix (run `npm run prepare`, then re-commit). Docs-only PRs, bot PRs, and the automated release PR are unaffected, and PRs from before the audit-format change are accepted via their old-format record. Also fixes the `.gitignore` pattern so a symlinked `node_modules` can't be accidentally committed (a slip this very investigation made once).
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Gemini final pane replies now reach Telegram
|
|
2
|
+
|
|
3
|
+
Gemini can finish a Telegram task by printing the final answer in its terminal pane without running the Telegram reply script. That is exactly the bad user experience: the work is visible in the live pane, but Telegram stays silent.
|
|
4
|
+
|
|
5
|
+
This change gives the session monitor a Gemini-specific fallback. When a Gemini topic has an unanswered Telegram message, the monitor looks for Gemini's completed assistant block: a line beginning with `✦`, followed later by Gemini's normal input footer. Only then does it treat the block as the reply and send it to the Telegram topic.
|
|
6
|
+
|
|
7
|
+
The guard is intentionally narrow. It only runs for `gemini-cli` sessions with a pending Telegram injection, only considers text after the matching `[telegram:N]` prompt, and only fires after Gemini has returned to the input/footer state. Claude and Codex keep their existing reply-script and transcript paths.
|
|
8
|
+
|
|
9
|
+
Respawn-context note: after the server restart, the durable pieces survived: the Telegram history preserved the cycle id and repro, and the `gemini-final-output-relay` worktree survived cleanly. What had to be re-derived was the in-memory claim-check trail: which exact source files owned final relay, completion detection, and Gemini pane parsing.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Side-Effects Review — decision-audit presence PR gate (task #81 close-out)
|
|
2
|
+
|
|
3
|
+
**Version / slug:** `decision-audit-presence`
|
|
4
|
+
**Date:** `2026-06-05`
|
|
5
|
+
**Author:** `echo`
|
|
6
|
+
**Second-pass reviewer:** `self-review under the Tier-1 lite lane; over-block analysis below covers every legitimate-PR shape considered`
|
|
7
|
+
|
|
8
|
+
## Summary of the change
|
|
9
|
+
|
|
10
|
+
New PR-boundary check (`scripts/decision-audit-presence-check.mjs` + `.github/workflows/decision-audit-gate.yml`): a PR whose diff touches gate-scoped files (src/, scripts/, .husky/, skills/ code — the same `inScope` predicate as the pre-commit gate) must also carry gate evidence: an added `.instar/instar-dev-decisions/*.json` per-entry file (post-#827) or a modified legacy `.instar/instar-dev-decisions.jsonl` (transition grace). Otherwise it fails with an actionable message naming the husky-shim cause and the `npm run prepare` fix. Plus: `.gitignore` `node_modules/` → `node_modules` so the worktree node_modules SYMLINK is ignored too (trailing-slash patterns match only directories; the symlink slipped into a commit once tonight).
|
|
11
|
+
|
|
12
|
+
## Decision-point inventory
|
|
13
|
+
|
|
14
|
+
- `evaluateDecisionAuditPresence` — add — pure; exemptions mirror the eli16 PR gate (Bot authors, `chore: release` titles).
|
|
15
|
+
- `isInScopeFile` — add — duplicated from `scripts/instar-dev-precommit.js` `inScope()` with a sync comment; drift only weakens detection, never blocks a PR the local gate doesn't also cover.
|
|
16
|
+
- Workflow — add — `pull_request` types opened/synchronize/reopened/ready_for_review, `contents: read`, full-depth checkout for the three-dot diff.
|
|
17
|
+
- `.gitignore` — modified — one-line pattern fix.
|
|
18
|
+
|
|
19
|
+
## 1. Over-block analysis (can this fail a legitimate PR?)
|
|
20
|
+
|
|
21
|
+
- **Docs/tests/upgrades-only PRs** — pass (no in-scope files).
|
|
22
|
+
- **In-flight pre-#827 PRs** — pass via the legacy-jsonl grace path (their gate appended a line).
|
|
23
|
+
- **Gated code PRs** — pass: the gate stages an audit record into every evaluated commit (post-#814), so evidence is present by construction.
|
|
24
|
+
- **The genuinely-blocked shape** — in-scope changes with NO record — is exactly the bypass this exists to surface. The failure message gives the one-command fix.
|
|
25
|
+
- **Bots + release-cut** — exempt, mirroring the eli16 gate.
|
|
26
|
+
- **Squash-merge interaction** — none: the check runs on the PR diff (base...head), not on merged history.
|
|
27
|
+
- Residual risk: an operator hand-editing in-scope files via the GitHub web UI would fail the check — correctly, since the gate never evaluated that change; the fix message applies (commit locally through the gate).
|
|
28
|
+
|
|
29
|
+
## 2. Under-block
|
|
30
|
+
|
|
31
|
+
Evidence is presence-based, not per-commit: one gated commit in a PR vouches for the PR even if a sibling commit bypassed. Accepted for this slice — the common failure mode (a WHOLE worktree without hooks) produces zero evidence and is caught. Per-commit matching would need trace↔commit correlation; noted as a possible tightening, not promised.
|
|
32
|
+
|
|
33
|
+
## 3. Signal vs authority
|
|
34
|
+
|
|
35
|
+
Deterministic file-presence check — no LLM, no semantic classification. Authority shape matches existing required CI (eli16 gate, repo invariants).
|
|
36
|
+
|
|
37
|
+
## 4. Migration parity
|
|
38
|
+
|
|
39
|
+
None — repo CI infrastructure, not agent-installed files.
|
|
40
|
+
|
|
41
|
+
## 5. Token/cost impact
|
|
42
|
+
|
|
43
|
+
One ubuntu CI job per PR event, seconds long. No LLM calls.
|
|
44
|
+
|
|
45
|
+
## 6. Rollback
|
|
46
|
+
|
|
47
|
+
Delete the workflow file (or revert); the script is inert without it.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Side-Effects Review — Gemini final pane Telegram relay
|
|
2
|
+
|
|
3
|
+
**Version / slug:** `gemini-final-pane-relay`
|
|
4
|
+
**Date:** `2026-06-05`
|
|
5
|
+
**Author:** `instar-codey`
|
|
6
|
+
|
|
7
|
+
## Summary
|
|
8
|
+
|
|
9
|
+
When a `gemini-cli` topic session has a pending Telegram injection, `SessionManager` now checks the captured pane for a completed Gemini assistant block and emits `injectionReplyDetected`. Server wiring sends that detected reply to the same Telegram topic.
|
|
10
|
+
|
|
11
|
+
## Decision-point inventory
|
|
12
|
+
|
|
13
|
+
- Gemini pane parser — added — pure helper in `paneText`, requiring a `✦` assistant block followed by Gemini's idle/input footer.
|
|
14
|
+
- Pending-injection monitor — modified — Gemini-only branch after liveness is confirmed and before generic completion/timeout checks.
|
|
15
|
+
- Telegram send wiring — added — listens for `injectionReplyDetected` and posts to the original topic.
|
|
16
|
+
|
|
17
|
+
## Direction of failure
|
|
18
|
+
|
|
19
|
+
- Old failure: Gemini completed work in-pane, but no Telegram reply was sent because Gemini did not execute the relay script.
|
|
20
|
+
- New behavior: a completed Gemini final block is relayed once and clears the pending injection tracker.
|
|
21
|
+
- Conservative failure direction: if the pane shape is ambiguous, lacks the matching `[telegram:N]` marker, or Gemini has not returned to the idle footer, no automatic relay happens.
|
|
22
|
+
|
|
23
|
+
## Side-effects checklist
|
|
24
|
+
|
|
25
|
+
1. **Over-block:** The implementation relays only; it does not reject inputs or user actions. The concrete false-negative tradeoff is conservative non-relay when Gemini's footer shape changes, when the matching Telegram marker has scrolled out of the 400-line capture, or when the final block uses a shape other than the `✦` assistant marker.
|
|
26
|
+
2. **Under-block:** It can still miss very long Gemini answers where the original `[telegram:N]` marker is outside the captured tail, panes with a future Gemini TUI footer vocabulary, or answers that are complete but remain in an intermediate TUI state without the idle footer.
|
|
27
|
+
3. **Level-of-abstraction fit:** The helper lives in `paneText` because it is pane-shape parsing, not Telegram delivery policy. `SessionManager` owns the pending-injection tracker and can decide when a framework-specific pane observation is eligible for relay. `server` remains the Telegram transport boundary.
|
|
28
|
+
4. **Signal vs authority compliance:** The parser is a detector and does not hold blocking authority. It only produces a completed-reply signal after a pending Gemini Telegram injection exists; the server listener surfaces that signal to the original topic. This complies with `docs/signal-vs-authority.md` because the brittle regex/TUI detection never blocks a judgment path.
|
|
29
|
+
5. **Interactions:** The branch is scoped to `framework === 'gemini-cli'` and a live pending injection, so Claude and Codex transcript/reply-script behavior is unchanged. The pending injection is cleared before emitting the event to avoid duplicate sends on subsequent monitor ticks.
|
|
30
|
+
6. **External surfaces:** Telegram users can now receive a Gemini final pane answer that previously stayed visible only in tmux. The behavior depends on runtime pane text, the pending-injection map, and Gemini's idle footer, so the implementation is intentionally narrow and fail-closed.
|
|
31
|
+
7. **Rollback cost:** Reverting the parser, the Gemini monitor branch, and the server listener restores the prior behavior without data migration or state repair.
|
|
32
|
+
|
|
33
|
+
## Scope not taken
|
|
34
|
+
|
|
35
|
+
- No Claude/Codex behavior changes.
|
|
36
|
+
- No broad "scrape any final-looking text" behavior.
|
|
37
|
+
- No stale Gemini quota telemetry work; that remains parked per operator instruction.
|
|
38
|
+
- No task-boundary blending fix; recorded as observation only.
|
|
39
|
+
|
|
40
|
+
## Rollback
|
|
41
|
+
|
|
42
|
+
Revert the parser, the Gemini pending-injection branch, and the `injectionReplyDetected` server listener. Gemini returns to the previous behavior: visible pane output may remain silent unless the agent runs the reply script.
|