@junghanacs/entwurf 0.50.0 → 0.52.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 +2 -1
- package/CHANGELOG.md +140 -0
- package/ENTWURF.json +10 -4
- package/README.md +16 -8
- package/VERIFY.md +16 -9
- package/demo/README.md +1 -1
- package/docs/acp-backend-rail.md +1 -1
- package/docs/external-mcp-host.md +2 -2
- package/docs/setup-clean-host.md +92 -35
- package/mcp/entwurf-bridge/dist/ENTWURF.json +10 -4
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-control-rpc.js +4 -1
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-contract.js +4 -4
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-mailbox-body.js +1 -1
- package/package.json +11 -18
- package/pi/pi-durable/carrier/harness-setup.js +1 -1
- package/pi/pi-durable/carrier/runtime.js +221 -50
- package/pi/pi-durable/carrier/subagent.js +6 -3
- package/pi/pi-durable/carrier/tui.js +60 -22
- package/pi/pi-durable/overlay/upstream-pin.json +19 -18
- package/pi-extensions/lib/entwurf-control-rpc.ts +5 -1
- package/pi-extensions/lib/entwurf-v2-contract-schema.ts +73 -69
- package/pi-extensions/lib/entwurf-v2-contract.ts +4 -4
- package/pi-extensions/lib/meta-mailbox-body.ts +1 -1
- package/pi-extensions/meta-bridge-pi-durable.ts +1 -1
- package/run.sh +148 -46
- package/scripts/check-entwurf-v2-contract.ts +4 -4
- package/scripts/check-entwurf-v2-surface.ts +7 -21
- package/scripts/check-gate-qualification.ts +3 -3
- package/scripts/check-pi-durable-send.ts +4 -1
- package/scripts/lib/codex-fresh-source-receipts.ts +12 -6
- package/scripts/mutants/agent-guidance.json +2 -2
- package/scripts/mutants/codex-native.json +2 -2
- package/scripts/mutants/control-send-receipt.json +47 -7
- package/scripts/mutants/pack-install.json +4 -4
- package/scripts/mutants/pi-durable.json +189 -3
- package/scripts/mutants/pi-floor.json +20 -5
- package/scripts/mutants/v2-surface.json +4 -6
- package/scripts/smoke-acp-cortex-live.ts +1 -1
- package/scripts/smoke-acp-v2-send-live.ts +1 -1
|
@@ -70,20 +70,20 @@
|
|
|
70
70
|
{
|
|
71
71
|
"name": "runtime.js",
|
|
72
72
|
"source": "pi/pi-durable/src/experimental/durable/runtime.ts",
|
|
73
|
-
"blob": "
|
|
74
|
-
"sha256": "
|
|
73
|
+
"blob": "00646b1b1fbd7e935fb3e66b7578a2befc01f3c8",
|
|
74
|
+
"sha256": "b47113364b7525abd3bf9286ecb0069f78ac96688b8a271bdbca3a54b9d864c5"
|
|
75
75
|
},
|
|
76
76
|
{
|
|
77
77
|
"name": "tui.js",
|
|
78
78
|
"source": "pi/pi-durable/src/experimental/durable/tui.ts",
|
|
79
|
-
"blob": "
|
|
80
|
-
"sha256": "
|
|
79
|
+
"blob": "4b5dd1876ceac8f51910bb11ed5f0024003f4f34",
|
|
80
|
+
"sha256": "7fefe490d9d462e6a91621901b82b767546926f4a9f4e88d585fe74b727a02c1"
|
|
81
81
|
},
|
|
82
82
|
{
|
|
83
83
|
"name": "harness-setup.js",
|
|
84
84
|
"source": "pi/pi-durable/src/experimental/durable/harness-setup.ts",
|
|
85
|
-
"blob": "
|
|
86
|
-
"sha256": "
|
|
85
|
+
"blob": "5a799bfbfbbedbec229761b26f639fbe2702b623",
|
|
86
|
+
"sha256": "70b50044ab14c1293a2ace53b375dc48ad940ea9eeacc131d498ccb1ce040617"
|
|
87
87
|
},
|
|
88
88
|
{
|
|
89
89
|
"name": "prompt.js",
|
|
@@ -100,8 +100,8 @@
|
|
|
100
100
|
{
|
|
101
101
|
"name": "subagent.js",
|
|
102
102
|
"source": "pi/pi-durable/src/experimental/durable/subagent.ts",
|
|
103
|
-
"blob": "
|
|
104
|
-
"sha256": "
|
|
103
|
+
"blob": "8c18e24a030f0b701167f15a33579195303f5ac5",
|
|
104
|
+
"sha256": "208618441e8e81813de2f44fa9ad5d5bdcdbb78a754679bb7a93d82480e7bece"
|
|
105
105
|
},
|
|
106
106
|
{
|
|
107
107
|
"name": "session-name.js",
|
|
@@ -138,17 +138,18 @@
|
|
|
138
138
|
]
|
|
139
139
|
},
|
|
140
140
|
"sdk": {
|
|
141
|
-
"comment": "The published library set the carrier runs against, derived from the 1.
|
|
141
|
+
"comment": "The published library set the carrier runs against, derived from the 1.5.2 declarations. members: the @earendil-works packages the carrier imports and every @earendil-works package those declare (1.5.0 adds pi-schema, declared by chord, pi-agent-core, pi-ai and pi-durable). direct: a third-party package a carrier file imports itself (sessions.ts: proper-lockfile, at the version pi-coding-agent 1.5.2 pins). Each is an exact production dependency in package.json. Since 1.3.0 the members' own edges are exact too (upstream #10865), and the installed physical edges are still what must equal these versions.",
|
|
142
142
|
"members": {
|
|
143
|
-
"@earendil-works/chord": "1.
|
|
144
|
-
"@earendil-works/pi-agent-core": "1.
|
|
145
|
-
"@earendil-works/pi-ai": "1.
|
|
146
|
-
"@earendil-works/pi-codemode": "1.
|
|
147
|
-
"@earendil-works/pi-coding-agent": "1.
|
|
148
|
-
"@earendil-works/pi-durable": "1.
|
|
149
|
-
"@earendil-works/pi-mcp": "1.
|
|
150
|
-
"@earendil-works/pi-
|
|
151
|
-
"@earendil-works/pi-
|
|
143
|
+
"@earendil-works/chord": "1.5.2",
|
|
144
|
+
"@earendil-works/pi-agent-core": "1.5.2",
|
|
145
|
+
"@earendil-works/pi-ai": "1.5.2",
|
|
146
|
+
"@earendil-works/pi-codemode": "1.5.2",
|
|
147
|
+
"@earendil-works/pi-coding-agent": "1.5.2",
|
|
148
|
+
"@earendil-works/pi-durable": "1.5.2",
|
|
149
|
+
"@earendil-works/pi-mcp": "1.5.2",
|
|
150
|
+
"@earendil-works/pi-schema": "1.5.2",
|
|
151
|
+
"@earendil-works/pi-telemetry": "1.5.2",
|
|
152
|
+
"@earendil-works/pi-tui": "1.5.2"
|
|
152
153
|
},
|
|
153
154
|
"direct": {
|
|
154
155
|
"proper-lockfile": "4.1.2"
|
|
@@ -50,7 +50,11 @@ export interface SenderEnvelope {
|
|
|
50
50
|
* renders nothing (etiquette marker, not transport contract).
|
|
51
51
|
*/
|
|
52
52
|
export function formatSenderInfoBlock(sender: SenderEnvelope, wantsReply = false): string {
|
|
53
|
-
|
|
53
|
+
const replyGuidance =
|
|
54
|
+
sender.replyable === true
|
|
55
|
+
? "\n\n[entwurf: When a reply is requested, send the result via entwurf_v2 to the requested recipient (default: sender_info.sessionId); a local final is not delivery. Honor routing and no-send instructions; an absent or false wants_reply does not cancel a request. A replyable address alone needs no acknowledgment.]"
|
|
56
|
+
: "";
|
|
57
|
+
return `${replyGuidance}\n\n<sender_info>${JSON.stringify({
|
|
54
58
|
sessionId: sender.sessionId,
|
|
55
59
|
agentId: sender.agentId,
|
|
56
60
|
cwd: sender.cwd,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* entwurf-v2-contract-schema — the pi-side
|
|
3
|
-
* `entwurf_v2` contract. This module exists ONLY to carry the pi
|
|
4
|
-
*
|
|
2
|
+
* entwurf-v2-contract-schema — the pi-side JSON Schema REPRESENTATION of the frozen
|
|
3
|
+
* `entwurf_v2` contract. This module exists ONLY to carry the pi schema builders
|
|
4
|
+
* (pi-ai's `StringEnum`, pi-schema's `obj`/`str`/…) out of the pi-free core
|
|
5
5
|
* (`entwurf-v2-contract.ts`); the constants/types/decision logic live there.
|
|
6
6
|
*
|
|
7
7
|
* ⚠️ pi LANE ONLY — the MCP bridge (`mcp/entwurf-bridge/src/index.ts`) MUST NOT
|
|
@@ -11,18 +11,21 @@
|
|
|
11
11
|
* the contract CONSTANTS + `resolveDispatch` (pi-free core), never these schemas.
|
|
12
12
|
* Consumer: `check-entwurf-v2-contract` ONLY. This is a gate-side REPRESENTATION of the
|
|
13
13
|
* frozen contract, not a shipped tool schema — measured 2026-07-27, nothing else in the
|
|
14
|
-
* import graph reaches it. The
|
|
15
|
-
* `
|
|
16
|
-
*
|
|
17
|
-
*
|
|
14
|
+
* import graph reaches it. The surface a model actually reads builds its own:
|
|
15
|
+
* `mcp/entwurf-bridge/src/index.ts` (Zod, descriptions from ENTWURF.json), which a pi citizen
|
|
16
|
+
* reaches through Pi's built-in MCP since the native pi tools were retired (2f7c883, Pi 0.99).
|
|
17
|
+
* Change a model-facing description THERE; changing it here reaches no model.
|
|
18
18
|
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* `
|
|
19
|
+
* Pi SDK 1.5 (#155) removed pi-ai's TypeBox re-export (`Type`); its builders are now
|
|
20
|
+
* `@earendil-works/pi-schema`, which emits plain JSON Schema (obj() closed by default,
|
|
21
|
+
* opt() leaves a property out of `required`, lit() is `{const}`), and pi-ai's
|
|
22
|
+
* `StringEnum` still emits `{type:"string", enum}`. The logic types in the core are
|
|
23
|
+
* hand-written unions, NOT `Static<>` inferences; `check-entwurf-v2-contract` keeps
|
|
24
|
+
* these schemas and the core types in lockstep.
|
|
23
25
|
*/
|
|
24
26
|
|
|
25
|
-
import { StringEnum
|
|
27
|
+
import { StringEnum } from "@earendil-works/pi-ai";
|
|
28
|
+
import { bool, lit, nul, obj, opt, type Properties, type Schema, str, union } from "@earendil-works/pi-schema";
|
|
26
29
|
import {
|
|
27
30
|
ENTWURF_INTENTS,
|
|
28
31
|
ENTWURF_V2_ACTIONS,
|
|
@@ -34,36 +37,43 @@ import {
|
|
|
34
37
|
} from "./entwurf-v2-contract.ts";
|
|
35
38
|
import { SESSION_ID_RE } from "./session-id.js";
|
|
36
39
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
40
|
+
/**
|
|
41
|
+
* The face the drift guard reads. pi-schema types a schema as `{[keyword]: unknown}`; obj() always emits
|
|
42
|
+
* `properties`, so this names that one keyword without asserting anything else about the shape.
|
|
43
|
+
*/
|
|
44
|
+
type ObjectSchema = Schema & { readonly properties: Readonly<Record<string, Schema>> };
|
|
45
|
+
|
|
46
|
+
/** obj() — closed, so it emits `additionalProperties: false` — under the face above. */
|
|
47
|
+
const closedObject = (properties: Properties): ObjectSchema => obj(properties) as ObjectSchema;
|
|
48
|
+
|
|
49
|
+
export const EntwurfV2InputSchema = closedObject({
|
|
50
|
+
// R2/F6 executable: the garden-id shape is enforced by pattern, not prose —
|
|
51
|
+
// a malformed/typo gid fails the schema (→ bad-target) and can never reach a
|
|
52
|
+
// spawn. SSOT regex = SESSION_ID_RE (pi-extensions/lib/session-id.js).
|
|
53
|
+
target: str({
|
|
54
|
+
pattern: SESSION_ID_RE.source,
|
|
55
|
+
description:
|
|
56
|
+
"garden-id of an EXISTING citizen (pattern-enforced). Fresh sibling creation is out of scope on every current surface — there is no fallback verb that still spawns. A malformed/typo gid is bad-target, never a new spawn.",
|
|
57
|
+
}),
|
|
58
|
+
intent: StringEnum(ENTWURF_INTENTS, {
|
|
59
|
+
description:
|
|
60
|
+
"caller's declared outcome contract (F1). ONE member since the visible-first cut: fire-and-forget = ack only. The second, owned-outcome (caller owns completion), resumed a dormant citizen by launching a hidden background child and was withdrawn — a dormant citizen is currently unreachable by this verb.",
|
|
61
|
+
}),
|
|
62
|
+
mode: opt(
|
|
63
|
+
StringEnum(ENTWURF_V2_MODES, {
|
|
44
64
|
description:
|
|
45
|
-
"
|
|
65
|
+
"delivery mode — NOT the ownership axis (F1) nor liveness routing. steer (ask the receiver's steering queue) or follow_up (ask its follow-up queue). NEITHER is an interrupt: a busy receiver drains steering after each turn and follow-ups only when its inner loop ends, so a later steer overtakes every earlier follow_up and there is no order between the two. Both queues are volatile process memory — an abort drops what is in them. The receipt names which queue accepted the message (`queued-steer` / `queued-follow-up`); an idle receiver answers `sent`, meaning the turn was TRIGGERED, not that the model has seen the text. MEANINGLESS on the meta-mailbox transport (F-mailbox): a mailbox ack is enqueue+doorbell, not a turn injection, so steer/follow_up does not apply when the verdict transport is meta-mailbox.",
|
|
46
66
|
}),
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
67
|
+
),
|
|
68
|
+
wantsReply: opt(
|
|
69
|
+
bool({
|
|
70
|
+
description: "conversation etiquette only — NOT ownership; never triggers an auto-send (Q2).",
|
|
50
71
|
}),
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
),
|
|
57
|
-
wantsReply: Type.Optional(
|
|
58
|
-
Type.Boolean({
|
|
59
|
-
description: "conversation etiquette only — NOT ownership; never triggers an auto-send (Q2).",
|
|
60
|
-
}),
|
|
61
|
-
),
|
|
62
|
-
// `additionalProperties: false` — a frozen contract input is exact; an unknown
|
|
63
|
-
// key is a caller error, not silently ignored.
|
|
64
|
-
},
|
|
65
|
-
{ additionalProperties: false },
|
|
66
|
-
);
|
|
72
|
+
),
|
|
73
|
+
// `additionalProperties: false` — a frozen contract input is exact; an unknown
|
|
74
|
+
// key is a caller error, not silently ignored. obj() is closed by default (it
|
|
75
|
+
// emits `additionalProperties: false` unless `open: true`).
|
|
76
|
+
});
|
|
67
77
|
|
|
68
78
|
// Receipt = a DISCRIMINATED union on `ok` (R3/F6) — NOT one flat object with
|
|
69
79
|
// optionals. Each branch is EXACT (`additionalProperties: false`): without it,
|
|
@@ -72,35 +82,29 @@ export const EntwurfV2InputSchema = Type.Object(
|
|
|
72
82
|
// With it, success carries action/transport/ownership and rejects a stray reason;
|
|
73
83
|
// reject carries reason and rejects any allow facet — the branches are mutually
|
|
74
84
|
// exclusive at the schema level, not merely by declared-property convention.
|
|
75
|
-
export const EntwurfV2ReceiptSuccessSchema =
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
},
|
|
85
|
-
{ additionalProperties: false },
|
|
86
|
-
);
|
|
85
|
+
export const EntwurfV2ReceiptSuccessSchema = closedObject({
|
|
86
|
+
ok: lit(true),
|
|
87
|
+
action: StringEnum(ENTWURF_V2_ACTIONS),
|
|
88
|
+
transport: StringEnum(ENTWURF_V2_TRANSPORTS),
|
|
89
|
+
ownership: StringEnum(ENTWURF_V2_OWNERSHIPS),
|
|
90
|
+
observedLiveness: StringEnum(FACT_LIVENESSES, {
|
|
91
|
+
description: "the 4-value fact liveness the verdict was computed from (R1/R3).",
|
|
92
|
+
}),
|
|
93
|
+
});
|
|
87
94
|
|
|
88
|
-
export const EntwurfV2ReceiptRejectSchema =
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
},
|
|
103
|
-
{ additionalProperties: false },
|
|
104
|
-
);
|
|
95
|
+
export const EntwurfV2ReceiptRejectSchema = closedObject({
|
|
96
|
+
ok: lit(false),
|
|
97
|
+
reason: StringEnum(ENTWURF_V2_REJECT_REASONS),
|
|
98
|
+
// ?6: required-nullable, NOT optional — a reject branch ALWAYS carries the
|
|
99
|
+
// key, and it is `null` for the pre-probe rejects (PRE_PROBE_REJECT_REASONS)
|
|
100
|
+
// and a real FactLiveness otherwise. Optional would lose the "key always
|
|
101
|
+
// present, value may be null" shape and weaken the discriminated union; the
|
|
102
|
+
// reason-dependent null/non-null rule is enforced semantically (the gate's
|
|
103
|
+
// rejectObservedLivenessWellFormed fixture), not by this blanket union.
|
|
104
|
+
observedLiveness: union([StringEnum(FACT_LIVENESSES), nul()], {
|
|
105
|
+
description:
|
|
106
|
+
"the 4-value fact liveness the reject was computed from (R1/R3); null for the pre-probe rejects (bad-target / target-locked / target-address-conflict) where no probe ran.",
|
|
107
|
+
}),
|
|
108
|
+
});
|
|
105
109
|
|
|
106
|
-
export const EntwurfV2ReceiptSchema =
|
|
110
|
+
export const EntwurfV2ReceiptSchema = union([EntwurfV2ReceiptSuccessSchema, EntwurfV2ReceiptRejectSchema]);
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* verb (0.11 Stage 0 step 4-pre / 동결결정 10). PURE pi-FREE core: the
|
|
4
4
|
* intent×liveness decision table + the reject taxonomy + a pure resolver.
|
|
5
5
|
* NO runtime dispatch, NO spawn/send, NO I/O — step 5 wires this to transports.
|
|
6
|
-
* The pi-
|
|
6
|
+
* The pi-schema REPRESENTATION of this contract lives in the separate
|
|
7
7
|
* `entwurf-v2-contract-schema.ts` (0.12.1 B-1) so this module — which the
|
|
8
8
|
* harness-neutral MCP bridge reaches at boot — carries no pi dependency.
|
|
9
9
|
*
|
|
@@ -516,9 +516,9 @@ export function resolveNativePushDispatch(intent: EntwurfIntent, liveness: Nativ
|
|
|
516
516
|
};
|
|
517
517
|
}
|
|
518
518
|
|
|
519
|
-
// ──
|
|
520
|
-
// MOVED to `entwurf-v2-contract-schema.ts` (0.12.1 B-1): the pi
|
|
521
|
-
// builders (StringEnum
|
|
519
|
+
// ── JSON schemas ───────────────────────────────────────────────────────────
|
|
520
|
+
// MOVED to `entwurf-v2-contract-schema.ts` (0.12.1 B-1): the pi schema
|
|
521
|
+
// builders (pi-ai StringEnum, pi-schema since #155) are a pi-lane dependency, so they cannot live in
|
|
522
522
|
// this pi-free core — the MCP bridge reaches this module at boot and must stay
|
|
523
523
|
// harness-neutral (check-entwurf-bridge-pi-free). The schemas import the
|
|
524
524
|
// constants/types above; pi-side consumers import the schemas from there.
|
|
@@ -79,7 +79,7 @@ export function formatMetaMailboxBody(sender: MailboxSenderEnvelope, message: st
|
|
|
79
79
|
// SENDING host, so it is neither abbreviated against this host's HOME nor shown as a local path.
|
|
80
80
|
const remote = !replyable ? sender.remote : undefined;
|
|
81
81
|
const sessionLine = replyable
|
|
82
|
-
? `${sender.sessionId} (${kind}replyable — reply
|
|
82
|
+
? `${sender.sessionId} (${kind}replyable — when a reply is requested, send the result via entwurf_v2 (intent=fire-and-forget) to the requested recipient, defaulting to this sessionId; a local final is not delivery. Honor routing and no-send instructions; an absent or false wants_reply does not cancel a request. A replyable address alone needs no acknowledgment)`
|
|
83
83
|
: remote
|
|
84
84
|
? `${sender.sessionId} (remote via ${remote.via}; ${remote.replyRoute === "declared" ? "reply route declared, not probed" : "no reply route declared"})`
|
|
85
85
|
: isMeta
|
|
@@ -349,7 +349,7 @@ export interface PiDurableRoots {
|
|
|
349
349
|
// ---------------------------------------------------------------------------
|
|
350
350
|
// Durable surface, typed NARROWLY and locally — read at pi-durable 1.0.2 @cd32f77 (#129,
|
|
351
351
|
// `harness/types.ts`; historical coordinates, not re-anchored here). The current supply is the
|
|
352
|
-
// carrier emitted from Entwurf's owned source (pi/pi-durable/src, #141) against the 1.
|
|
352
|
+
// carrier emitted from Entwurf's owned source (pi/pi-durable/src, #141) against the 1.5.2 SDK set
|
|
353
353
|
// `pi/pi-durable/overlay/upstream-pin.json` names (origin `abe508e`). `[read 2026-10-13]` at
|
|
354
354
|
// v1.2.0 one shape typed below moved: `ToolExecutionResult.content` is now `output`, beside the new
|
|
355
355
|
// `structuredOutput` (`harness/types.ts`, its CHANGELOG's breaking changes). An omitted `output`
|