@r1z4x/tezgah 1.13.0 → 1.14.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.
- package/CHANGELOG.md +175 -1
- package/MANIFEST +18 -0
- package/NOTICE +152 -0
- package/README.de.md +41 -20
- package/README.es.md +39 -19
- package/README.fr.md +41 -20
- package/README.md +15 -8
- package/README.tr.md +39 -21
- package/bin/codegen +9 -2
- package/bin/consult +6 -0
- package/bin/tezgah-adhd +3 -0
- package/bin/tezgah-agents +3 -0
- package/bin/tezgah-capture +3 -0
- package/bin/tezgah-design +329 -54
- package/bin/tezgah-docs +157 -41
- package/bin/tezgah-dsh +1 -1
- package/bin/tezgah-gate +7 -2
- package/bin/tezgah-import-ai-research +16 -4
- package/bin/tezgah-index +3 -0
- package/bin/tezgah-lessons +13 -4
- package/bin/tezgah-mcp +4 -0
- package/bin/tezgah-migrate +3 -0
- package/bin/tezgah-ocr-review +2 -1
- package/bin/tezgah-optimize +4 -1
- package/bin/tezgah-pony +3 -0
- package/bin/tezgah-research +12 -6
- package/bin/tezgah-rollback +3 -0
- package/bin/tezgah-route +1 -1
- package/bin/tezgah-setup +596 -157
- package/bin/tezgah-status +11 -1
- package/bin/tezgah-task +3 -0
- package/bin/tezgah.js +10 -3
- package/commands/adhd.md +1 -1
- package/docs/README.md +19 -8
- package/docs/architecture.md +2 -2
- package/docs/citations-baseline.json +11 -17
- package/docs/clarity-baseline.json +3 -3
- package/docs/contract.md +77 -31
- package/docs/environment.md +58 -24
- package/docs/evidence.md +49 -19
- package/docs/gate.md +71 -21
- package/docs/hosts.md +65 -52
- package/docs/layers.md +1 -1
- package/docs/operations.md +67 -24
- package/docs/research.md +1 -1
- package/docs/skills.md +31 -8
- package/docs/status-line.md +33 -23
- package/docs/testing.md +48 -17
- package/docs/vision.md +6 -2
- package/hooks/lang/en.json +5 -2
- package/hooks/lang/tr.json +3 -2
- package/hooks/projects-posttooluse.py +11 -3
- package/hooks/projects-stop.py +1 -1
- package/hooks/tezgah_context.py +40 -23
- package/hooks/tezgah_gate.py +404 -106
- package/hooks/tezgah_integrity.py +367 -97
- package/hooks/tezgah_lessons.py +5 -2
- package/hooks/tezgah_paths.py +17 -6
- package/hooks/tezgah_policy.py +13 -5
- package/hooks/tezgah_skill_pick.py +1 -1
- package/hooks/tezgah_snapshot.py +6 -3
- package/hooks/tezgah_stopspec.py +2 -1
- package/hosts/amp/hook.py +1 -1
- package/hosts/amp/tezgah-plugin.ts.in +13 -3
- package/hosts/antigravity/hook.py +1 -1
- package/hosts/codex/hook.py +1 -1
- package/hosts/commandcode/hook.py +1 -1
- package/hosts/copilot/hook.py +1 -1
- package/hosts/cursor/hook.py +2 -1
- package/hosts/droid/hook.py +1 -1
- package/hosts/gemini/hook.py +1 -1
- package/hosts/goose/hook.py +1 -1
- package/hosts/omp/hook.py +1 -1
- package/hosts/omp/tezgah-hook.ts.in +127 -35
- package/hosts/opencode/plugins/tezgah.js +209 -63
- package/hosts/qwen/hook.py +1 -1
- package/output-styles/tezgah.md +1 -1
- package/package.json +6 -3
- package/packaging/build.sh +4 -4
- package/packaging/install.sh +11 -0
- package/packaging/upgrade.sh +3 -0
- package/skills/ai-research/LICENSE +21 -0
- package/skills/design-contract/SKILL.md +27 -6
- package/skills/design-library/LICENSE +21 -0
- package/skills/plan-add/render_table.py +7 -0
- package/skills/pm-frameworks/LICENSE +21 -0
- package/skills/rl-env/LICENSE +201 -0
- package/skills/tezgah-contract/SKILL.md +2 -2
- package/third_party/open-code-review/LICENSE +201 -0
- package/third_party/open-code-review/README.md +15 -0
- package/third_party/open-code-review/prompts/main_task_system.md +26 -0
- package/third_party/open-code-review/prompts/review_filter_task_system.md +13 -0
- package/workflows/graph-map.js +14 -5
package/docs/skills.md
CHANGED
|
@@ -217,8 +217,8 @@ inside the repository (`hooks/tezgah_skill_pick.py::section_hint`,
|
|
|
217
217
|
Measured on this machine on 2026-10-07: 7 502 sections and a 9.5 MB index. The
|
|
218
218
|
one cold rebuild took 1.36 s, and a warm prompt takes 6-15 ms. On a turn it
|
|
219
219
|
fires the line costs 196-239 bytes on omp and 245-320 elsewhere. It is not a
|
|
220
|
-
judgement, so `judge-off` leaves it on
|
|
221
|
-
|
|
220
|
+
judgement, so `judge-off` leaves it on, and so does `reminder-off`, which drops
|
|
221
|
+
only the reminder line (`tests/test_skill_search.py::LocalHint`,
|
|
222
222
|
`OmpPromptPath`).
|
|
223
223
|
|
|
224
224
|
|
|
@@ -226,10 +226,31 @@ of the per-turn text (`tests/test_skill_search.py::LocalHint`,
|
|
|
226
226
|
|
|
227
227
|
`SKILLS` in `bin/tezgah-setup::SKILLS` is the shipped list, and it is the single
|
|
228
228
|
definition of "a tezgah skill": the router, the per-host linking, the uninstall
|
|
229
|
-
and the context budget all read it.
|
|
230
|
-
directories into the host's own skill directory
|
|
231
|
-
|
|
232
|
-
|
|
229
|
+
and the context budget all read it. Every host but Claude has an install function
|
|
230
|
+
that links those directories into the host's own skill directory:
|
|
231
|
+
|
|
232
|
+
| Host | Install function | Skill directory |
|
|
233
|
+
|---|---|---|
|
|
234
|
+
| Codex | `bin/tezgah-setup::install_codex` | `$CODEX_HOME/skills` |
|
|
235
|
+
| opencode | `bin/tezgah-setup::install_opencode` | `~/.config/opencode/skills` |
|
|
236
|
+
| Cursor | `bin/tezgah-setup::install_cursor` | `~/.cursor/skills`, only for a skill no other dir Cursor reads already links |
|
|
237
|
+
| dsh | `bin/tezgah-setup::install_dsh` | `$DSH_HOME/skills` |
|
|
238
|
+
| omp | `bin/tezgah-setup::install_omp` | `~/.omp/agent/skills` |
|
|
239
|
+
| Qwen Code | `bin/tezgah-setup::install_qwen` | `$QWEN_HOME/skills` |
|
|
240
|
+
| Droid | `bin/tezgah-setup::install_droid` | `~/.factory/skills` |
|
|
241
|
+
| Command Code | `bin/tezgah-setup::install_commandcode` | `~/.commandcode/skills` |
|
|
242
|
+
| Copilot CLI | `bin/tezgah-setup::install_copilot` | `$COPILOT_HOME/skills` |
|
|
243
|
+
| Gemini CLI | `bin/tezgah-setup::install_gemini` | `~/.gemini/extensions/tezgah/skills` |
|
|
244
|
+
| Antigravity | `bin/tezgah-setup::install_antigravity` | `~/.gemini/antigravity-cli/skills` |
|
|
245
|
+
| Goose | `bin/tezgah-setup::install_goose` | `~/.agents/plugins/tezgah/skills` |
|
|
246
|
+
| Amp | `bin/tezgah-setup::install_amp` | `~/.config/amp/skills` |
|
|
247
|
+
|
|
248
|
+
Cursor reads `~/.codex/skills`, `~/.claude/skills` and `~/.agents/skills` too,
|
|
249
|
+
and names no winner for a skill found twice. So a skill one of those already
|
|
250
|
+
links to this tree is not linked into `~/.cursor/skills` again
|
|
251
|
+
(`bin/tezgah-setup::cursor_shared_copy`, `bin/tezgah-setup::CURSOR_SHARED_SKILLS`). The install prints
|
|
252
|
+
`<n> skills reach Cursor through <dir>, not linked twice`. Cursor installs after
|
|
253
|
+
Codex, so it sees Codex's links. Claude is the exception: it installs from a
|
|
233
254
|
plugin, so the skills arrive in the COPY at
|
|
234
255
|
`~/.claude/plugins/cache/<marketplace>/tezgah/<version>/` that `--sync` refreshes
|
|
235
256
|
and `--install` re-refreshes when it is stale (`bin/tezgah-setup:26-29`,
|
|
@@ -238,8 +259,10 @@ and `--install` re-refreshes when it is stale (`bin/tezgah-setup:26-29`,
|
|
|
238
259
|
|
|
239
260
|
The install report checks the file, not the link. `skills_linked()` requires
|
|
240
261
|
every name in `SKILLS` to resolve to a readable `SKILL.md` under the host
|
|
241
|
-
directory (`skills_linked()`, `bin/tezgah-setup::skills_linked`), and
|
|
242
|
-
|
|
262
|
+
directory (`skills_linked()`, `bin/tezgah-setup::skills_linked`), and the `skills linked` row of
|
|
263
|
+
every host but Claude and Cursor calls it (`host_checks_<host>`, for example
|
|
264
|
+
`bin/tezgah-setup::host_checks_codex`). Cursor's row accepts either a readable
|
|
265
|
+
`SKILL.md` under `~/.cursor/skills` or a shared copy (`bin/tezgah-setup::host_checks_cursor`). It was
|
|
243
266
|
`islink()` once, and a link to nothing is a link: a name whose `SKILL.md` was
|
|
244
267
|
never written reported as linked on every host at once while no host could read
|
|
245
268
|
it (`tests/test_skills.py::SkillStandards`).
|
package/docs/status-line.md
CHANGED
|
@@ -15,8 +15,8 @@ host-neutrally by `health_segments()` (`hooks/tezgah_context.py::health_segments
|
|
|
15
15
|
groups (`hooks/tezgah_context.py::render_line`). The group is *data on each segment*: a renderer building its
|
|
16
16
|
own line from `--json` separates on `seg.group` and matches `render_line()`
|
|
17
17
|
without a second copy of the partition (`hooks/tezgah_context.py::health_segments`) — opencode and dsh do exactly
|
|
18
|
-
that (hosts/opencode/tui/tezgah-tui.tsx
|
|
19
|
-
hosts/dsh/statusline/lib/client.js
|
|
18
|
+
that (`TezgahBar` in `hosts/opencode/tui/tezgah-tui.tsx`,
|
|
19
|
+
`TezgahStatusLine` in `hosts/dsh/statusline/lib/client.js`).
|
|
20
20
|
|
|
21
21
|
| group | members | why together |
|
|
22
22
|
|---|---|---|
|
|
@@ -173,7 +173,12 @@ group separators stay identical for every extension. An extension never has to
|
|
|
173
173
|
know the gutter. It must name `text` and `state`. tezgah fills a missing `glyph`
|
|
174
174
|
from the state's own mark, so a chip reads like a built-in. The per-extension cap
|
|
175
175
|
(`MAX_SEGMENTS`) and the hard timeout (`timeout_ms`, default
|
|
176
|
-
`DEFAULT_TIMEOUT_MS`) bound one row.
|
|
176
|
+
`DEFAULT_TIMEOUT_MS`) bound one row. The command prints one JSON object whose
|
|
177
|
+
`segments` key holds that list. tezgah reads a bare list on stdout as malformed output:
|
|
178
|
+
|
|
179
|
+
```json
|
|
180
|
+
{"segments": [{"key": "cyber-eng", "state": "on", "text": "eng"}]}
|
|
181
|
+
```
|
|
177
182
|
|
|
178
183
|
It is a subprocess and not an import on purpose. The extension is the user's
|
|
179
184
|
repo, in whatever language, and may be slow or broken. A bounded child keeps a
|
|
@@ -229,10 +234,13 @@ python is asked (`hooks/tezgah_context.py::skill_read_kind`). A surface that can
|
|
|
229
234
|
was never opened", so it declares what it can see and those marks render `info`
|
|
230
235
|
(dim, no glyph) instead of `ready` (`observable`, `hooks/tezgah_context.py::health_segments`; the set constant
|
|
231
236
|
`TOOL_USE_MEASURES`, `hooks/tezgah_context.py::TOOL_USE_MEASURES`). The `--observable=` flag carries it on the CLI
|
|
232
|
-
(`bin/tezgah-status::main`).
|
|
233
|
-
|
|
234
|
-
`
|
|
235
|
-
|
|
237
|
+
(`bin/tezgah-status::main`). Every host whose line reads the store and cannot see
|
|
238
|
+
a skill read passes the tool-use set: the status line for Cursor, Qwen, Droid, Copilot and Antigravity
|
|
239
|
+
(`statusline.py::HOST`, `statusline.py::observable`), and Codex, Command Code
|
|
240
|
+
and Gemini, which render the line plain into `systemMessage`
|
|
241
|
+
(`hosts/codex/hook.py::main`, `hosts/commandcode/hook.py::status`,
|
|
242
|
+
`hosts/gemini/hook.py::status`); dsh passes the literal flag
|
|
243
|
+
string (`OBSERVABLE` in `hosts/dsh/statusline/lib/index.js`), which names the five marks its
|
|
236
244
|
own hook can record - `judge` included, since dsh wires the same PostToolUse hook
|
|
237
245
|
every other host does. The set is what a host can write, not what it happens to
|
|
238
246
|
have written: a mark the literal omits reads `info` there rather than a claim.
|
|
@@ -248,15 +256,15 @@ the five kinds are ever written (`hooks/tezgah_context.py::record`).
|
|
|
248
256
|
|
|
249
257
|
Writers: the shared PostToolUse hook `hooks/projects-posttooluse.py` — `graph` from
|
|
250
258
|
an MCP tool name, else the shell tokenizer's answer, which counts a tool only when
|
|
251
|
-
the command really ran it (
|
|
259
|
+
the command really ran it (`hooks/projects-posttooluse.py::used_kind`) and is the one writer that can earn `judge`
|
|
252
260
|
(a run of `bin/tezgah-triage` or `bin/tezgah-docs`, `shell_kind`, `hooks/tezgah_context.py::shell_kind`)
|
|
253
261
|
— plus `hooks/projects-auto-init.py::main`
|
|
254
262
|
(`orch` on subagent start), `hosts/codex/hook.py::main`,
|
|
255
|
-
`hosts/cursor/hook.py::dispatch`, hosts/opencode/plugins/tezgah.js
|
|
256
|
-
|
|
263
|
+
`hosts/cursor/hook.py::dispatch`, `record` in `hosts/opencode/plugins/tezgah.js`,
|
|
264
|
+
`hosts/omp/hook.py::handle`. Both Claude (hooks/hooks.json) and dsh
|
|
257
265
|
(hosts/dsh/hooks.json) wire PostToolUse to that one shared hook, which is how dsh
|
|
258
266
|
gets any used mark at all: with no local transcript, the store is the only channel
|
|
259
|
-
its line has (hooks/projects-posttooluse.py
|
|
267
|
+
its line has (`hooks/projects-posttooluse.py::used_kind`).
|
|
260
268
|
|
|
261
269
|
Claude's line never reads the store: it parses `tool_use` blocks out of
|
|
262
270
|
`payload["transcript_path"]` plus the subagent transcripts under it, which is how
|
|
@@ -269,15 +277,15 @@ Every other surface reads the store.
|
|
|
269
277
|
picks the host from `--cursor` or `TEZGAH_STATUS_HOST`, renders
|
|
270
278
|
`render_line(segs, color=color_default())`, and joins Orca's own status line to
|
|
271
279
|
the tezgah segment with ` | `; `TEZGAH_STATUS_LEGEND=1` appends the legend
|
|
272
|
-
(
|
|
280
|
+
(`statusline.py::HOST`, `statusline.py::seg`, `statusline.py::out`). ANSI is dropped under `NO_COLOR` or
|
|
273
281
|
`TEZGAH_STATUS_COLOR=0` (`color_default()`, `hooks/tezgah_context.py::color_default`).
|
|
274
282
|
- **omp** — hosts/omp/tezgah-hook.ts.in: `draw()` prefers
|
|
275
283
|
`ctx.ui.setWidget("tezgah", [line], {placement: "belowEditor"})`, which renders
|
|
276
284
|
the colored string as-is; `setStatus` is the fallback for a build without
|
|
277
|
-
`setWidget`, and it is plain because omp strips ANSI (
|
|
285
|
+
`setWidget`, and it is plain because omp strips ANSI (`draw` in `hosts/omp/tezgah-hook.ts.in`). `status_line()`
|
|
278
286
|
builds the line and carries `idx_override`, so a per-tool redraw forks no git
|
|
279
287
|
(`hosts/omp/hook.py::status_line`); it redraws on session start, session switch, turn end
|
|
280
|
-
and each watched tool result (hosts/omp/tezgah-hook.ts.in
|
|
288
|
+
and each watched tool result (`refresh` and `WATCHED` in `hosts/omp/tezgah-hook.ts.in`).
|
|
281
289
|
**Motion:** while the agent runs (`agent_start` until an `agent_end` whose
|
|
282
290
|
`isTerminal` is not `false`) the widget leads with a braille spinner, the tool
|
|
283
291
|
in flight (`tool_execution_start`/`_end`, "thinking" between tools) and the
|
|
@@ -297,20 +305,20 @@ Every other surface reads the store.
|
|
|
297
305
|
(`tui.json`'s `plugin` array, not the server plugin) registering an `app_bottom`
|
|
298
306
|
slot, shelling out to `tezgah-status <dir> --json <sessionID>`, coloring each
|
|
299
307
|
segment from the active theme and rebuilding the separator from `seg.group`
|
|
300
|
-
(
|
|
301
|
-
`--legend` (
|
|
308
|
+
(`TezgahBar` in `hosts/opencode/tui/tezgah-tui.tsx`). Its `tezgah: status legend` command opens a dialog running
|
|
309
|
+
`--legend` (`LegendDialog` in `hosts/opencode/tui/tezgah-tui.tsx`).
|
|
302
310
|
On opencode 2 the same line comes from hosts/opencode/tui/cli/tui.tsx, a
|
|
303
311
|
`Plugin.define` CLI plugin listed in `cli.json`. It reuses the v1 file's `run`.
|
|
304
312
|
- **dsh** — hosts/dsh/statusline/lib/index.js serves `GET /api/tezgah.status`
|
|
305
313
|
behind the Web UI's own authenticated fetch fence, so the browser fetches it
|
|
306
|
-
same-origin with no extra token handling (
|
|
307
|
-
`--observable=consult,research,graph,orch,judge` (
|
|
308
|
-
legend}` for `?format=json`, plain text otherwise (
|
|
314
|
+
same-origin with no extra token handling (`apply` in `hosts/dsh/statusline/lib/index.js`); it always passes
|
|
315
|
+
`--observable=consult,research,graph,orch,judge` (`OBSERVABLE` in `hosts/dsh/statusline/lib/index.js`) and returns `{segments,
|
|
316
|
+
legend}` for `?format=json`, plain text otherwise (`statusText` in `hosts/dsh/statusline/lib/index.js`). Its client half
|
|
309
317
|
(hosts/dsh/statusline/lib/client.js) renders the marks in the session header in
|
|
310
318
|
fixed light/dark colors, polls every 10 s while the tab is visible, and shows the
|
|
311
|
-
legend on hover, pins it on click (
|
|
319
|
+
legend on hover, pins it on click (`TezgahStatusLine` in `hosts/dsh/statusline/lib/client.js`).
|
|
312
320
|
- **Codex** — hosts/codex/hook.py puts the plain line in `systemMessage`
|
|
313
|
-
(
|
|
321
|
+
(`hosts/codex/hook.py::main`).
|
|
314
322
|
- **Amp** — the plugin draws the widest plain tier
|
|
315
323
|
(`hosts/amp/hook.py::status_line`) on Amp's experimental status item
|
|
316
324
|
(`createStatusItem`, TUI only, plain text). It draws only for the thread the
|
|
@@ -336,7 +344,8 @@ tezgah-status --judge # what the judge used last, and why
|
|
|
336
344
|
|
|
337
345
|
The session id is the second positional argument or `TEZGAH_SESSION`; without it
|
|
338
346
|
the used marks cannot light up (`bin/tezgah-status::main`). `--color`/`--no-color` force ANSI or plain,
|
|
339
|
-
`--observable=` narrows the measures as above, and an unknown flag exits 2
|
|
347
|
+
`--observable=` narrows the measures as above, and an unknown flag exits 2. So does
|
|
348
|
+
an `--observable=` measure outside `TOOL_USE_MEASURES` plus `pony` and `adhd` (`bin/tezgah-status::main`).
|
|
340
349
|
|
|
341
350
|
`--counters` is not the marks: it prints `tezgah_integrity.counters(session)` —
|
|
342
351
|
`steps`, `tool_error_rate`, `claims`, `false_completion`, `shape_blocked`,
|
|
@@ -413,7 +422,8 @@ could not be read - so the mark refuses to say either fresh or stale, and
|
|
|
413
422
|
`index_notice()` says on the turn that the graph's age is unknown. On a host that
|
|
414
423
|
sandboxes hook writes (dsh) the stamp is never written, and before that state
|
|
415
424
|
existed the mark read green there for good. That is why `observable` exists (`hooks/tezgah_context.py::health_segments`),
|
|
416
|
-
why the skill-read check is documented as unavailable on
|
|
425
|
+
why the skill-read check is documented as unavailable on every host that passes
|
|
426
|
+
the tool-use set or the dsh literal (see `--observable=` above)
|
|
417
427
|
(`hooks/tezgah_context.py::skill_read_kind`), why omp ignores any `idx` value that is not one of
|
|
418
428
|
its five glyphs (`hosts/omp/hook.py::status_line`) - a value outside that set re-probes
|
|
419
429
|
instead of being reused, one fork and never a wrong mark - and
|
package/docs/testing.md
CHANGED
|
@@ -47,7 +47,7 @@ baseline on the next run. Only `--clarity --update` raises it.
|
|
|
47
47
|
A pin is a claim about what ran, not a guarantee about what will. This repository
|
|
48
48
|
has two, and both are about the language rather than about dependencies: the
|
|
49
49
|
floor `py310` (`pyproject.toml:5`) and the CI matrix that proves it
|
|
50
|
-
(`.github/workflows/ci.yml
|
|
50
|
+
(the `test` job's `python-version` matrix in `.github/workflows/ci.yml`). There is no dependency lockfile to pin
|
|
51
51
|
because there is no package: tezgah is a set of scripts run in place, and no
|
|
52
52
|
`[project]` or build system is declared (`pyproject.toml:1-2`). The only
|
|
53
53
|
third-party tool the checks name is ruff, at a version in
|
|
@@ -65,10 +65,15 @@ conclude from either.
|
|
|
65
65
|
|
|
66
66
|
`.github/workflows/ci.yml` runs on a push to `main` and on a pull request, so
|
|
67
67
|
a branch commit runs once, through its pull request, not twice. A tag push does
|
|
68
|
-
not start it. `release.yml` calls it (`
|
|
68
|
+
not start it. `release.yml` calls it (its `workflow_call` trigger) as its `ci` job, so npm and
|
|
69
69
|
brew publish only after CI passed on the release commit. Its first job,
|
|
70
70
|
`on-main`, fails the release when the tag's commit is not on `origin/main`.
|
|
71
|
-
Then no job builds or uploads anything.
|
|
71
|
+
Then no job builds or uploads anything. Next, `green` looks for a finished push
|
|
72
|
+
run of `ci.yml` on the same commit. It waits for a running one and counts only
|
|
73
|
+
`success`, and then `ci` does not run: a release does not run the suite twice. No
|
|
74
|
+
such run, or any other outcome, runs `ci` as before. `npm-publish` and
|
|
75
|
+
`brew-formula` need `green` and `ci`, and publish when either answered green.
|
|
76
|
+
A newer push to the
|
|
72
77
|
same ref cancels the run it replaces, except on a release (`concurrency`). Every
|
|
73
78
|
job has a `timeout-minutes`, so a hung test cannot hold a runner for six hours.
|
|
74
79
|
No matrix cancels its other legs when one fails (`fail-fast: false`).
|
|
@@ -79,33 +84,58 @@ No matrix cancels its other legs when one fails (`fail-fast: false`).
|
|
|
79
84
|
empty diff, a base it cannot read, a release or a manual run runs everything.
|
|
80
85
|
- `docs`, prose only: the citations audit, the clarity audit and
|
|
81
86
|
`tests/impacted.py --ref <base>`, which maps a docs page to the docs modules.
|
|
82
|
-
- `test`
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
87
|
+
- `test` runs on Python 3.10 and 3.14, the floor and the ceiling. Its first steps
|
|
88
|
+
are "Byte-compile every script", "Install ruff" (from `requirements-dev.txt`,
|
|
89
|
+
pip cached) and "Lint". Then come "Every docs citation lands in the symbol it
|
|
90
|
+
names" and "The docs prose audit". The last two are "The plan and decision
|
|
91
|
+
rules, in a real project" (`TEZGAH_E2E_STRICT=1 python3 tests/e2e_plan_flow.py`)
|
|
92
|
+
and "The research checks against their known-truth set" (`python3
|
|
93
|
+
bin/tezgah-research release-check`). A release passes the `release` input and
|
|
94
|
+
runs one 3.10 leg.
|
|
95
|
+
- `test-sharded` on Python 3.10 and 3.14 with node 22 (the
|
|
88
96
|
first line that loads the omp `.ts` hook without a flag). On `main` and a
|
|
89
|
-
release
|
|
90
|
-
|
|
91
|
-
|
|
97
|
+
release its step "Run the suite, sharded" runs `python3 tests/impacted.py --all`.
|
|
98
|
+
On a pull request "Run the impacted modules, sharded (pull request)" runs
|
|
99
|
+
`--ref <base>` instead. That runs the modules the change maps to, or the whole
|
|
100
|
+
suite when the map does not know a path. It replaced the serial `unittest discover` step on
|
|
92
101
|
2026-10-13: both caught the same failures, and the serial step took about 30
|
|
93
102
|
minutes.
|
|
94
|
-
- `apps-e2e`
|
|
103
|
+
- `apps-e2e` on Python 3.12 and node 20: one step, "App MCP handshake
|
|
104
|
+
(playwright + mobile-mcp)",
|
|
95
105
|
`TEZGAH_E2E_STRICT=1 python3 tests/e2e_analyze_wiring.py`. It completes the
|
|
96
106
|
app-MCP handshake only - no browser, no device - so it stays deterministic;
|
|
97
107
|
strict mode makes a server that cannot start a failure rather than a skip, so
|
|
98
108
|
a broken wire cannot hide behind a skip (`e2e_analyze_wiring.py:4-12`).
|
|
99
|
-
- `artifact-install`
|
|
109
|
+
- `artifact-install` on Python 3.10 and 3.12: builds the
|
|
100
110
|
tarball, installs from it under a temp prefix, and runs the artifact smoke on
|
|
101
111
|
the installed tree instead of the checkout.
|
|
102
|
-
- `artifact-install-windows`
|
|
112
|
+
- `artifact-install-windows` on `windows-latest`: the same
|
|
103
113
|
build, install and smoke through `packaging/install.ps1` - the twin a Windows
|
|
104
114
|
user runs - so it is the only place the Windows claim is proven. It then runs
|
|
105
115
|
the opencode plugin's path tests natively, `tezgah update --dry-run`, the
|
|
106
116
|
opencode live probe and `--uninstall` from the installed tree. Any residue
|
|
107
117
|
under the prefix fails it.
|
|
108
118
|
|
|
119
|
+
Four node harnesses run JavaScript and TypeScript the suite cannot import. Their
|
|
120
|
+
Python modules drive them, so they run wherever those modules run: in
|
|
121
|
+
`test-sharded`, which installs node 22, and locally under `tests/impacted.py`.
|
|
122
|
+
|
|
123
|
+
- `tests/_opencode_plugin_harness.mjs` loads the opencode plugin
|
|
124
|
+
(`tests/test_opencode_plugin.py`).
|
|
125
|
+
- `tests/_omp_extension_harness.mjs` loads the omp extension
|
|
126
|
+
(`tests/test_omp_extension.py`) and `tests/_amp_plugin_harness.mjs` the Amp
|
|
127
|
+
plugin (`tests/test_amp_plugin.py`). Both need a node that strips types
|
|
128
|
+
(22.18+).
|
|
129
|
+
- `tests/_workflow_harness.mjs` is a stub of the Workflow runtime. It runs
|
|
130
|
+
`workflows/graph-review.js`, `workflows/graph-impact.js` and
|
|
131
|
+
`workflows/graph-map.js` as async function
|
|
132
|
+
bodies. It answers each `agent()` from a fixture, and `null` is a failed agent.
|
|
133
|
+
`python3 -m pytest tests/test_graph_workflows.py` runs it.
|
|
134
|
+
|
|
135
|
+
Without node, or with a node too old for `.ts`, these modules skip rather than
|
|
136
|
+
fail, so a leg with no node passes them silently. `test-sharded` is the leg
|
|
137
|
+
that proves them.
|
|
138
|
+
|
|
109
139
|
`.github/workflows/neuter.yml` runs two jobs weekly, on demand, and on a push to
|
|
110
140
|
`main` that changes a guard, the matrix or a test module it runs. The matrix is
|
|
111
141
|
CI's, not the local loop's. The first job, `neuter`, asks the question the suite
|
|
@@ -127,10 +157,11 @@ row.
|
|
|
127
157
|
Each mutant first runs alone the test that killed it last time, read from
|
|
128
158
|
`tests/neuter_killers.json`. When that test passes or is gone, the mutant runs
|
|
129
159
|
every module in its own HOME and TMPDIR. The module that reads the mutated file
|
|
130
|
-
goes first.
|
|
160
|
+
goes first. With `--update-killers`, the first failing test becomes its new
|
|
161
|
+
entry. Without it, the tracked cache is left as it was. The
|
|
131
162
|
control runs every module, then every cached killer alone, so a killer that
|
|
132
163
|
fails without a mutant voids the run. A session that adds a deny rule checks its
|
|
133
|
-
one mutant with `python3 tests/neuter_matrix.py --only <name
|
|
164
|
+
one mutant with `python3 tests/neuter_matrix.py --only <name> --update-killers`.
|
|
134
165
|
|
|
135
166
|
The second, `fuzz-shell`, runs the bash-oracle fuzzer (`tests/fuzz_shell.py`)
|
|
136
167
|
under the ubuntu runner's bash 5.x. Locally, macOS ships bash 3.2. A first step
|
package/docs/vision.md
CHANGED
|
@@ -117,8 +117,12 @@ conflicting SWE-bench split, the agent cheated in 0 of 132 runs with tezgah and
|
|
|
117
117
|
no headroom. Hand labels of final messages on those impossible tasks found
|
|
118
118
|
false done claims in 3 of 30 runs with tezgah and 6 of 30 without. The CI of
|
|
119
119
|
that difference includes 0. The Stop rule's claim reader
|
|
120
|
-
flagged far more runs than that. On Turkish replies it
|
|
121
|
-
(verified) on a partial fix as a claim,
|
|
120
|
+
flagged far more runs than that. On Turkish replies it counted `doğrulandı`
|
|
121
|
+
(verified) on a partial fix as a claim, even beside a `doğrulanmadı`. Commit
|
|
122
|
+
9cb4d1d fixed that shape. Its held-out recall is 0.857, below the 0.9 bar. A
|
|
123
|
+
narrower gap remains. A Turkish partial fix with no admission word
|
|
124
|
+
(`hâlâ başarısız`, `kısmen`) still reads as done and verified. Its English twin
|
|
125
|
+
reads as verification only. The
|
|
122
126
|
numbers, the per-task counts and the instrument flaws are in
|
|
123
127
|
[the results bundle](results/paired-outcome-2026-10.md).
|
|
124
128
|
|
package/hooks/lang/en.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "English",
|
|
3
3
|
"done": [
|
|
4
|
-
"done|complete[d]?|finished|implemented|fixed|shipped|landed|merged|wired up|wired into|all tests
|
|
4
|
+
"done|complete[d]?|finished|implemented|fixed|(?<!\\bis )(?<!\\bare )(?<!\\bget )(?<!\\bgets )(?<!\\bbe )(?<!\\bbeing )(?<!-)updated(?!-)|shipped|landed|merged|wired up|wired into|(?:all )?(?:tests?|checks?|suite|build) passed|(?:all )?(?:tests|checks) pass|(?:suite|build) passes|(?:tests?|checks?|suite) (?:is |are )?(?:green|passing)|build is green"
|
|
5
5
|
],
|
|
6
6
|
"verified": [
|
|
7
7
|
"tested|verified|i ran|ran the (?:tests?|suite|build|lint|checks?)"
|
|
8
8
|
],
|
|
9
9
|
"negated": [
|
|
10
|
-
"unverified|not verified|could ?n[o']t verify|verification (?:was )?skipped"
|
|
10
|
+
"unverified|not verified|could ?n[o']t verify|verification (?:was )?skipped|^\\s*(?:untested|not (?:yet )?(?:been )?(?:tested|checked))\\b|(?:^|[.!;]\\s+)(?:(?:this|the) (?:change|fix|patch)|it|i)\\b[^.\\n]{0,24}?(?:not|n't) (?:yet )?(?:been )?tested|not checked yet"
|
|
11
11
|
],
|
|
12
12
|
"admitted": [
|
|
13
13
|
"contradict|unsatisfiable|(?:can ?not|can't|can ?never|never) pass|impossible"
|
|
@@ -36,6 +36,9 @@
|
|
|
36
36
|
"negation_before": [
|
|
37
37
|
"\\bnot|n't|\\bnever"
|
|
38
38
|
],
|
|
39
|
+
"condition_before": [
|
|
40
|
+
"\\b(?:if|when|once|unless|until|whether)\\b"
|
|
41
|
+
],
|
|
39
42
|
"question_particle": [],
|
|
40
43
|
"question_end": [],
|
|
41
44
|
"clause_join": [
|
package/hooks/lang/tr.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "Turkish",
|
|
3
3
|
"done": [
|
|
4
|
-
"yaptım|tamamladım|tamamlandı|bitirdim|bitirildi|ekledim|eklendi|düzelttim|düzeltildi|hallettim|güncellendi|kuruldu|uygulandı|yayına girdi|kapatıldı|yüklendi|tüm testler geçti|testler geçti|testler yeşil|çalışıyor"
|
|
4
|
+
"yaptım|tamamladım|tamamlandı|bitirdim|bitirildi|ekledim|eklendi|düzelttim|düzeltildi|hallettim|güncellendi|kuruldu|uygulandı|yayına girdi|kapatıldı|yüklendi|tüm testler geçti|testler geçti|testler geçiyor|testler yeşil|çalışıyor"
|
|
5
5
|
],
|
|
6
6
|
"verified": [
|
|
7
7
|
"doğruladım|test ettim|kontrol ettim|denetledim|doğrulandı|test edildi"
|
|
@@ -89,6 +89,7 @@
|
|
|
89
89
|
"negation_before": [
|
|
90
90
|
"\\bdeğil"
|
|
91
91
|
],
|
|
92
|
+
"condition_before": [],
|
|
92
93
|
"question_particle": [
|
|
93
94
|
"m[ıiuü]|değil"
|
|
94
95
|
],
|
|
@@ -200,7 +201,7 @@
|
|
|
200
201
|
"ürün(?!\\w*_)\\w*|yol harita\\w*|kuzey yıldız\\w*|aktivasyon\\w*|dönüşüm\\w*|fiyatlandır\\w*|önceliklendir\\w*|kullanıcı araştırma\\w*|ürün keşf\\w*|müşteri geri bildirim\\w*|benimsen\\w*|konumlandır\\w*|segmentasyon\\w*|hedef kitle\\w*|(kullanıcı|müşteri) discovery|keşif (görüşme|çalışma)\\w*|fırsat\\w*|memnuniyet\\w*|anket\\w*|(kullanıcı|müşteri)[ -]?(feedback|geri bildirim)\\w*|(customer|user)[ -]?geri bildirim\\w*|şikayet\\w*|rakip\\w*|rekabet\\w*|pazar pay\\w*|terk oran\\w*|elde tutma\\w*|abonelik\\w*|gelir model\\w*|özellik\\w*|sayfa(?! numara)\\w*|ekran(?! kart)(?!a\\b[^.!?\\n]{0,40}\\b(?:yaz|bas)\\w*)\\w*|arayüz\\w*|arama kutu\\w*|filtre\\w*|tablo(?![^.!?\\n]{0,60}\\b(?:sütun|kolon|sql|index|indeks)\\w*)\\w*|adım(?! sayı)\\w*|kullanıcı liste\\w*|form(u|un|da|daki|lar|ları|unu)\\w*[^.!?\\n]{0,40}\\b(?:incele|denetle|analiz|de[ğg]erlendir|iyile[şs]tir|sadele[şs]tir|kontrol)\\w*"
|
|
201
202
|
],
|
|
202
203
|
"design": [
|
|
203
|
-
"(?:(?<![\\w'’] )|(?<=\\bbu )|(?<=\\bşu ))tasar[ıi]m\\w*|(?:dashboard|pano|g[öo]sterge panel|ekran|sayfa|aray[üu]z|landing|logo|ikon)\\w* (?:\\w+ ){0,2}(?:tasarla|tasar[ıi]m|redesign)\\w*|(?:web[ -]?)?site\\w* tasar[ıi]m\\w*|(?:mobil |web )?uygulama\\w* tasar[ıi]m\\w*|(?:web|mobil) tasar[ıi]m\\w*|tasar[ıi]m (?:sistem|token|dil|rehber)\\w*|yeniden tasarla\\w*|ba[şs]tan tasarla\\w*|design [çc]al[ıi][şs]ma\\w*|aray[üu]z\\w*|(?:ui|aray[üu]z|form|buton|d[üu][ğg]me|kart|men[üu]|sayfa|ekran|react|vue)\\w* (?:\\w+ )?bile[şs]en\\w*|bile[şs]en (?:k[üu]t[üu]phane|sistem)\\w*|tipografi\\w*|renk\\w*|tema(?:s[ıi]|y[ıi]|lar\\w*)?|kullan[ıi]labilirlik\\w*|eri[şs]ilebilirli[kğg]\\w*|g[öo]rsel (?:hiyerar[şs]i|tutarl[ıi]l[ıi]k|denetim|ele[şs]tiri)\\w*",
|
|
204
|
+
"(?:(?<![\\w'’] )|(?<=\\bbu )|(?<=\\bşu ))tasar[ıi]m\\w*|(?:dashboard|pano|g[öo]sterge panel|ekran|sayfa|aray[üu]z|landing|logo|ikon)\\w* (?:\\w+ ){0,2}(?:tasarla|tasar[ıi]m|redesign)\\w*|(?:uygulama(?:y[ıi]|s[ıi]n[ıi])?|site(?:yi|sini)?) redesign\\w*|(?:web[ -]?)?site\\w* tasar[ıi]m\\w*|(?:mobil |web )?uygulama\\w* tasar[ıi]m\\w*|(?:web|mobil) tasar[ıi]m\\w*|tasar[ıi]m (?:sistem|token|dil|rehber)\\w*|yeniden tasarla\\w*|ba[şs]tan tasarla\\w*|design [çc]al[ıi][şs]ma\\w*|aray[üu]z\\w*|(?:ui|aray[üu]z|form|buton|d[üu][ğg]me|kart|men[üu]|sayfa|ekran|react|vue)\\w* (?:\\w+ )?bile[şs]en\\w*|bile[şs]en (?:k[üu]t[üu]phane|sistem)\\w*|tipografi\\w*|renk\\w*|tema(?:s[ıi]|y[ıi]|lar\\w*)?|kullan[ıi]labilirlik\\w*|eri[şs]ilebilirli[kğg]\\w*|g[öo]rsel (?:hiyerar[şs]i|tutarl[ıi]l[ıi]k|denetim|ele[şs]tiri)\\w*",
|
|
204
205
|
{
|
|
205
206
|
"ui_ask": "iyile[şs]tir\\w*|g[üu]zelle[şs]tir\\w*|d[üu]zenle\\w*|kar[ıi][şs][ıi]k\\w*|tutars[ıi]z\\w*|da[ğg][ıi]n[ıi]k\\w*|[çc]irkin\\w*"
|
|
206
207
|
},
|
|
@@ -69,11 +69,19 @@ def result_size(result):
|
|
|
69
69
|
so a container is measured by its top-level length (O(1) for str, bytes,
|
|
70
70
|
list, dict, set) instead of re-serializing it: `json.dumps` on every
|
|
71
71
|
PostToolUse copied the whole tool response and broke the hook's cost bound
|
|
72
|
-
("a sha1 over a short string and a few fields; nothing else").
|
|
73
|
-
|
|
74
|
-
|
|
72
|
+
("a sha1 over a short string and a few fields; nothing else"). A shell
|
|
73
|
+
result is the exception: Claude's Bash answers `{"stdout", "stderr",
|
|
74
|
+
"interrupted", ...}`, so its field count is never 0 and a check that
|
|
75
|
+
printed nothing would read as output (`passing_check`'s silent failure,
|
|
76
|
+
B-005); its stream strings (`ran_nothing`'s keys) are measured instead.
|
|
77
|
+
ponytail: any other dict reports its field count, not its byte length."""
|
|
75
78
|
if result is None:
|
|
76
79
|
return None
|
|
80
|
+
if isinstance(result, dict):
|
|
81
|
+
streams = [result[k] for k in ("stdout", "stderr", "output")
|
|
82
|
+
if isinstance(result.get(k), str)]
|
|
83
|
+
if streams:
|
|
84
|
+
return sum(map(len, streams))
|
|
77
85
|
if isinstance(result, (str, bytes, bytearray, list, tuple, dict, set,
|
|
78
86
|
frozenset)):
|
|
79
87
|
return len(result)
|
package/hooks/projects-stop.py
CHANGED
|
@@ -48,7 +48,7 @@ def main():
|
|
|
48
48
|
if not isinstance(p, dict):
|
|
49
49
|
return
|
|
50
50
|
session_id = p.get("session_id")
|
|
51
|
-
safe(session_id, bind_session, session_id) # the switch latch
|
|
51
|
+
safe(session_id, bind_session, session_id, p.get("parent")) # the switch latch
|
|
52
52
|
cwd = p.get("cwd") or os.getcwd()
|
|
53
53
|
if p.get("hook_event_name") == "SubagentStop" and p.get("agent_id") \
|
|
54
54
|
and root_for(cwd) and not off("slices-off"):
|
package/hooks/tezgah_context.py
CHANGED
|
@@ -335,9 +335,10 @@ def skill_read_kind(tool, inp):
|
|
|
335
335
|
|
|
336
336
|
Only the hosts that can see a read without paying a process per read call
|
|
337
337
|
this (Claude parses its transcript, opencode classifies in-process, omp's
|
|
338
|
-
embedded runner filters before it asks python). On codex,
|
|
339
|
-
|
|
340
|
-
state and the
|
|
338
|
+
embedded runner filters before it asks python). On codex, commandcode,
|
|
339
|
+
gemini, cursor, qwen, droid, copilot, antigravity and dsh a read is not
|
|
340
|
+
observable at that price, so those marks stay at their armed state and the
|
|
341
|
+
legend says so.
|
|
341
342
|
|
|
342
343
|
A read of one of the two marked skills earns its mark (`SKILL_MARKS`); a read
|
|
343
344
|
of any OTHER shipped skill earns `skill:<name>`. That second kind lights
|
|
@@ -2095,7 +2096,8 @@ def context_for(event, cwd, payload=None, with_core=True):
|
|
|
2095
2096
|
# The switch latch: every off() below answers for this session, and a
|
|
2096
2097
|
# prompt's turn marker (with its `authorized` row) is written first, so a
|
|
2097
2098
|
# switch the user's prompt names is honored from this very turn.
|
|
2098
|
-
bind_session(session_of(payload)
|
|
2099
|
+
bind_session(session_of(payload),
|
|
2100
|
+
payload.get("parent") if isinstance(payload, dict) else None)
|
|
2099
2101
|
if event == "user_prompt":
|
|
2100
2102
|
# One marker per user turn, written before the reminder check: the loop
|
|
2101
2103
|
# guard counts an identical call's failures in the current turn only, so
|
|
@@ -2103,13 +2105,16 @@ def context_for(event, cwd, payload=None, with_core=True):
|
|
|
2103
2105
|
# guard state rather than part of the reminder. Only a hash of the prompt
|
|
2104
2106
|
# is stored - note_turn keys the row on it so one submission cannot write
|
|
2105
2107
|
# two markers and hide the failures the guard had just counted.
|
|
2106
|
-
note_turn(session_of(payload), prompt_text(payload), workspace=root_for(cwd)
|
|
2108
|
+
note_turn(session_of(payload), prompt_text(payload), workspace=root_for(cwd),
|
|
2109
|
+
subagent=isinstance(payload, dict) and bool(payload.get("subagent")))
|
|
2107
2110
|
core, disabled = core_for(cwd)
|
|
2108
2111
|
# A disabled rule is also removed from the on-demand skill's reach, because
|
|
2109
2112
|
# the skill is loaded separately and would otherwise re-enable it.
|
|
2113
|
+
# Claude's `tezgah` output style is a static copy of the core that no switch
|
|
2114
|
+
# re-renders, so the note names it beside the skill (OQ-12).
|
|
2110
2115
|
off_note = ("Kill switches active this session: %s. Those rules are OFF; "
|
|
2111
|
-
"ignore the matching section in the `tezgah-contract` skill
|
|
2112
|
-
% ", ".join(disabled)) if disabled else ""
|
|
2116
|
+
"ignore the matching section in the `tezgah-contract` skill and "
|
|
2117
|
+
"the `tezgah` output style." % ", ".join(disabled)) if disabled else ""
|
|
2113
2118
|
if event == "user_prompt":
|
|
2114
2119
|
prompt = prompt_text(payload)
|
|
2115
2120
|
session_id = session_of(payload)
|
|
@@ -2118,24 +2123,24 @@ def context_for(event, cwd, payload=None, with_core=True):
|
|
|
2118
2123
|
host = (payload or {}).get("host") if isinstance(payload, dict) else None
|
|
2119
2124
|
tezgah_taste.note_prompt(session_id, prompt, cwd,
|
|
2120
2125
|
host=host if isinstance(host, str) else None)
|
|
2121
|
-
#
|
|
2122
|
-
#
|
|
2123
|
-
#
|
|
2126
|
+
# The gate notice: never in DROP_ORDER, so no budget gives it up, and
|
|
2127
|
+
# `reminder-off` keeps it - it says the rules below are not being
|
|
2128
|
+
# enforced. Reading it also writes the status mark.
|
|
2124
2129
|
gate = gate_inactive(session_id, payload)
|
|
2125
|
-
# The user's grants and lifts (`user_grants`)
|
|
2126
|
-
#
|
|
2127
|
-
#
|
|
2128
|
-
# user's grant (omp's bridge sends `subagent`).
|
|
2130
|
+
# The user's grants and lifts (`user_grants`): the Stop rule reads them
|
|
2131
|
+
# whatever this turn's text shows. A subagent's prompt is its parent's
|
|
2132
|
+
# brief, never the user's grant (omp's bridge sends `subagent`).
|
|
2129
2133
|
for clause, target in ([] if isinstance(payload, dict) and payload.get("subagent")
|
|
2130
2134
|
else user_grants(prompt)):
|
|
2131
2135
|
note(session_id, GRANT_KIND, clause, target=target)
|
|
2132
2136
|
# per-turn nudge: openers decay over long sessions. Kept short because
|
|
2133
2137
|
# it is paid every turn, and on Claude the output style already carries
|
|
2134
2138
|
# the same rules on every response. The conditional rules ride along
|
|
2135
|
-
# only on the turn whose prompt matches their task class.
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
parts = [("reminder"
|
|
2139
|
+
# only on the turn whose prompt matches their task class. `reminder-off`
|
|
2140
|
+
# mutes this one line: every other part has its own switch or none
|
|
2141
|
+
# (OQ-10), and the gate notice must never be given up.
|
|
2142
|
+
parts = ([] if off("reminder-off") else
|
|
2143
|
+
[("reminder", render(prompt_reminder(dropped_switches(cwd))))])
|
|
2139
2144
|
if gate:
|
|
2140
2145
|
parts.append(("gate", gate))
|
|
2141
2146
|
# The previous turn's stamp, read before the armed paragraphs: they are
|
|
@@ -2258,8 +2263,8 @@ def context_for(event, cwd, payload=None, with_core=True):
|
|
|
2258
2263
|
if stale:
|
|
2259
2264
|
parts.append(("index", stale))
|
|
2260
2265
|
if disabled:
|
|
2261
|
-
parts.append(("offnote", "(off this session: %s
|
|
2262
|
-
% ", ".join(disabled)))
|
|
2266
|
+
parts.append(("offnote", "(off this session: %s; ignore their sections "
|
|
2267
|
+
"in the `tezgah` output style)" % ", ".join(disabled)))
|
|
2263
2268
|
text = budgeted(event, parts)
|
|
2264
2269
|
# latched only when the budget kept it, so a dropped line comes back
|
|
2265
2270
|
if heavy and heavy in text:
|
|
@@ -2625,7 +2630,18 @@ def shell_kind(command):
|
|
|
2625
2630
|
could light from `orx` alone and the layer's own commands stayed invisible to
|
|
2626
2631
|
it. The absolute spelling needs no case of its own - this reader keeps
|
|
2627
2632
|
basenames, so `<bin>/tezgah-research` and the bare name arrive as the same
|
|
2628
|
-
word.
|
|
2633
|
+
word.
|
|
2634
|
+
|
|
2635
|
+
A python or node interpreter given a script file (`python3 bin/tezgah-docs
|
|
2636
|
+
q`) runs that script, so the interpreter word is dropped before the line is
|
|
2637
|
+
read; `-c`, `-m` and `-` (stdin) keep it, as their next word is code or a
|
|
2638
|
+
module, not a file. The match stays on one line (spaces and tabs only), and a
|
|
2639
|
+
shell interpreter needs none of this: the wrapper reader already looks past
|
|
2640
|
+
`bash`/`sh`. `shell_programs` itself stays as it is: the gate reads it and
|
|
2641
|
+
must keep the interpreter."""
|
|
2642
|
+
command = re.sub(r"(?<![\w/.$=-])(?:[\w./-]*/)?(?:python[\d.]*|node)"
|
|
2643
|
+
r"(?:[ \t]+-(?![cm]\b)\w[\w-]*)*[ \t]+(?=[^\s-])", "",
|
|
2644
|
+
str(command or ""))
|
|
2629
2645
|
ran = shell_programs(command)
|
|
2630
2646
|
if "consult" in ran:
|
|
2631
2647
|
return "consult"
|
|
@@ -2930,8 +2946,9 @@ colored, and the glyph carries the state on its own where color does not):
|
|
|
2930
2946
|
name\u25cb yellow armed, on demand - not used yet this session
|
|
2931
2947
|
name\u2717 red turned off by a kill switch or a per-repo .no-* mark
|
|
2932
2948
|
pony, adhd, dim this surface cannot report that measure (a skill read
|
|
2933
|
-
needs a process per read to observe on codex,
|
|
2934
|
-
|
|
2949
|
+
needs a process per read to observe on codex, commandcode,
|
|
2950
|
+
gemini, cursor, qwen, droid, copilot, antigravity and dsh,
|
|
2951
|
+
so those two marks state nothing there instead of
|
|
2935
2952
|
claiming the skill was never opened)
|
|
2936
2953
|
dim no state to report: idx n/a or uncomparable, or no blocked
|
|
2937
2954
|
plan
|