@junghanacs/entwurf 0.12.2 → 0.12.4
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 +2 -2
- package/CHANGELOG.md +39 -0
- package/README.md +9 -5
- package/VERIFY.md +4 -4
- package/demo/README.md +5 -5
- package/demo/demo-baseline.sh +2 -2
- package/demo/demo.sh +3 -3
- package/docs/setup-clean-host.md +27 -10
- package/mcp/entwurf-bridge/dist/scripts/meta-bridge-store-doctor.js +55 -0
- package/mcp/entwurf-bridge/tsconfig.build.json +14 -6
- package/package.json +9 -9
- package/pi/entwurf-targets.json +3 -6
- package/pi-extensions/lib/acp/acp-client.ts +2 -2
- package/pi-extensions/lib/acp/models.ts +7 -9
- package/run.sh +74 -21
- package/scripts/check-acp-backend-preflight.ts +1 -1
- package/scripts/check-acp-config.ts +3 -3
- package/scripts/check-acp-event-mapper.ts +1 -1
- package/scripts/check-acp-provider-surface.ts +1 -1
- package/scripts/check-acp-sdk-surface.ts +22 -22
- package/scripts/check-acp-session-reuse.ts +3 -3
- package/scripts/check-acp-session-store.ts +6 -6
- package/scripts/check-acp-tool-surface.ts +2 -2
- package/scripts/check-entwurf-session-identity.ts +9 -9
- package/scripts/check-model-lock.ts +2 -2
- package/scripts/check-package-source-routing.ts +4 -4
- package/scripts/meta-bridge-doctor.sh +55 -10
- package/scripts/meta-bridge-state.py +2 -0
- package/scripts/resolve-acp-bridge.ts +1 -1
- package/scripts/smoke-acp-bundled-mcp-live.ts +1 -1
- package/scripts/smoke-acp-carrier-augment-live.ts +1 -1
- package/scripts/smoke-acp-mcp-live.ts +1 -1
- package/scripts/smoke-acp-memory-containment-live.ts +8 -9
- package/scripts/smoke-acp-overlay-live.ts +8 -9
- package/scripts/smoke-acp-provider-live.ts +1 -1
- package/scripts/smoke-acp-raw-turn-live.ts +12 -11
- package/scripts/smoke-acp-session-reuse-live.ts +24 -9
- package/scripts/smoke-acp-skill-live.ts +1 -1
- package/scripts/smoke-meta-install-state.sh +3 -3
package/run.sh
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
#
|
|
3
3
|
# Model id convention (see AGENTS.md Hard Rule #1):
|
|
4
4
|
# - User-facing examples use the qualified form `entwurf/<backend-model>`
|
|
5
|
-
# (e.g. `entwurf/claude-sonnet-
|
|
5
|
+
# (e.g. `entwurf/claude-sonnet-5`); the prefix routes to this provider
|
|
6
6
|
# so `--provider` is redundant and is dropped in docs.
|
|
7
7
|
# - Smoke helpers that feed `ensureBridgeSession({modelId})` directly (cancel,
|
|
8
|
-
# model-switch) pass BARE backend ids (`claude-sonnet-
|
|
8
|
+
# model-switch) pass BARE backend ids (`claude-sonnet-5`, `gpt-5.4`)
|
|
9
9
|
# because the bridge library contract is bare. Smoke helpers that invoke pi
|
|
10
10
|
# via the CLI still pin `--provider entwurf` and can accept either
|
|
11
11
|
# bare or qualified model, but we keep bare here to match the bridge-level
|
|
@@ -32,7 +32,7 @@ TARGET_PROJECT_DIR=${2:-$PROJECT_DIR_DEFAULT}
|
|
|
32
32
|
# and install path against the same scope for traceability.
|
|
33
33
|
PACKAGE_NAME="@junghanacs/entwurf"
|
|
34
34
|
# Runtime provider id — DO NOT change. Embedded in model strings
|
|
35
|
-
# (`entwurf/claude-sonnet-
|
|
35
|
+
# (`entwurf/claude-sonnet-5`), settings keys (`entwurfProvider`),
|
|
36
36
|
# log prefixes (`[entwurf:bootstrap]`), and the `--provider entwurf`
|
|
37
37
|
# CLI surface. Renaming this would break every consumer transcript and every
|
|
38
38
|
# saved session anchor.
|
|
@@ -908,7 +908,7 @@ smoke_acp_raw_turn_live() {
|
|
|
908
908
|
# plus captured raw NDJSON bytes. NO provider/overlay/streamSimple/_meta — the
|
|
909
909
|
# raw backend pipe only. Launch source must be the package bin (PATH fallback
|
|
910
910
|
# fails acceptance unless ENTWURF_ACP_RAW_TURN_ALLOW_PATH_FALLBACK=1, debug).
|
|
911
|
-
# Model override: ENTWURF_ACP_RAW_TURN_MODEL (default claude-sonnet-
|
|
911
|
+
# Model override: ENTWURF_ACP_RAW_TURN_MODEL (default claude-sonnet-5).
|
|
912
912
|
# LIVE=1 ./run.sh smoke-acp-raw-turn-live
|
|
913
913
|
(cd "$REPO_DIR" && node --experimental-strip-types scripts/smoke-acp-raw-turn-live.ts)
|
|
914
914
|
}
|
|
@@ -926,7 +926,7 @@ smoke_acp_overlay_live() {
|
|
|
926
926
|
# meta-store for mailbox absence (flaky — concurrent sessions); the honest
|
|
927
927
|
# claim is overlay-supplies-hooks:{}. Launch must be the package bin (PATH
|
|
928
928
|
# fallback fails acceptance unless ENTWURF_ACP_OVERLAY_ALLOW_PATH_FALLBACK=1).
|
|
929
|
-
# Model override: ENTWURF_ACP_OVERLAY_MODEL (default claude-sonnet-
|
|
929
|
+
# Model override: ENTWURF_ACP_OVERLAY_MODEL (default claude-sonnet-5).
|
|
930
930
|
# LIVE=1 ./run.sh smoke-acp-overlay-live
|
|
931
931
|
(cd "$REPO_DIR" && node --experimental-strip-types scripts/smoke-acp-overlay-live.ts)
|
|
932
932
|
}
|
|
@@ -941,7 +941,7 @@ smoke_acp_memory_containment_live() {
|
|
|
941
941
|
# can stop a memory write is the lever — not us. Fails loud if engraving.md is
|
|
942
942
|
# empty (carrier OFF = no containment). Launch must be the package bin (PATH
|
|
943
943
|
# fallback fails acceptance unless ENTWURF_ACP_MEMORY_ALLOW_PATH_FALLBACK=1).
|
|
944
|
-
# Model override: ENTWURF_ACP_MEMORY_MODEL (default claude-sonnet-
|
|
944
|
+
# Model override: ENTWURF_ACP_MEMORY_MODEL (default claude-sonnet-5).
|
|
945
945
|
# LIVE=1 ./run.sh smoke-acp-memory-containment-live
|
|
946
946
|
(cd "$REPO_DIR" && node --experimental-strip-types scripts/smoke-acp-memory-containment-live.ts)
|
|
947
947
|
}
|
|
@@ -956,7 +956,7 @@ smoke_acp_provider_live() {
|
|
|
956
956
|
# assistant reply (live model proof) + the removed S0 stub error never appears
|
|
957
957
|
# (provider path actually opened) + pi exits 0. Tool-free prompt; the
|
|
958
958
|
# event-mapper gate owns the tool→notice contract.
|
|
959
|
-
# Model override: ENTWURF_ACP_PROVIDER_MODEL (default claude-sonnet-
|
|
959
|
+
# Model override: ENTWURF_ACP_PROVIDER_MODEL (default claude-sonnet-5).
|
|
960
960
|
# LIVE=1 ./run.sh smoke-acp-provider-live
|
|
961
961
|
(cd "$REPO_DIR" && node --experimental-strip-types scripts/smoke-acp-provider-live.ts)
|
|
962
962
|
}
|
|
@@ -970,7 +970,7 @@ smoke_acp_session_reuse_live() {
|
|
|
970
970
|
# was reused and the live ACP session kept turn-1 history (a respawn-per-turn
|
|
971
971
|
# backend would forget it). The one-shot exit0 half is owned by
|
|
972
972
|
# smoke-acp-provider-live.
|
|
973
|
-
# Model override: ENTWURF_ACP_PROVIDER_MODEL (default claude-sonnet-
|
|
973
|
+
# Model override: ENTWURF_ACP_PROVIDER_MODEL (default claude-sonnet-5).
|
|
974
974
|
# LIVE=1 ./run.sh smoke-acp-session-reuse-live
|
|
975
975
|
(cd "$REPO_DIR" && node --experimental-strip-types scripts/smoke-acp-session-reuse-live.ts)
|
|
976
976
|
}
|
|
@@ -982,7 +982,7 @@ smoke_acp_carrier_augment_live() {
|
|
|
982
982
|
# secret (the augment rode the wire to the model) and the EMPTY default carrier
|
|
983
983
|
# must bill clean (exit 0, no HTTP-400 canary — 핀1 live). Optional tiny carrier
|
|
984
984
|
# check via SMOKE_ACP_CARRIER_PRESENT=1 (non-blocking).
|
|
985
|
-
# Model override: ENTWURF_ACP_PROVIDER_MODEL (default claude-sonnet-
|
|
985
|
+
# Model override: ENTWURF_ACP_PROVIDER_MODEL (default claude-sonnet-5).
|
|
986
986
|
# LIVE=1 ./run.sh smoke-acp-carrier-augment-live
|
|
987
987
|
(cd "$REPO_DIR" && node --experimental-strip-types scripts/smoke-acp-carrier-augment-live.ts)
|
|
988
988
|
}
|
|
@@ -1040,9 +1040,9 @@ smoke_acp_rgg_live() {
|
|
|
1040
1040
|
# surface (plugin stays lightweight, no ambient MCP — S2b/S2d boundary). To
|
|
1041
1041
|
# observe that boundary directly, run the shared runner with SMOKE_RGG_POSITIVE=1
|
|
1042
1042
|
# and ENTWURF_LIVE_TARGET set (T3 will report N/A, not a real failure).
|
|
1043
|
-
# Target override: ENTWURF_RGG_TARGET (default entwurf/claude-sonnet-
|
|
1043
|
+
# Target override: ENTWURF_RGG_TARGET (default entwurf/claude-sonnet-5).
|
|
1044
1044
|
# ./run.sh smoke-acp-rgg-live
|
|
1045
|
-
local target="${ENTWURF_RGG_TARGET:-entwurf/claude-sonnet-
|
|
1045
|
+
local target="${ENTWURF_RGG_TARGET:-entwurf/claude-sonnet-5}"
|
|
1046
1046
|
(cd "$REPO_DIR" && ENTWURF_LIVE_TARGET="$target" SMOKE_RGG_POSITIVE=0 bash scripts/smoke-resident-garden-guard.sh)
|
|
1047
1047
|
}
|
|
1048
1048
|
|
|
@@ -1280,7 +1280,7 @@ assert.equal(peerTui, piAi,
|
|
|
1280
1280
|
// pi moves its public surface every minor (the 0.79→0.80 getModels→provider-
|
|
1281
1281
|
// factory churn is exactly this), so an open `>=` floor is exactly how the next
|
|
1282
1282
|
// installer re-acquires the drift. Expected
|
|
1283
|
-
// shape: `>=<devDep> <0.<minor+1>` (e.g. `>=0.80.
|
|
1283
|
+
// shape: `>=<devDep> <0.<minor+1>` (e.g. `>=0.80.3 <0.81`).
|
|
1284
1284
|
const [piMaj, piMin] = piAi.split('.').map(Number);
|
|
1285
1285
|
assert.equal(piMaj, 0,
|
|
1286
1286
|
`pi pin major must stay 0 for the next-minor ceiling rule (got ${piAi}); revisit check-dep-versions when pi reaches 1.x`);
|
|
@@ -1375,7 +1375,7 @@ check_pi_runtime_version() {
|
|
|
1375
1375
|
# never statically import a floor-only symbol here, or this guard would crash
|
|
1376
1376
|
# before it can fail loud.
|
|
1377
1377
|
(cd "$REPO_DIR" && node --input-type=module <<'EOF'
|
|
1378
|
-
const FLOOR = '0.80.
|
|
1378
|
+
const FLOOR = '0.80.3';
|
|
1379
1379
|
const cmp = (a, b) => {
|
|
1380
1380
|
const pa = a.split('.').map(Number), pb = b.split('.').map(Number);
|
|
1381
1381
|
for (let i = 0; i < 3; i++) { if ((pa[i] || 0) !== (pb[i] || 0)) return (pa[i] || 0) - (pb[i] || 0); }
|
|
@@ -1393,7 +1393,7 @@ if (typeof VERSION !== 'string') {
|
|
|
1393
1393
|
process.exit(1);
|
|
1394
1394
|
}
|
|
1395
1395
|
if (cmp(VERSION, FLOOR) < 0) {
|
|
1396
|
-
console.error(`[check-pi-runtime-version] FAIL: pi VERSION ${VERSION} < ${FLOOR} — the bridge is built and tested against the 0.80.
|
|
1396
|
+
console.error(`[check-pi-runtime-version] FAIL: pi VERSION ${VERSION} < ${FLOOR} — the bridge is built and tested against the 0.80.3 public/runtime surface (trust exports hasTrustRequiringProjectResources + ProjectTrustStore nearest-ancestor get, the 0.80 model-catalog API getModels reached via the deprecated /compat entrypoint — 0.80 moved the standalone root getModels there, and the extension loader resolves only /compat, NOT the providers/* factory subpath — provider registration surface, compaction semantics) that older pi lacks or behaves differently on. Bump @earendil-works/pi-*.`);
|
|
1397
1397
|
process.exit(1);
|
|
1398
1398
|
}
|
|
1399
1399
|
console.log(`[check-pi-runtime-version] ok — pi VERSION ${VERSION} >= ${FLOOR}`);
|
|
@@ -1536,8 +1536,8 @@ check_acp_provider_surface() {
|
|
|
1536
1536
|
|
|
1537
1537
|
check_acp_sdk_surface() {
|
|
1538
1538
|
# Deterministic gate for the S2a ACP SDK dependency surface. Pins the three
|
|
1539
|
-
# ACP runtime deps to the
|
|
1540
|
-
#
|
|
1539
|
+
# ACP runtime deps to the current oracle versions (@agentclientprotocol/sdk
|
|
1540
|
+
# 1.1.0 + claude-agent-acp 0.54.1 + @anthropic-ai/sdk 0.100.1), locks the
|
|
1541
1541
|
# peer-resolution that keeps claude-agent-sdk satisfiable (0.100.1, not the
|
|
1542
1542
|
# stale 0.91.1), asserts the wire SDK still value-exports the symbols the raw
|
|
1543
1543
|
# turn needs (silent-rename gate), and forbids any source-level anthropic SDK
|
|
@@ -1731,6 +1731,10 @@ check_pack() {
|
|
|
1731
1731
|
# this dist JS when present (the .ts source can't strip-types under
|
|
1732
1732
|
# node_modules). prepack runs on `npm pack --dry-run`, so it is in this gate.
|
|
1733
1733
|
"mcp/entwurf-bridge/dist/mcp/entwurf-bridge/src/index.js"
|
|
1734
|
+
# 0.12.4 — the doctor's node_modules-safe store-scan artifact. meta-bridge-
|
|
1735
|
+
# doctor.sh runs this prebuilt JS when installed under node_modules (strip-types
|
|
1736
|
+
# refuses the .ts there), same boundary start.sh crosses. build-bridge emits it.
|
|
1737
|
+
"mcp/entwurf-bridge/dist/scripts/meta-bridge-store-doctor.js"
|
|
1734
1738
|
"scripts/postinstall-chmod.cjs"
|
|
1735
1739
|
"pi/entwurf-capabilities.json"
|
|
1736
1740
|
"pi/entwurf-targets.json"
|
|
@@ -1880,6 +1884,9 @@ check_pack_install() {
|
|
|
1880
1884
|
"mcp/entwurf-bridge/src/index.ts"
|
|
1881
1885
|
# 0.12.1 C — prepack-built node_modules-safe boot artifact (see check-pack).
|
|
1882
1886
|
"mcp/entwurf-bridge/dist/mcp/entwurf-bridge/src/index.js"
|
|
1887
|
+
# 0.12.4 — prebuilt node_modules-safe store-scan artifact for the doctor
|
|
1888
|
+
# (see check-pack). The installed-scan smoke below runs exactly this file.
|
|
1889
|
+
"mcp/entwurf-bridge/dist/scripts/meta-bridge-store-doctor.js"
|
|
1883
1890
|
"scripts/postinstall-chmod.cjs"
|
|
1884
1891
|
"pi/entwurf-capabilities.json"
|
|
1885
1892
|
"pi/entwurf-targets.json"
|
|
@@ -1946,9 +1953,9 @@ check_pack_install() {
|
|
|
1946
1953
|
local install_log
|
|
1947
1954
|
install_log=$(cd "$tmp" && pnpm add \
|
|
1948
1955
|
"$tgz_path" \
|
|
1949
|
-
"@earendil-works/pi-ai@0.80.
|
|
1950
|
-
"@earendil-works/pi-coding-agent@0.80.
|
|
1951
|
-
"@earendil-works/pi-tui@0.80.
|
|
1956
|
+
"@earendil-works/pi-ai@0.80.3" \
|
|
1957
|
+
"@earendil-works/pi-coding-agent@0.80.3" \
|
|
1958
|
+
"@earendil-works/pi-tui@0.80.3" \
|
|
1952
1959
|
"typebox@latest" \
|
|
1953
1960
|
--ignore-workspace --ignore-scripts 2>&1) || {
|
|
1954
1961
|
fail "[check-pack-install] pnpm add failed:"
|
|
@@ -2000,14 +2007,14 @@ check_pack_install() {
|
|
|
2000
2007
|
# opus anchor (CURATED_ANCHOR_MODEL_ID in lib/acp/models.ts — the model whose
|
|
2001
2008
|
# absence is a hard registry regression). Checking only one would let half the
|
|
2002
2009
|
# surface drop silently.
|
|
2003
|
-
for anchor in "claude-sonnet-
|
|
2010
|
+
for anchor in "claude-sonnet-5" "claude-opus-4-8"; do
|
|
2004
2011
|
if ! grep -q "$anchor" <<<"$loader_out"; then
|
|
2005
2012
|
fail "[check-pack-install] pi loader output missing curated Claude model $anchor:"
|
|
2006
2013
|
echo "$loader_out" | tail -10 | sed 's/^/ /' >&2
|
|
2007
2014
|
return 1
|
|
2008
2015
|
fi
|
|
2009
2016
|
done
|
|
2010
|
-
echo "[check-pack-install] pi loader smoke pass (entwurf registered, claude-sonnet-
|
|
2017
|
+
echo "[check-pack-install] pi loader smoke pass (entwurf registered, claude-sonnet-5 + claude-opus-4-8 anchor)"
|
|
2011
2018
|
|
|
2012
2019
|
# npm-managed neutral install regression — the README's PRIMARY install path is
|
|
2013
2020
|
# now `npm install @junghanacs/entwurf` (NOT `pi install npm:...`). This layout
|
|
@@ -2127,6 +2134,52 @@ JS
|
|
|
2127
2134
|
fi
|
|
2128
2135
|
echo "[check-pack-install] installed bridge boot pass (dist boots under node_modules, pi-free: $boot_out)"
|
|
2129
2136
|
|
|
2137
|
+
# 0.12.4 — installed STORE-DOCTOR regression. meta-bridge-doctor.sh's full store
|
|
2138
|
+
# scan runs the prebuilt dist JS when it lives under node_modules (strip-types
|
|
2139
|
+
# refuses the .ts there — the same class as the bridge boot above). Before the dist
|
|
2140
|
+
# split the doctor ran the raw .ts and reported a FALSE "corrupt records" FAIL on
|
|
2141
|
+
# EVERY installed host. Prove the shipped dist JS scans a fixture store with PLAIN
|
|
2142
|
+
# node (a strip-types fallback would crash with the exact
|
|
2143
|
+
# ERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING) AND that its rewritten import of the
|
|
2144
|
+
# emitted meta-session.js resolves — a real record exercises parseMetaIdentity.
|
|
2145
|
+
local installed_store_doctor="$npm_pkg/mcp/entwurf-bridge/dist/scripts/meta-bridge-store-doctor.js"
|
|
2146
|
+
if [ ! -f "$installed_store_doctor" ]; then
|
|
2147
|
+
fail "[check-pack-install] installed store-doctor missing prebuilt dist (prepack did not emit it into the tarball?): $installed_store_doctor"
|
|
2148
|
+
return 1
|
|
2149
|
+
fi
|
|
2150
|
+
local sd_fixture="$npm_tmp/store-fixture"
|
|
2151
|
+
mkdir -p "$sd_fixture"
|
|
2152
|
+
# One valid v2 record: filename == "${gardenId}.meta.json" (no drift), unique
|
|
2153
|
+
# nativeSessionId (no dupe). gardenId must match YYYYMMDDTHHMMSS-[0-9a-f]{6}.
|
|
2154
|
+
printf '%s\n' '{"schemaVersion":2,"gardenId":"20990101T000000-abcdef","backend":"claude-code","nativeSessionId":"native-store-doctor-fixture","cwd":"/tmp/entwurf-fixture","model":null,"transcriptPath":null,"parentGardenId":null,"isEntwurf":false,"createdAt":"2099-01-01T00:00:00.000Z","recordUpdatedAt":"2099-01-01T00:00:00.000Z"}' \
|
|
2155
|
+
> "$sd_fixture/20990101T000000-abcdef.meta.json"
|
|
2156
|
+
local sd_out
|
|
2157
|
+
if ! sd_out=$(node "$installed_store_doctor" "$sd_fixture" 2>&1); then
|
|
2158
|
+
fail "[check-pack-install] installed store-doctor FAILED to scan under node_modules (strip-types-under-node_modules regression, or the emitted meta-session import broke):"
|
|
2159
|
+
echo "$sd_out" | tail -15 | sed 's/^/ /' >&2
|
|
2160
|
+
return 1
|
|
2161
|
+
fi
|
|
2162
|
+
if ! grep -q "1 record(s) scanned" <<<"$sd_out"; then
|
|
2163
|
+
fail "[check-pack-install] installed store-doctor scanned but did not report the fixture record (parseMetaIdentity path not exercised?): $sd_out"
|
|
2164
|
+
return 1
|
|
2165
|
+
fi
|
|
2166
|
+
echo "[check-pack-install] installed store-doctor scan pass (dist JS scans under node_modules with plain node: $sd_out)"
|
|
2167
|
+
|
|
2168
|
+
# 0.12.4 — installed DOCTOR DISPATCH lock. The artifact above proves the store-scan
|
|
2169
|
+
# target runs under node_modules; this proves the doctor SCRIPT actually routes to
|
|
2170
|
+
# it (store scan → dist JS) and defers the strip-types-only source-shape gate
|
|
2171
|
+
# (v2-surface) when installed, instead of running raw .ts and false-failing.
|
|
2172
|
+
local installed_doctor="$npm_pkg/scripts/meta-bridge-doctor.sh"
|
|
2173
|
+
if ! grep -q 'dist/scripts/meta-bridge-store-doctor.js' "$installed_doctor"; then
|
|
2174
|
+
fail "[check-pack-install] installed doctor does not dispatch the store scan to the dist JS under node_modules: $installed_doctor"
|
|
2175
|
+
return 1
|
|
2176
|
+
fi
|
|
2177
|
+
if ! grep -q 'shipped surface source present' "$installed_doctor"; then
|
|
2178
|
+
fail "[check-pack-install] installed doctor does not defer the v2-surface source-shape gate on installed hosts: $installed_doctor"
|
|
2179
|
+
return 1
|
|
2180
|
+
fi
|
|
2181
|
+
echo "[check-pack-install] installed doctor dispatch lock pass (store-scan → dist JS, v2-surface deferred)"
|
|
2182
|
+
|
|
2130
2183
|
ok "[check-pack-install] publish install smoke pass"
|
|
2131
2184
|
return 0
|
|
2132
2185
|
}
|
|
@@ -21,7 +21,7 @@ import { resolve } from "node:path";
|
|
|
21
21
|
import { pathToFileURL } from "node:url";
|
|
22
22
|
import type { Api, AssistantMessageEvent, Context, Model } from "@earendil-works/pi-ai";
|
|
23
23
|
|
|
24
|
-
const model = { id: "claude-sonnet-
|
|
24
|
+
const model = { id: "claude-sonnet-5" } as unknown as Model<Api>;
|
|
25
25
|
|
|
26
26
|
// Declared tools exclude `read`, but the Claude child always exposes Read →
|
|
27
27
|
// declared != actual → the preflight must reject before spawning.
|
|
@@ -58,7 +58,7 @@ function settings(name: string, block: unknown): string {
|
|
|
58
58
|
function resolveWith(globalPath: string, projectPath: string, adapter: AcpBackendAdapter = claudeLikeFake) {
|
|
59
59
|
return resolveProviderConfig({
|
|
60
60
|
cwd: root,
|
|
61
|
-
modelId: "claude-sonnet-
|
|
61
|
+
modelId: "claude-sonnet-5",
|
|
62
62
|
adapter,
|
|
63
63
|
globalSettingsPath: globalPath,
|
|
64
64
|
projectSettingsPath: projectPath,
|
|
@@ -291,11 +291,11 @@ try {
|
|
|
291
291
|
weather: { type: "http", url: "https://w.test" },
|
|
292
292
|
other: { command: "x" },
|
|
293
293
|
}).servers;
|
|
294
|
-
const enriched = enrichMcpServersWithEnvelope(servers, { modelId: "claude-sonnet-
|
|
294
|
+
const enriched = enrichMcpServersWithEnvelope(servers, { modelId: "claude-sonnet-5", piSessionId: "LIVE-1" });
|
|
295
295
|
const bridge = enriched.find((s) => s.name === "entwurf-bridge") as Extract<AcpMcpServer, { command: string }>;
|
|
296
296
|
const env = Object.fromEntries(bridge.env.map((e) => [e.name, e.value]));
|
|
297
297
|
assert.equal(env.PI_SESSION_ID, "LIVE-1", "live PI_SESSION_ID wins over the stale operator value");
|
|
298
|
-
assert.equal(env.PI_AGENT_ID, "entwurf/claude-sonnet-
|
|
298
|
+
assert.equal(env.PI_AGENT_ID, "entwurf/claude-sonnet-5", "PI_AGENT_ID injected from the model id");
|
|
299
299
|
assert.equal(env.FOO, "bar", "operator env preserved");
|
|
300
300
|
const weather = enriched.find((s) => s.name === "weather");
|
|
301
301
|
assert.ok(!("env" in (weather ?? {})), "http server not enriched (no env carrier)");
|
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
finalizeAcpStreamState,
|
|
22
22
|
} from "../pi-extensions/lib/acp/event-mapper.ts";
|
|
23
23
|
|
|
24
|
-
const IDENTITY = { api: "entwurf", provider: "entwurf", model: "claude-sonnet-
|
|
24
|
+
const IDENTITY = { api: "entwurf", provider: "entwurf", model: "claude-sonnet-5" };
|
|
25
25
|
|
|
26
26
|
// Drive a set of synthetic updates through a fresh mapper and collect every
|
|
27
27
|
// emitted event (push is synchronous; the terminal done drains the queue).
|
|
@@ -117,7 +117,7 @@ try {
|
|
|
117
117
|
assert.equal(cap.cfg.apiKey, ENTWURF_ACP_NO_AUTH_SENTINEL, "entry apiKey is not the no-auth sentinel");
|
|
118
118
|
assert.equal(cap.cfg.api, "entwurf", "entry api field drifted");
|
|
119
119
|
const capIds = (cap.cfg.models ?? []).map((m) => m.id);
|
|
120
|
-
for (const want of ["claude-sonnet-
|
|
120
|
+
for (const want of ["claude-sonnet-5", CURATED_ANCHOR_MODEL_ID]) {
|
|
121
121
|
assert.ok(capIds.includes(want), `entry model surface missing ${want} (got: ${capIds.join(", ") || "none"})`);
|
|
122
122
|
}
|
|
123
123
|
assert.equal(typeof cap.cfg.streamSimple, "function", "entry streamSimple must be a function");
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
// Deterministic gate for the S2a ACP SDK dependency surface.
|
|
2
2
|
//
|
|
3
|
-
// Pins the ACP runtime deps to the
|
|
3
|
+
// Pins the ACP runtime deps to the current behavior-oracle versions and locks
|
|
4
4
|
// the peer-resolution that makes the Claude ACP adapter satisfiable:
|
|
5
5
|
//
|
|
6
|
-
// @agentclientprotocol/sdk
|
|
7
|
-
// @agentclientprotocol/claude-agent-acp 0.
|
|
6
|
+
// @agentclientprotocol/sdk 1.1.0 wire SDK (acp-bridge import source)
|
|
7
|
+
// @agentclientprotocol/claude-agent-acp 0.54.1 Claude adapter (spawn binary)
|
|
8
8
|
// @anthropic-ai/sdk 0.100.1 peer-resolution pin ONLY (see below)
|
|
9
9
|
//
|
|
10
10
|
// The anthropic SDK is NOT an API client / auth surface here. It is a direct
|
|
11
|
-
// dep solely to satisfy @anthropic-ai/claude-agent-sdk@0.3.
|
|
11
|
+
// dep solely to satisfy @anthropic-ai/claude-agent-sdk@0.3.197's peer floor
|
|
12
12
|
// (>=0.93.0); drop it and the tree resolves a stale 0.91.1 so the peer goes
|
|
13
|
-
// unmet — a failure that would only surface at the first raw turn.
|
|
13
|
+
// unmet — a failure that would only surface at the first raw turn. The
|
|
14
14
|
// lockfile proves the same shape. Source-level import / API-client
|
|
15
15
|
// instantiation / credential use stays forbidden — asserted in layer (4).
|
|
16
16
|
// (GPT hard constraint 2, revised 2026-06-18: direct dep allowed ONLY as an
|
|
@@ -42,15 +42,15 @@ const read = (p: string): string => readFileSync(resolve(repoRoot, p), "utf8");
|
|
|
42
42
|
const pkg = JSON.parse(read("package.json")) as { dependencies?: Record<string, string> };
|
|
43
43
|
const deps = pkg.dependencies ?? {};
|
|
44
44
|
const PINS: Record<string, string> = {
|
|
45
|
-
"@agentclientprotocol/sdk": "
|
|
46
|
-
"@agentclientprotocol/claude-agent-acp": "0.
|
|
45
|
+
"@agentclientprotocol/sdk": "1.1.0",
|
|
46
|
+
"@agentclientprotocol/claude-agent-acp": "0.54.1",
|
|
47
47
|
[ANTHROPIC_SDK]: "0.100.1",
|
|
48
48
|
};
|
|
49
49
|
for (const [name, ver] of Object.entries(PINS)) {
|
|
50
50
|
assert.equal(
|
|
51
51
|
deps[name],
|
|
52
52
|
ver,
|
|
53
|
-
`package.json dependencies["${name}"] must be exact "${ver}" (got "${deps[name]}") — S2a pins the
|
|
53
|
+
`package.json dependencies["${name}"] must be exact "${ver}" (got "${deps[name]}") — S2a pins the current oracle versions`,
|
|
54
54
|
);
|
|
55
55
|
}
|
|
56
56
|
|
|
@@ -63,13 +63,13 @@ for (const [name, ver] of Object.entries(PINS)) {
|
|
|
63
63
|
const lock = read("pnpm-lock.yaml");
|
|
64
64
|
assert.match(
|
|
65
65
|
lock,
|
|
66
|
-
/@agentclientprotocol\/claude-agent-acp@0\.
|
|
67
|
-
"pnpm-lock: claude-agent-acp@0.
|
|
66
|
+
/@agentclientprotocol\/claude-agent-acp@0\.54\.1\(@anthropic-ai\/sdk@0\.100\.1/,
|
|
67
|
+
"pnpm-lock: claude-agent-acp@0.54.1 must peer-resolve @anthropic-ai/sdk@0.100.1 (peer-pin), not the stale 0.91.1",
|
|
68
68
|
);
|
|
69
69
|
assert.match(
|
|
70
70
|
lock,
|
|
71
|
-
/@anthropic-ai\/claude-agent-sdk@0\.3\.
|
|
72
|
-
"pnpm-lock: claude-agent-sdk@0.3.
|
|
71
|
+
/@anthropic-ai\/claude-agent-sdk@0\.3\.197\(@anthropic-ai\/sdk@0\.100\.1/,
|
|
72
|
+
"pnpm-lock: claude-agent-sdk@0.3.197 must peer-resolve @anthropic-ai/sdk@0.100.1 — else its >=0.93.0 peer floor is unmet",
|
|
73
73
|
);
|
|
74
74
|
|
|
75
75
|
// ---------------------------------------------------------------------------
|
|
@@ -108,8 +108,8 @@ const casEntry = adapterRequire.resolve("@anthropic-ai/claude-agent-sdk");
|
|
|
108
108
|
const casInfo = pkgInfoFromEntry(casEntry);
|
|
109
109
|
assert.equal(
|
|
110
110
|
casInfo.version,
|
|
111
|
-
"0.3.
|
|
112
|
-
`@anthropic-ai/claude-agent-sdk must runtime-resolve to 0.3.
|
|
111
|
+
"0.3.197",
|
|
112
|
+
`@anthropic-ai/claude-agent-sdk must runtime-resolve to 0.3.197 from the adapter context (got ${casInfo.version})`,
|
|
113
113
|
);
|
|
114
114
|
const casRequire = createRequire(resolve(casInfo.dir, "package.json"));
|
|
115
115
|
const sdkEntry = casRequire.resolve(ANTHROPIC_SDK);
|
|
@@ -121,19 +121,19 @@ assert.equal(
|
|
|
121
121
|
);
|
|
122
122
|
|
|
123
123
|
// ---------------------------------------------------------------------------
|
|
124
|
-
// (2c) adapter-context wire-SDK + MCP-SDK runtime resolve — the
|
|
125
|
-
// fault surface. Lock text (layer 2) freezes the publish floor; these probe
|
|
124
|
+
// (2c) adapter-context wire-SDK + MCP-SDK runtime resolve — the ACP dep bump's
|
|
125
|
+
// real fault surface. Lock text (layer 2) freezes the publish floor; these probe
|
|
126
126
|
// the LIVE module graph the adapter actually traverses: the adapter must SEE
|
|
127
|
-
// the same wire SDK the backend imports at root (
|
|
127
|
+
// the same wire SDK the backend imports at root (1.1.0), and claude-agent-sdk
|
|
128
128
|
// must SEE its declared MCP peer (1.29.x). Cheap edges, both newly relevant
|
|
129
|
-
// after the 0.
|
|
129
|
+
// after the 0.50→0.54 / 0.29→1.1 bump.
|
|
130
130
|
// ---------------------------------------------------------------------------
|
|
131
131
|
const wireEntry = adapterRequire.resolve("@agentclientprotocol/sdk");
|
|
132
132
|
const wireInfo = pkgInfoFromEntry(wireEntry);
|
|
133
133
|
assert.equal(
|
|
134
134
|
wireInfo.version,
|
|
135
|
-
"
|
|
136
|
-
`@agentclientprotocol/sdk must runtime-resolve to
|
|
135
|
+
"1.1.0",
|
|
136
|
+
`@agentclientprotocol/sdk must runtime-resolve to 1.1.0 from the adapter context (got ${wireInfo.version}) — the adapter and the backend must share one wire SDK`,
|
|
137
137
|
);
|
|
138
138
|
// @modelcontextprotocol/sdk gates its bare specifier behind "exports", so a
|
|
139
139
|
// require.resolve of the package ROOT throws (no resolvable entry) — read the
|
|
@@ -143,12 +143,12 @@ assert.equal(
|
|
|
143
143
|
const mcpPkg = JSON.parse(read("node_modules/@modelcontextprotocol/sdk/package.json")) as { version?: string };
|
|
144
144
|
assert.ok(
|
|
145
145
|
typeof mcpPkg.version === "string" && mcpPkg.version.startsWith("1.29."),
|
|
146
|
-
`@modelcontextprotocol/sdk must be 1.29.x (got ${mcpPkg.version}) — claude-agent-sdk 0.3.
|
|
146
|
+
`@modelcontextprotocol/sdk must be 1.29.x (got ${mcpPkg.version}) — claude-agent-sdk 0.3.197 declares a ^1.29.0 peer`,
|
|
147
147
|
);
|
|
148
148
|
|
|
149
149
|
// ---------------------------------------------------------------------------
|
|
150
150
|
// (3) @agentclientprotocol/sdk value-export surface (silent-rename gate)
|
|
151
|
-
// The
|
|
151
|
+
// The ACP bridge imports these from the wire SDK; a silent upstream
|
|
152
152
|
// rename would not fail typecheck (type-only erasure) but would break the
|
|
153
153
|
// raw turn. Assert the *value* exports exist at runtime.
|
|
154
154
|
// ---------------------------------------------------------------------------
|
|
@@ -32,7 +32,7 @@ import { resolve } from "node:path";
|
|
|
32
32
|
import { pathToFileURL } from "node:url";
|
|
33
33
|
import type { Api, AssistantMessageEvent, Context, Message, Model } from "@earendil-works/pi-ai";
|
|
34
34
|
|
|
35
|
-
const sonnet = { id: "claude-sonnet-
|
|
35
|
+
const sonnet = { id: "claude-sonnet-5" } as unknown as Model<Api>;
|
|
36
36
|
const opus = { id: "claude-opus-4-8" } as unknown as Model<Api>;
|
|
37
37
|
|
|
38
38
|
type Stream = AsyncIterable<AssistantMessageEvent> & {
|
|
@@ -488,7 +488,7 @@ try {
|
|
|
488
488
|
);
|
|
489
489
|
const d1 = deltaText(t1);
|
|
490
490
|
const iPrep = d1.indexOf("[acp: preparing claude session]");
|
|
491
|
-
const iReady = d1.indexOf("[acp: session ready model=claude-sonnet-
|
|
491
|
+
const iReady = d1.indexOf("[acp: session ready model=claude-sonnet-5]");
|
|
492
492
|
const iSent = d1.indexOf("[acp: sending prompt]");
|
|
493
493
|
assert.ok(
|
|
494
494
|
iPrep >= 0 && iReady > iPrep && iSent > iReady,
|
|
@@ -517,7 +517,7 @@ try {
|
|
|
517
517
|
messages: [
|
|
518
518
|
{ role: "user", content: "real user line", timestamp: 0 },
|
|
519
519
|
mkAssistant([
|
|
520
|
-
{ type: "text", text: "\n[acp: session ready model=claude-sonnet-
|
|
520
|
+
{ type: "text", text: "\n[acp: session ready model=claude-sonnet-5]\n", textSignature: MARKER },
|
|
521
521
|
{ type: "text", text: "real assistant line" },
|
|
522
522
|
]),
|
|
523
523
|
],
|
|
@@ -43,8 +43,8 @@ import {
|
|
|
43
43
|
|
|
44
44
|
const baseInput = (): BridgeConfigInput => ({
|
|
45
45
|
backend: "claude",
|
|
46
|
-
modelId: "claude-sonnet-
|
|
47
|
-
nativeModelId: "claude-sonnet-
|
|
46
|
+
modelId: "claude-sonnet-5",
|
|
47
|
+
nativeModelId: "claude-sonnet-5",
|
|
48
48
|
appendSystemPrompt: "",
|
|
49
49
|
mcpServersHash: "deadbeef",
|
|
50
50
|
settingSources: [],
|
|
@@ -61,7 +61,7 @@ const baseInput = (): BridgeConfigInput => ({
|
|
|
61
61
|
{
|
|
62
62
|
const sig0 = bridgeConfigSignature(baseInput());
|
|
63
63
|
assert.ok(isSha256Hex(sig0), "config signature is a sha256 digest (no raw carrier text on disk)");
|
|
64
|
-
assert.ok(!sig0.includes("claude-sonnet-
|
|
64
|
+
assert.ok(!sig0.includes("claude-sonnet-5"), "config signature is a digest — never embeds the raw modelId/carrier");
|
|
65
65
|
assert.equal(sig0, bridgeConfigSignature(baseInput()), "signature is deterministic");
|
|
66
66
|
// Array copies do not affect equality (same content).
|
|
67
67
|
assert.equal(bridgeConfigSignature({ ...baseInput(), settingSources: [] }), sig0, "empty settingSources stable");
|
|
@@ -178,7 +178,7 @@ const baseInput = (): BridgeConfigInput => ({
|
|
|
178
178
|
|
|
179
179
|
const facts = (over: Partial<SessionCompatFacts> = {}): SessionCompatFacts => ({
|
|
180
180
|
cwd: "/w",
|
|
181
|
-
modelId: "claude-sonnet-
|
|
181
|
+
modelId: "claude-sonnet-5",
|
|
182
182
|
bridgeConfigSignature: bridgeConfigSignature(baseInput()),
|
|
183
183
|
contextMessageSignatures: ["user:text:a"],
|
|
184
184
|
...over,
|
|
@@ -201,7 +201,7 @@ const baseInput = (): BridgeConfigInput => ({
|
|
|
201
201
|
const sig = bridgeConfigSignature(baseInput());
|
|
202
202
|
const compatFacts: SessionCompatFacts = {
|
|
203
203
|
cwd: "/w",
|
|
204
|
-
modelId: "claude-sonnet-
|
|
204
|
+
modelId: "claude-sonnet-5",
|
|
205
205
|
bridgeConfigSignature: sig,
|
|
206
206
|
contextMessageSignatures: ["user:text:a"],
|
|
207
207
|
};
|
|
@@ -305,7 +305,7 @@ const baseInput = (): BridgeConfigInput => ({
|
|
|
305
305
|
{
|
|
306
306
|
const facts: SessionCompatFacts = {
|
|
307
307
|
cwd: "/w",
|
|
308
|
-
modelId: "claude-sonnet-
|
|
308
|
+
modelId: "claude-sonnet-5",
|
|
309
309
|
bridgeConfigSignature: bridgeConfigSignature(baseInput()),
|
|
310
310
|
contextMessageSignatures: ["user:text:a"],
|
|
311
311
|
};
|
|
@@ -90,7 +90,7 @@ assert.ok(nativeThrew, "non-claude backend exposing write natively must throw wh
|
|
|
90
90
|
// ---------------------------------------------------------------------------
|
|
91
91
|
|
|
92
92
|
const baseParams = {
|
|
93
|
-
modelId: "claude-sonnet-
|
|
93
|
+
modelId: "claude-sonnet-5",
|
|
94
94
|
tools: DEFAULT_CLAUDE_TOOLS,
|
|
95
95
|
permissionAllow: DEFAULT_CLAUDE_PERMISSION_ALLOW,
|
|
96
96
|
disallowedTools: DEFAULT_CLAUDE_DISALLOWED_TOOLS,
|
|
@@ -101,7 +101,7 @@ const baseParams = {
|
|
|
101
101
|
|
|
102
102
|
const meta = buildClaudeSessionMeta(baseParams);
|
|
103
103
|
const opts = (meta.claudeCode as { options: Record<string, unknown> }).options;
|
|
104
|
-
assert.equal(opts.model, "claude-sonnet-
|
|
104
|
+
assert.equal(opts.model, "claude-sonnet-5", "model must propagate");
|
|
105
105
|
assert.deepEqual(opts.tools, [...DEFAULT_CLAUDE_TOOLS], "tools must propagate (copied)");
|
|
106
106
|
assert.deepEqual(
|
|
107
107
|
(opts.settings as { permissions: { allow: string[] } }).permissions.allow,
|
|
@@ -132,7 +132,7 @@ try {
|
|
|
132
132
|
{ p: "entwurf", m: "claude-opus-4-8", title: "Review substrate smoke", tags: ["entwurf", "review"] },
|
|
133
133
|
{ p: "openai-codex", m: "gpt-5.5", title: "async resume check", tags: ["entwurf", "smoke"] },
|
|
134
134
|
{ p: "entwurf", m: "gemini-3.1-pro-preview", title: "vision team", tags: ["entwurf"] },
|
|
135
|
-
{ p: "entwurf", m: "claude-sonnet-
|
|
135
|
+
{ p: "entwurf", m: "claude-sonnet-5", title: "manual session", tags: [] as string[] },
|
|
136
136
|
];
|
|
137
137
|
for (const c of cases) {
|
|
138
138
|
const sid = generateSessionId(new Date(2026, 5, 3, 19, 12, 45));
|
|
@@ -252,7 +252,7 @@ try {
|
|
|
252
252
|
tags: ["entwurf"],
|
|
253
253
|
});
|
|
254
254
|
eq(parseSessionName(goodName)?.model, recorded, "name model mirrors recorded model");
|
|
255
|
-
const driftName = "20260603T191245-deadbe==entwurf/claude-sonnet-
|
|
255
|
+
const driftName = "20260603T191245-deadbe==entwurf/claude-sonnet-5--x__entwurf";
|
|
256
256
|
ok(parseSessionName(driftName)?.model !== recorded, "model drift is detectable for fail-fast");
|
|
257
257
|
|
|
258
258
|
// ---- T-collision: header scan is authority; spawn pre-check ----
|
|
@@ -440,12 +440,12 @@ try {
|
|
|
440
440
|
bigFile,
|
|
441
441
|
`${JSON.stringify({ type: "session", id: "20260603T210000-bbbbbb", cwd: "/b" })}\n` +
|
|
442
442
|
msg({ content: bigBody, model: "m-big", provider: "p-big", usage: { cost: { total: 1 } } }) +
|
|
443
|
-
msg({ content: "final", model: "claude-sonnet-
|
|
443
|
+
msg({ content: "final", model: "claude-sonnet-5", provider: "entwurf", usage: { cost: { total: 0.5 } } }),
|
|
444
444
|
);
|
|
445
445
|
const a2 = analyzeSessionFileLike(bigFile);
|
|
446
446
|
eq(a2.turns, 2, "analyze(big): turns correct across chunk boundaries");
|
|
447
447
|
eq(a2.lastAssistantText, "final", "analyze(big): trailing turn intact after multi-chunk line");
|
|
448
|
-
eq(a2.lastModel, "claude-sonnet-
|
|
448
|
+
eq(a2.lastModel, "claude-sonnet-5", "analyze(big): trailing model intact");
|
|
449
449
|
eq(Math.round(a2.cost * 100) / 100, 1.5, "analyze(big): cost summed across large line");
|
|
450
450
|
|
|
451
451
|
// ---- T-identity: resume identity authority = FIRST model_change ----
|
|
@@ -513,21 +513,21 @@ try {
|
|
|
513
513
|
const cleanName = buildSessionName({
|
|
514
514
|
sessionId: idE,
|
|
515
515
|
provider: "entwurf",
|
|
516
|
-
model: "claude-sonnet-
|
|
516
|
+
model: "claude-sonnet-5",
|
|
517
517
|
rawTitle: "clean resume",
|
|
518
518
|
tags: ["entwurf", "async"],
|
|
519
519
|
});
|
|
520
520
|
fs.writeFileSync(
|
|
521
521
|
fileE,
|
|
522
522
|
sessionLine(idE, "/identity/e") +
|
|
523
|
-
mc("entwurf", "claude-sonnet-
|
|
523
|
+
mc("entwurf", "claude-sonnet-5") +
|
|
524
524
|
infoLine(cleanName) +
|
|
525
|
-
msg({ content: "ok", model: "claude-sonnet-
|
|
525
|
+
msg({ content: "ok", model: "claude-sonnet-5", provider: "entwurf" }),
|
|
526
526
|
);
|
|
527
527
|
noThrow(() => readSessionIdentity(fileE), "identity: clean session does not throw");
|
|
528
528
|
const recE = readSessionIdentity(fileE);
|
|
529
529
|
eq(recE?.provider, "entwurf", "identity(clean): provider");
|
|
530
|
-
eq(recE?.modelId, "claude-sonnet-
|
|
530
|
+
eq(recE?.modelId, "claude-sonnet-5", "identity(clean): modelId mirrors name");
|
|
531
531
|
|
|
532
532
|
// 6. no model_change → null (caller refuses with its own no-recorded-model result).
|
|
533
533
|
const idF = "20260603T220000-6666ff";
|
|
@@ -583,7 +583,7 @@ try {
|
|
|
583
583
|
);
|
|
584
584
|
eq(
|
|
585
585
|
readSessionIdentity(fileE, { requireEntwurf: true })?.modelId,
|
|
586
|
-
"claude-sonnet-
|
|
586
|
+
"claude-sonnet-5",
|
|
587
587
|
"requireEntwurf: accepted Entwurf session returns first-model_change identity",
|
|
588
588
|
);
|
|
589
589
|
|
|
@@ -210,7 +210,7 @@ async function makeHarness(opts: MakeHarnessOpts = {}): Promise<Harness> {
|
|
|
210
210
|
// Test models.
|
|
211
211
|
const NATIVE_A: ModelLike = { provider: "openai-codex", id: "gpt-5.4" };
|
|
212
212
|
const NATIVE_B: ModelLike = { provider: "openai-codex", id: "gpt-5.5" };
|
|
213
|
-
const PSA_SONNET: ModelLike = { provider: "entwurf", id: "claude-sonnet-
|
|
213
|
+
const PSA_SONNET: ModelLike = { provider: "entwurf", id: "claude-sonnet-5" };
|
|
214
214
|
const PSA_OPUS: ModelLike = { provider: "entwurf", id: "claude-opus-4-8" };
|
|
215
215
|
|
|
216
216
|
let passed = 0;
|
|
@@ -250,7 +250,7 @@ await run("2. native → entwurf: revert + warning notify", async () => {
|
|
|
250
250
|
assert.equal(h.notifyCalls.length, 1);
|
|
251
251
|
assert.equal(h.notifyCalls[0].level, "warning");
|
|
252
252
|
assert.match(h.notifyCalls[0].message, /locked to openai-codex\/gpt-5\.4/);
|
|
253
|
-
assert.match(h.notifyCalls[0].message, /entwurf\/claude-sonnet-
|
|
253
|
+
assert.match(h.notifyCalls[0].message, /entwurf\/claude-sonnet-5/);
|
|
254
254
|
});
|
|
255
255
|
|
|
256
256
|
await run("3. entwurf → native: revert + warning notify", async () => {
|
|
@@ -74,7 +74,7 @@ function rmInstall(...segs: string[]): void {
|
|
|
74
74
|
fs.rmSync(path.join(tmpAgent, ...segs), { recursive: true, force: true });
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
-
const ACP: ResolvedTarget = { provider: "entwurf", model: "claude-sonnet-
|
|
77
|
+
const ACP: ResolvedTarget = { provider: "entwurf", model: "claude-sonnet-5", explicitOnly: false };
|
|
78
78
|
const eArg = (r: { args: string[] }): string | undefined => {
|
|
79
79
|
const i = r.args.indexOf("-e");
|
|
80
80
|
return i >= 0 ? r.args[i + 1] : undefined;
|
|
@@ -211,7 +211,7 @@ check("project-scope source (unseen in user settings) fails fast on remote", ()
|
|
|
211
211
|
// (resume callers fail-fast; no -e injected).
|
|
212
212
|
check("resume recorded entwurf + remote + no source → unresolvedAcpIntent", () => {
|
|
213
213
|
setSource(null);
|
|
214
|
-
const r = getEntwurfExplicitExtensions("claude-sonnet-
|
|
214
|
+
const r = getEntwurfExplicitExtensions("claude-sonnet-5", true, "entwurf");
|
|
215
215
|
assert.equal(r.unresolvedAcpIntent, true);
|
|
216
216
|
assert.equal(eArg(r), undefined);
|
|
217
217
|
assert.ok(r.warnings.length > 0, "should warn about the unresolved bridge");
|
|
@@ -220,7 +220,7 @@ check("resume recorded entwurf + remote + no source → unresolvedAcpIntent", ()
|
|
|
220
220
|
// 13. recorded provider=entwurf + LOCAL → self-root resolves, no fail-fast.
|
|
221
221
|
check("resume recorded entwurf + local resolves via self-root", () => {
|
|
222
222
|
setSource(null);
|
|
223
|
-
const r = getEntwurfExplicitExtensions("claude-sonnet-
|
|
223
|
+
const r = getEntwurfExplicitExtensions("claude-sonnet-5", false, "entwurf");
|
|
224
224
|
assert.ok(!r.unresolvedAcpIntent, "local self-root should resolve");
|
|
225
225
|
assert.equal(eArg(r), REPO_ROOT);
|
|
226
226
|
assert.equal(r.provider, "entwurf");
|
|
@@ -242,7 +242,7 @@ check("resume Codex-via-ACP opt-in + remote + no source → unresolvedAcpIntent"
|
|
|
242
242
|
// fail-fast — because the legacy pi-claude-code-use bridge may exist.
|
|
243
243
|
check("resume Claude-only heuristic + remote + no source stays warning-only", () => {
|
|
244
244
|
setSource(null);
|
|
245
|
-
const r = getEntwurfExplicitExtensions("claude-sonnet-
|
|
245
|
+
const r = getEntwurfExplicitExtensions("claude-sonnet-5", true, undefined);
|
|
246
246
|
assert.ok(!r.unresolvedAcpIntent, "Claude heuristic must not fail-fast");
|
|
247
247
|
assert.ok(r.warnings.length > 0, "should warn");
|
|
248
248
|
assert.equal(eArg(r), undefined);
|