@junghanacs/entwurf 0.21.0 → 0.23.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/AGENTS.md +3 -2
- package/BASELINE.md +3 -1
- package/CHANGELOG.md +658 -0
- package/DELIVERY.md +167 -29
- package/README.md +104 -14
- package/VERIFY.md +73 -11
- package/docs/external-mcp-host.md +16 -6
- package/docs/setup-clean-host.md +73 -22
- package/mcp/entwurf-bridge/dist/mcp/entwurf-bridge/src/index.js +54 -31
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/codex-caller-seat.js +174 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/codex-declaration.js +609 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/codex-fresh-preflight.js +289 -57
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-control-rpc.js +40 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-fact-provider.js +6 -2
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-facts.js +7 -1
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-peer-observe.js +67 -2
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-peers-render.js +9 -1
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-self-address.js +24 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-runner.js +3 -2
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-send.js +8 -4
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/fresh-call-composition.js +423 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/fresh-call-dispatch.js +98 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/herdr-fresh-call.js +1018 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/herdr-placement.js +213 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/mux-fresh-call.js +171 -263
- package/mcp/entwurf-bridge/dist/scripts/codex-socket-path.js +30 -0
- package/mcp/entwurf-bridge/dist/scripts/peer-facts.js +109 -0
- package/mcp/entwurf-bridge/src/index.ts +65 -31
- package/mcp/entwurf-bridge/tsconfig.build.json +10 -0
- package/package.json +4 -4
- package/pi-extensions/entwurf-control.ts +91 -52
- package/pi-extensions/lib/codex-caller-seat.ts +204 -0
- package/pi-extensions/lib/codex-declaration.js +612 -0
- package/pi-extensions/lib/codex-fresh-preflight.ts +325 -52
- package/pi-extensions/lib/entwurf-control-rpc.ts +46 -0
- package/pi-extensions/lib/entwurf-fact-provider.ts +13 -2
- package/pi-extensions/lib/entwurf-facts.ts +14 -1
- package/pi-extensions/lib/entwurf-peer-observe.ts +72 -2
- package/pi-extensions/lib/entwurf-peers-render.ts +9 -1
- package/pi-extensions/lib/entwurf-self-address.ts +33 -0
- package/pi-extensions/lib/entwurf-v2-runner.ts +3 -2
- package/pi-extensions/lib/entwurf-v2-send.ts +16 -11
- package/pi-extensions/lib/fresh-call-composition.ts +493 -0
- package/pi-extensions/lib/fresh-call-dispatch.ts +142 -0
- package/pi-extensions/lib/herdr-fresh-call.ts +1378 -0
- package/pi-extensions/lib/herdr-placement.ts +276 -0
- package/pi-extensions/lib/mux-fresh-call.ts +257 -304
- package/run.sh +522 -10
- package/scripts/check-codex-app-server-launch.ts +445 -0
- package/scripts/check-codex-birth-hook.ts +187 -0
- package/scripts/check-entwurf-control-rpc.ts +138 -0
- package/scripts/check-entwurf-fact-provider.ts +4 -2
- package/scripts/check-entwurf-facts.ts +12 -6
- package/scripts/check-entwurf-peers-surface.ts +3 -1
- package/scripts/check-entwurf-self-address.ts +68 -0
- package/scripts/check-entwurf-v2-production.ts +42 -1
- package/scripts/check-entwurf-v2-send.ts +26 -7
- package/scripts/check-fresh-call-dispatch.ts +301 -0
- package/scripts/check-gate-qualification.ts +19 -5
- package/scripts/check-herdr-activation.ts +1293 -0
- package/scripts/check-herdr-fresh-call.ts +1250 -0
- package/scripts/check-herdr-placement.ts +383 -0
- package/scripts/check-herdr-plugin-build.ts +842 -0
- package/scripts/check-herdr-plugin-profile.ts +371 -0
- package/scripts/check-herdr-plugin.ts +523 -0
- package/scripts/check-herdr-runtime-bootstrap.ts +1264 -0
- package/scripts/check-herdr-sandbox.ts +456 -0
- package/scripts/check-herdr-supply.ts +184 -0
- package/scripts/check-mux-launch-tmux.ts +331 -35
- package/scripts/check-mux-launcher-fence.ts +138 -0
- package/scripts/check-peer-facts.ts +331 -0
- package/scripts/check-release-gate-outcomes.ts +12 -0
- package/scripts/check-typing-call-fence.ts +296 -0
- package/scripts/codex-app-server-launch.sh +275 -0
- package/scripts/codex-birth-doctor.sh +159 -16
- package/scripts/codex-birth-install.sh +178 -72
- package/scripts/codex-birth-uninstall.sh +162 -7
- package/scripts/codex-socket-path.ts +33 -0
- package/scripts/codex-terminal-title-config.py +500 -0
- package/scripts/codex_toml_io.py +121 -0
- package/scripts/fixtures/herdr-supply.json +29 -0
- package/scripts/herdr-activation.mjs +536 -0
- package/scripts/herdr-plugin-activate.mjs +270 -0
- package/scripts/herdr-plugin-deactivate.mjs +193 -0
- package/scripts/herdr-runtime.mjs +1203 -0
- package/scripts/install-herdr-ci.sh +96 -0
- package/scripts/lib/codex-fresh-live-protocol.ts +13 -5
- package/scripts/lib/codex-fresh-source-receipts.ts +29 -2
- package/scripts/lib/tree-digest.ts +97 -0
- package/scripts/meta-bridge-install.sh +19 -2
- package/scripts/meta-bridge-state.py +167 -11
- package/scripts/mutants/codex-app-server-launch.json +157 -0
- package/scripts/mutants/codex-caller-seat.json +334 -0
- package/scripts/mutants/codex-native.json +195 -29
- package/scripts/mutants/control-socket-disconnect.json +57 -0
- package/scripts/mutants/fresh-call-dispatch.json +154 -0
- package/scripts/mutants/herdr-activation.json +305 -0
- package/scripts/mutants/herdr-fresh-call.json +448 -0
- package/scripts/mutants/herdr-placement.json +161 -0
- package/scripts/mutants/herdr-plugin-build.json +160 -0
- package/scripts/mutants/herdr-plugin-profile.json +202 -0
- package/scripts/mutants/herdr-plugin.json +133 -0
- package/scripts/mutants/herdr-runtime-bootstrap.json +411 -0
- package/scripts/mutants/herdr-supply.json +133 -0
- package/scripts/mutants/meta-hook-session-switch.json +2 -2
- package/scripts/mutants/mux-fresh-call.json +184 -25
- package/scripts/mutants/mux-launcher-fence.json +13 -0
- package/scripts/mutants/omp-fresh.json +4 -4
- package/scripts/mutants/peer-facts.json +98 -0
- package/scripts/mutants/self-address.json +33 -0
- package/scripts/mutants/typing-call-fence.json +17 -0
- package/scripts/mutants/v2-surface.json +22 -0
- package/scripts/peer-facts.ts +120 -0
- package/scripts/register-pi-package.py +8 -0
- package/scripts/register-pi-provider.py +88 -12
- package/scripts/smoke-codex-birth.sh +281 -12
- package/scripts/smoke-codex-config-state.sh +192 -3
- package/scripts/smoke-codex-fresh-live.ts +277 -37
- package/scripts/smoke-entwurf-chain-live.ts +50 -0
- package/scripts/smoke-herdr-fresh-call-live.ts +1027 -0
- package/scripts/smoke-herdr-plugin-build-live.ts +543 -0
- package/scripts/smoke-setup-verdict.sh +13 -11
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
# smoke-codex-config-state — hermetic install/doctor/inverse contract for the
|
|
3
|
-
#
|
|
3
|
+
# three Codex config atoms (codex-mcp-config.py + codex-statusline-config.py +
|
|
4
|
+
# codex-terminal-title-config.py).
|
|
4
5
|
# No Codex process, no model turn: the vendor's config.toml surface only.
|
|
5
6
|
set -euo pipefail
|
|
6
7
|
|
|
7
8
|
REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
8
9
|
MCP="$REPO_DIR/scripts/codex-mcp-config.py"
|
|
9
10
|
SL="$REPO_DIR/scripts/codex-statusline-config.py"
|
|
11
|
+
TT="$REPO_DIR/scripts/codex-terminal-title-config.py"
|
|
10
12
|
pass=0
|
|
11
13
|
ok() { printf ' ok %s\n' "$1"; pass=$((pass + 1)); }
|
|
12
14
|
die() { printf 'FAIL: %s\n' "$1" >&2; exit 1; }
|
|
@@ -39,6 +41,7 @@ mkdir -p "$CODEX_HOME" "$(dirname "$XDG_DATA_HOME")"
|
|
|
39
41
|
CFG="$CODEX_HOME/config.toml"
|
|
40
42
|
MCP_STATE="$XDG_DATA_HOME/entwurf/codex-mcp/install-state.json"
|
|
41
43
|
SL_STATE="$XDG_DATA_HOME/entwurf/codex-statusline/install-state.json"
|
|
44
|
+
TT_STATE="$XDG_DATA_HOME/entwurf/codex-terminal-title/install-state.json"
|
|
42
45
|
|
|
43
46
|
seed_config() { # the operator's hand-edited file: quoted header keys, nested
|
|
44
47
|
# tables, an unrelated MCP server, and NO entwurf atom content.
|
|
@@ -464,6 +467,189 @@ sed -i 's/^status_line = .*/status_line = [\n "weather",\n "thread-title",\n]/
|
|
|
464
467
|
refuses "restructured list refuses blind take-back" "changed since install" python3 "$SL" uninstall "$SL_STATE"
|
|
465
468
|
rm -f "$SL_STATE"
|
|
466
469
|
|
|
470
|
+
|
|
471
|
+
###############################################################################
|
|
472
|
+
# Atom 3 — [tui].terminal_title includes thread-id (#95 lane B caller seat)
|
|
473
|
+
#
|
|
474
|
+
# Same writer shape as atom 2 and a DIFFERENT contract in two places, both of
|
|
475
|
+
# which have a wrong answer that still parses: the seeded list must LEAD with
|
|
476
|
+
# `activity` (the herdr Codex detector keys on the spinner/action-required
|
|
477
|
+
# prefix), and an existing operator list is APPENDED to, never prepended — a
|
|
478
|
+
# prepend would put thread-id ahead of an activity the operator already
|
|
479
|
+
# configured. The append position is the third: a trailing comma, a trailing
|
|
480
|
+
# comment or a `]` inside a string item each send a naive `rfind("]")` at the
|
|
481
|
+
# wrong bytes, and one of those emits `,,`.
|
|
482
|
+
###############################################################################
|
|
483
|
+
|
|
484
|
+
# seeded from nothing: the herdr-safe order, verbatim
|
|
485
|
+
rm -f "$CFG" "$TT_STATE"
|
|
486
|
+
python3 "$TT" install "$CFG" "$TT_STATE" >"$SB/out"
|
|
487
|
+
want "[QK:CODEX-TT-SEED-ACTIVITY-FIRST] seeded terminal_title leads with activity, ends with thread-id" \
|
|
488
|
+
"grep -q '^created-new ' '$SB/out' && grep -q '^terminal_title = \[\"activity\", \"project-name\", \"thread-id\"\]$' '$CFG'"
|
|
489
|
+
python3 "$TT" doctor-static "$CFG" "$TT_STATE" >"$SB/out"
|
|
490
|
+
want "seeded terminal-title doctor is green and owned" "grep -q '^thread-id-present owned$' '$SB/out'"
|
|
491
|
+
python3 "$TT" uninstall "$TT_STATE" >"$SB/out"
|
|
492
|
+
want "seeded file is removed whole by the inverse" "[ ! -e '$CFG' ] && [ ! -e '$TT_STATE' ]"
|
|
493
|
+
|
|
494
|
+
# an operator list is APPENDED to — the direction that is opposite to atom 2
|
|
495
|
+
seed_config
|
|
496
|
+
sed -i '/^theme = /i terminal_title = ["activity", "project-name"]' "$CFG"
|
|
497
|
+
cp "$CFG" "$SB/tt-seed.toml"
|
|
498
|
+
python3 "$TT" install "$CFG" "$TT_STATE" >"$SB/out"
|
|
499
|
+
want "[QK:CODEX-TT-APPENDS-AT-END] thread-id is appended LAST, operator order untouched" \
|
|
500
|
+
"grep -q '^merged-item ' '$SB/out' && grep -q '^terminal_title = \[\"activity\", \"project-name\", \"thread-id\"\]$' '$CFG'"
|
|
501
|
+
toml_ok "$CFG"; ok "merged terminal_title still parses"
|
|
502
|
+
MT1="$(stat -c %Y "$CFG")"; sleep 1.1
|
|
503
|
+
python3 "$TT" install "$CFG" "$TT_STATE" >/dev/null
|
|
504
|
+
want "terminal-title reinstall writes nothing" "[ '$MT1' = '$(stat -c %Y "$CFG")' ]"
|
|
505
|
+
python3 "$TT" uninstall "$TT_STATE" >/dev/null
|
|
506
|
+
cmp -s "$SB/tt-seed.toml" "$CFG" && ok "appended item restored byte-exact" || die "terminal-title inverse mismatch"
|
|
507
|
+
|
|
508
|
+
# an activity-TERMINATED operator list: the item still lands after it
|
|
509
|
+
seed_config
|
|
510
|
+
sed -i '/^theme = /i terminal_title = ["project-name", "activity"]' "$CFG"
|
|
511
|
+
python3 "$TT" install "$CFG" "$TT_STATE" >/dev/null
|
|
512
|
+
want "an activity-terminated list keeps activity in place and appends after it" \
|
|
513
|
+
"grep -q '^terminal_title = \[\"project-name\", \"activity\", \"thread-id\"\]$' '$CFG'"
|
|
514
|
+
python3 "$TT" uninstall "$TT_STATE" >/dev/null
|
|
515
|
+
|
|
516
|
+
# multi-line array with a TRAILING COMMA — the shape a naive append breaks
|
|
517
|
+
seed_config
|
|
518
|
+
python3 - "$CFG" <<'PY'
|
|
519
|
+
import sys
|
|
520
|
+
p = sys.argv[1]
|
|
521
|
+
t = open(p).read()
|
|
522
|
+
t = t.replace('theme = "zenburn"',
|
|
523
|
+
'terminal_title = [\n "activity", # operator note\n "project-name",\n]\ntheme = "zenburn"')
|
|
524
|
+
open(p, 'w').write(t)
|
|
525
|
+
PY
|
|
526
|
+
cp "$CFG" "$SB/tt-multiline.toml"
|
|
527
|
+
python3 "$TT" install "$CFG" "$TT_STATE" >/dev/null
|
|
528
|
+
toml_ok "$CFG"
|
|
529
|
+
want "[QK:CODEX-TT-TRAILING-COMMA] a trailing-comma array is appended to without emitting a double comma" \
|
|
530
|
+
"! grep -q ',[[:space:]]*,' '$CFG' && python3 -c \"import tomllib,sys; d=tomllib.load(open(sys.argv[1],'rb')); assert d['tui']['terminal_title']==['activity','project-name','thread-id'], d\" '$CFG'"
|
|
531
|
+
python3 "$TT" uninstall "$TT_STATE" >/dev/null
|
|
532
|
+
cmp -s "$SB/tt-multiline.toml" "$CFG" && ok "trailing-comma array restored byte-exact" || die "trailing-comma inverse mismatch"
|
|
533
|
+
|
|
534
|
+
# a trailing COMMENT that itself contains `]` — rfind("]") would splice into it
|
|
535
|
+
seed_config
|
|
536
|
+
sed -i '/^theme = /i terminal_title = ["activity"] # keep ] this' "$CFG"
|
|
537
|
+
cp "$CFG" "$SB/tt-comment.toml"
|
|
538
|
+
python3 "$TT" install "$CFG" "$TT_STATE" >/dev/null
|
|
539
|
+
want "[QK:CODEX-TT-COMMENT-NOT-SPLICED] the item lands inside the array and the operator's comment survives" \
|
|
540
|
+
"grep -q '^terminal_title = \[\"activity\", \"thread-id\"\] # keep \] this$' '$CFG'"
|
|
541
|
+
python3 "$TT" uninstall "$TT_STATE" >/dev/null
|
|
542
|
+
cmp -s "$SB/tt-comment.toml" "$CFG" && ok "commented line restored byte-exact" || die "comment inverse mismatch"
|
|
543
|
+
|
|
544
|
+
# a `]` inside a string item, and the empty list
|
|
545
|
+
seed_config
|
|
546
|
+
sed -i '/^theme = /i terminal_title = ["a]b", "activity"]' "$CFG"
|
|
547
|
+
python3 "$TT" install "$CFG" "$TT_STATE" >/dev/null
|
|
548
|
+
want "a ] inside a string item does not become the append point" \
|
|
549
|
+
"grep -q '^terminal_title = \[\"a\]b\", \"activity\", \"thread-id\"\]$' '$CFG'"
|
|
550
|
+
python3 "$TT" uninstall "$TT_STATE" >/dev/null
|
|
551
|
+
seed_config
|
|
552
|
+
sed -i '/^theme = /i terminal_title = []' "$CFG"
|
|
553
|
+
cp "$CFG" "$SB/tt-empty.toml"
|
|
554
|
+
python3 "$TT" install "$CFG" "$TT_STATE" >/dev/null
|
|
555
|
+
want "empty terminal_title becomes exactly [\"thread-id\"]" "grep -q '^terminal_title = \[\"thread-id\"\]$' '$CFG'"
|
|
556
|
+
python3 "$TT" uninstall "$TT_STATE" >/dev/null
|
|
557
|
+
cmp -s "$SB/tt-empty.toml" "$CFG" && ok "empty terminal_title restored byte-exact" || die "empty terminal_title inverse mismatch"
|
|
558
|
+
|
|
559
|
+
# an operator-authored item is UNOWNED, and nothing is written over it
|
|
560
|
+
seed_config
|
|
561
|
+
sed -i '/^theme = /i terminal_title = ["activity", "thread-id"]' "$CFG"
|
|
562
|
+
cp "$CFG" "$SB/tt-operator.toml"
|
|
563
|
+
rm -f "$TT_STATE"
|
|
564
|
+
MT1="$(stat -c %Y "$CFG")"; sleep 1.1
|
|
565
|
+
python3 "$TT" install "$CFG" "$TT_STATE" >"$SB/out"
|
|
566
|
+
want "[QK:CODEX-TT-OPERATOR-ITEM-UNOWNED] an operator-authored thread-id writes NO receipt and no config byte" \
|
|
567
|
+
"grep -q '^already-present ' '$SB/out' && [ ! -e '$TT_STATE' ] && [ '$MT1' = '$(stat -c %Y "$CFG")' ]"
|
|
568
|
+
python3 "$TT" doctor-static "$CFG" "$TT_STATE" >"$SB/out"
|
|
569
|
+
want "the doctor reports it UNOWNED — we claim no edit we did not make" \
|
|
570
|
+
"grep -q '^thread-id-present unowned$' '$SB/out'"
|
|
571
|
+
python3 "$TT" uninstall "$TT_STATE" >"$SB/out" 2>&1 \
|
|
572
|
+
&& die "uninstall claimed to take back an operator's own item"
|
|
573
|
+
grep -q 'nothing to undo' "$SB/out" || die "unowned uninstall refusal is unnamed: $(cat "$SB/out")"
|
|
574
|
+
cmp -s "$SB/tt-operator.toml" "$CFG" && ok "the refused inverse left the operator's config byte-identical" \
|
|
575
|
+
|| die "unowned uninstall mutated the operator's config"
|
|
576
|
+
|
|
577
|
+
# ...and that is what keeps the INVERSE honest across a hand edit. With a receipt parked over an
|
|
578
|
+
# operator's item, a reinstall after they removed it splices ours in while the stale receipt still
|
|
579
|
+
# says it was already there — and the inverse then reports "nothing to take back" and leaves our
|
|
580
|
+
# bytes behind for good. Writing nothing above makes that second install an ordinary merged-item.
|
|
581
|
+
seed_config
|
|
582
|
+
sed -i '/^theme = /i terminal_title = ["activity"]' "$CFG"
|
|
583
|
+
cp "$CFG" "$SB/tt-inverse.toml"
|
|
584
|
+
rm -f "$TT_STATE"
|
|
585
|
+
python3 "$TT" install "$CFG" "$TT_STATE" >/dev/null
|
|
586
|
+
sed -i 's/, "thread-id"\]/]/' "$CFG" # the operator takes our item back by hand
|
|
587
|
+
python3 "$TT" install "$CFG" "$TT_STATE" >"$SB/out"
|
|
588
|
+
want "a reinstall after a hand removal records what it ACTUALLY did" \
|
|
589
|
+
"grep -q '^merged-item ' '$SB/out' && grep -q '\"detectMode\": \"merged-item\"' '$TT_STATE'"
|
|
590
|
+
python3 "$TT" uninstall "$TT_STATE" >/dev/null
|
|
591
|
+
cmp -s "$SB/tt-inverse.toml" "$CFG" && ok "the inverse takes our re-added item back, leaving nothing behind" \
|
|
592
|
+
|| { printf 'left behind:\n%s\n' "$(cat "$CFG")"; die "reinstall inverse left our item in the operator's config"; }
|
|
593
|
+
rm -f "$TT_STATE"
|
|
594
|
+
|
|
595
|
+
# the doctor's subject is the REQUIRED caller-seat axis, receipt or no receipt
|
|
596
|
+
seed_config
|
|
597
|
+
sed -i '/^theme = /i terminal_title = ["activity", "thread-id"]' "$CFG"
|
|
598
|
+
rm -f "$TT_STATE"
|
|
599
|
+
python3 "$TT" doctor-static "$CFG" "$TT_STATE" >"$SB/out"
|
|
600
|
+
want "unowned thread-id is green (state-independent)" "grep -q '^thread-id-present unowned$' '$SB/out'"
|
|
601
|
+
sed -i 's/, "thread-id"\]/]/' "$CFG"
|
|
602
|
+
python3 "$TT" doctor-static "$CFG" "$TT_STATE" >"$SB/out" 2>&1 \
|
|
603
|
+
&& die "[QK:CODEX-TT-DOCTOR-REQUIRES-SEAT-AXIS] unowned config WITHOUT thread-id reported green: $(cat "$SB/out")"
|
|
604
|
+
want "[QK:CODEX-TT-DOCTOR-REQUIRES-SEAT-AXIS] a missing caller-seat axis is RED even unowned" \
|
|
605
|
+
"grep -q '^thread-id-absent unowned$' '$SB/out'"
|
|
606
|
+
python3 "$TT" install "$CFG" "$TT_STATE" >/dev/null
|
|
607
|
+
sed -i 's/, "thread-id"\]/]/' "$CFG"
|
|
608
|
+
python3 "$TT" doctor-static "$CFG" "$TT_STATE" >"$SB/out" 2>&1 || true
|
|
609
|
+
want "our receipt over a vanished item reports drift, not green" "grep -q '^thread-id-absent owned drift$' '$SB/out'"
|
|
610
|
+
rm -f "$TT_STATE"
|
|
611
|
+
|
|
612
|
+
# the two [tui] atoms are independent: neither sees the other's key
|
|
613
|
+
seed_config
|
|
614
|
+
python3 "$SL" install "$CFG" "$SL_STATE" >/dev/null
|
|
615
|
+
python3 "$TT" install "$CFG" "$TT_STATE" >/dev/null
|
|
616
|
+
want "[QK:CODEX-TT-ATOM-INDEPENDENCE] both [tui] atoms live side by side" \
|
|
617
|
+
"python3 -c \"import tomllib,sys; d=tomllib.load(open(sys.argv[1],'rb'))['tui']; assert d['status_line']==['thread-title','model-with-reasoning','current-dir'], d; assert d['terminal_title']==['activity','project-name','thread-id'], d\" '$CFG'"
|
|
618
|
+
python3 "$TT" uninstall "$TT_STATE" >/dev/null
|
|
619
|
+
want "[QK:CODEX-TT-ATOM-INDEPENDENCE] taking back terminal_title leaves status_line exactly as it was" \
|
|
620
|
+
"grep -q '^status_line = \[\"thread-title\", \"model-with-reasoning\", \"current-dir\"\]$' '$CFG' && ! grep -q 'terminal_title' '$CFG'"
|
|
621
|
+
python3 "$SL" uninstall "$SL_STATE" >/dev/null
|
|
622
|
+
|
|
623
|
+
# refusals — symlink, malformed, contrary value by name, foreign/retargeted state
|
|
624
|
+
seed_config
|
|
625
|
+
ln -sf "$SB/foreign.toml" "$CFG"
|
|
626
|
+
refuses "symlink config refused (terminal-title)" "symlink" python3 "$TT" install "$CFG" "$TT_STATE"
|
|
627
|
+
rm -f "$CFG"
|
|
628
|
+
printf 'garbage [[[\n' > "$CFG"
|
|
629
|
+
refuses "malformed TOML refused (terminal-title)" "not valid TOML" python3 "$TT" install "$CFG" "$TT_STATE"
|
|
630
|
+
seed_config
|
|
631
|
+
sed -i '/^theme = /i terminal_title = "thread-id"' "$CFG"
|
|
632
|
+
refuses "non-array terminal_title refused BY NAME" "terminal_title.*explicitly" python3 "$TT" install "$CFG" "$TT_STATE"
|
|
633
|
+
want "terminal-title refusals wrote no state" "[ ! -e '$TT_STATE' ]"
|
|
634
|
+
seed_config
|
|
635
|
+
python3 "$SL" install "$CFG" "$SL_STATE" >/dev/null
|
|
636
|
+
cp "$SL_STATE" "$TT_STATE" # atom 2's receipt, on our path
|
|
637
|
+
refuses "foreign-atom state refused (terminal-title)" "belongs to atom" python3 "$TT" install "$CFG" "$TT_STATE"
|
|
638
|
+
python3 "$SL" uninstall "$SL_STATE" >/dev/null
|
|
639
|
+
rm -f "$TT_STATE"
|
|
640
|
+
seed_config
|
|
641
|
+
python3 "$TT" install "$CFG" "$TT_STATE" >/dev/null
|
|
642
|
+
sed -i "s|$(json_field "$TT_STATE" managedConfigPath)|$SB/elsewhere.toml|" "$TT_STATE"
|
|
643
|
+
refuses "retargeted state refused (terminal-title)" "refusing to retarget" python3 "$TT" install "$CFG" "$TT_STATE"
|
|
644
|
+
rm -f "$TT_STATE"
|
|
645
|
+
|
|
646
|
+
# operator restructures the list after install: the take-back refuses, by name
|
|
647
|
+
seed_config
|
|
648
|
+
python3 "$TT" install "$CFG" "$TT_STATE" >/dev/null
|
|
649
|
+
sed -i 's/^terminal_title = .*/terminal_title = [\n "weather",\n "thread-id",\n]/' "$CFG"
|
|
650
|
+
refuses "restructured terminal_title refuses blind take-back" "changed since install" python3 "$TT" uninstall "$TT_STATE"
|
|
651
|
+
rm -f "$TT_STATE"
|
|
652
|
+
|
|
467
653
|
###############################################################################
|
|
468
654
|
# Unrelated operator config survives the whole cycle, byte for byte
|
|
469
655
|
###############################################################################
|
|
@@ -471,6 +657,7 @@ seed_config
|
|
|
471
657
|
cp "$CFG" "$SB/final-seed.toml"
|
|
472
658
|
python3 "$MCP" install "$CFG" entwurf-bridge "$MCP_STATE" >/dev/null
|
|
473
659
|
python3 "$SL" install "$CFG" "$SL_STATE" >/dev/null
|
|
660
|
+
python3 "$TT" install "$CFG" "$TT_STATE" >/dev/null
|
|
474
661
|
toml_ok "$CFG"; ok "fully installed config parses as TOML"
|
|
475
662
|
python3 - "$CFG" <<'PY'
|
|
476
663
|
import tomllib, sys
|
|
@@ -494,17 +681,19 @@ assert d["mcp_servers"]["entwurf-bridge"] == {
|
|
|
494
681
|
"env": {"ENTWURF_BRIDGE_NATIVE_HOST": "codex"},
|
|
495
682
|
}, d
|
|
496
683
|
assert d["tui"]["status_line"] == ["thread-title", "model-with-reasoning", "current-dir"], d
|
|
684
|
+
assert d["tui"]["terminal_title"] == ["activity", "project-name", "thread-id"], d
|
|
497
685
|
assert d["tui"]["theme"] == "zenburn" and d["tui"]["model_availability_nux"] == {"gpt-5.5": 4}, d
|
|
498
686
|
assert d["plugins"]["github@openai-curated"] == {"enabled": False}, d
|
|
499
687
|
PY
|
|
500
|
-
ok "unrelated tables intact and
|
|
688
|
+
ok "unrelated tables intact and all three atoms semantically live"
|
|
501
689
|
# the vendor writes trust state back between install and uninstall (M1)
|
|
502
690
|
printf '[hooks.state."~/c.toml:stop:0:0"]\ntrusted_hash = "sha256:def"\n' >> "$CFG"
|
|
503
691
|
python3 "$MCP" uninstall "$MCP_STATE" >/dev/null
|
|
504
692
|
python3 "$SL" uninstall "$SL_STATE" >/dev/null
|
|
693
|
+
python3 "$TT" uninstall "$TT_STATE" >/dev/null
|
|
505
694
|
printf '[hooks.state."~/c.toml:stop:0:0"]\ntrusted_hash = "sha256:def"\n' >> "$SB/final-seed.toml"
|
|
506
695
|
cmp -s "$SB/final-seed.toml" "$CFG" && ok "full cycle leaves only vendor-added bytes (unrelated config survives)" || die "final byte mismatch"
|
|
507
|
-
want "
|
|
696
|
+
want "all three states cleared" "[ ! -e '$MCP_STATE' ] && [ ! -e '$SL_STATE' ] && [ ! -e '$TT_STATE' ]"
|
|
508
697
|
|
|
509
698
|
REPO_AFTER="$(cd "$REPO_DIR" && git status --porcelain)"
|
|
510
699
|
[ "$REPO_BEFORE" = "$REPO_AFTER" ] || die "smoke changed the checkout"
|