@quandev104/pi-style 0.1.5 → 0.1.6
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 +6 -0
- package/README.md +2 -2
- package/dist/extensions/pi-style.js +240 -243
- package/dist/extensions/pi-style.js.map +1 -1
- package/extension-src/pi-style/domain/config-authorization.ts +6 -3
- package/extension-src/pi-style/pi/compatibility-coordinator.ts +16 -12
- package/extension-src/pi-style/pi/compatibility-probe.ts +296 -254
- package/extension-src/pi-style/pi/index.ts +3 -2
- package/package.json +9 -9
|
@@ -25,142 +25,130 @@ import {
|
|
|
25
25
|
nextGeneration,
|
|
26
26
|
} from "./compatibility-registry.js";
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
export const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
});
|
|
28
|
+
/**
|
|
29
|
+
* Certification is identity-first, never version-pinned: a surface is certified
|
|
30
|
+
* when the runtime method (or class constructor, for additive installs) matches a
|
|
31
|
+
* recorded name/arity/source-fingerprint identity. Pi version strings are
|
|
32
|
+
* informational only (diagnostics, doctor output) and never gate installation — a
|
|
33
|
+
* version drift that preserves the native identity keeps working, and a drift that
|
|
34
|
+
* changes the identity degrades that single surface to its native fallback while
|
|
35
|
+
* every other surface continues.
|
|
36
|
+
*/
|
|
37
|
+
export const SUPPORTED_VERSION_RANGE = ">=0.83.0 <0.85.0";
|
|
38
|
+
export const SUPPORTED_PI_VERSIONS: readonly string[] = Object.freeze(["0.83.0", "0.84.0"]);
|
|
39
|
+
|
|
40
|
+
/** A recorded native identity for one certified surface. */
|
|
41
|
+
export interface KnownNativeIdentity {
|
|
42
|
+
readonly name: string;
|
|
43
|
+
readonly arity: number;
|
|
44
|
+
readonly fingerprint: string;
|
|
45
|
+
/** Pi versions known to carry this exact identity (informational only). */
|
|
46
|
+
readonly versions: readonly string[];
|
|
47
|
+
}
|
|
49
48
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
49
|
+
/**
|
|
50
|
+
* Registry of recorded native identities per surface. A surface matches when the
|
|
51
|
+
* runtime function has the same name, arity, and source fingerprint as one of its
|
|
52
|
+
* identities; the `versions` list only documents where that identity was observed.
|
|
53
|
+
* A matching name/arity/hash is evidence of the shipped native method, not a
|
|
54
|
+
* cryptographic proof: code loaded before this module could spoof the same
|
|
55
|
+
* function source. Unrecorded identities therefore fall back natively per surface.
|
|
56
|
+
*/
|
|
57
|
+
export const KNOWN_NATIVE_IDENTITIES: Readonly<Record<string, readonly KnownNativeIdentity[]>> = Object.freeze({
|
|
58
|
+
"native-assistant-message:render": Object.freeze([
|
|
59
|
+
Object.freeze({
|
|
59
60
|
name: "render",
|
|
60
61
|
arity: 1,
|
|
61
|
-
fingerprint:
|
|
62
|
-
|
|
63
|
-
status: "certified" as const,
|
|
62
|
+
fingerprint: "2a39243f",
|
|
63
|
+
versions: Object.freeze(["0.83.0", "0.84.0"]),
|
|
64
64
|
}),
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
name: "getCallRenderer",
|
|
73
|
-
arity: 0,
|
|
74
|
-
fingerprint: TRUSTED_NATIVE_FINGERPRINTS["tool-call-renderer:getCallRenderer"],
|
|
75
|
-
adapterId: "tool-renderer-component-v1",
|
|
76
|
-
status: "certified" as const,
|
|
77
|
-
}),
|
|
78
|
-
"tool-result-renderer:getResultRenderer": Object.freeze({
|
|
79
|
-
feature: "tools",
|
|
80
|
-
subtype: "tool-result-renderer",
|
|
81
|
-
target: ToolExecutionComponent.prototype,
|
|
82
|
-
method: "getResultRenderer",
|
|
83
|
-
writable: true,
|
|
84
|
-
configurable: true,
|
|
85
|
-
name: "getResultRenderer",
|
|
86
|
-
arity: 0,
|
|
87
|
-
fingerprint: TRUSTED_NATIVE_FINGERPRINTS["tool-result-renderer:getResultRenderer"],
|
|
88
|
-
adapterId: "tool-renderer-component-v1",
|
|
89
|
-
status: "certified" as const,
|
|
65
|
+
]),
|
|
66
|
+
"native-assistant-message:updateContent": Object.freeze([
|
|
67
|
+
Object.freeze({
|
|
68
|
+
name: "updateContent",
|
|
69
|
+
arity: 1,
|
|
70
|
+
fingerprint: "4a2f15ff",
|
|
71
|
+
versions: Object.freeze(["0.83.0"]),
|
|
90
72
|
}),
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
method: "updateContent",
|
|
96
|
-
writable: true,
|
|
97
|
-
configurable: true,
|
|
73
|
+
// 0.84.0 adds an `isStreaming` default parameter and per-part markdown
|
|
74
|
+
// transforms; default parameters do not count toward Function.length, so
|
|
75
|
+
// the arity stays 1 while the source fingerprint changes.
|
|
76
|
+
Object.freeze({
|
|
98
77
|
name: "updateContent",
|
|
99
78
|
arity: 1,
|
|
100
|
-
fingerprint:
|
|
101
|
-
|
|
102
|
-
status: "certified" as const,
|
|
79
|
+
fingerprint: "d2114491",
|
|
80
|
+
versions: Object.freeze(["0.84.0"]),
|
|
103
81
|
}),
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
adapterId: "message-block-boxed-v1",
|
|
112
|
-
status: "certified" as const,
|
|
82
|
+
]),
|
|
83
|
+
"native-compaction-message:updateDisplay": Object.freeze([
|
|
84
|
+
Object.freeze({
|
|
85
|
+
name: "updateDisplay",
|
|
86
|
+
arity: 0,
|
|
87
|
+
fingerprint: "f8c44e78",
|
|
88
|
+
versions: Object.freeze(["0.83.0", "0.84.0"]),
|
|
113
89
|
}),
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
adapterId: "message-block-boxed-v1",
|
|
122
|
-
status: "certified" as const,
|
|
90
|
+
]),
|
|
91
|
+
"native-branch-message:updateDisplay": Object.freeze([
|
|
92
|
+
Object.freeze({
|
|
93
|
+
name: "updateDisplay",
|
|
94
|
+
arity: 0,
|
|
95
|
+
fingerprint: "415d57b7",
|
|
96
|
+
versions: Object.freeze(["0.83.0", "0.84.0"]),
|
|
123
97
|
}),
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
adapterId: "message-block-boxed-v1",
|
|
132
|
-
status: "certified" as const,
|
|
98
|
+
]),
|
|
99
|
+
"native-skill-message:updateDisplay": Object.freeze([
|
|
100
|
+
Object.freeze({
|
|
101
|
+
name: "updateDisplay",
|
|
102
|
+
arity: 0,
|
|
103
|
+
fingerprint: "48099ea6",
|
|
104
|
+
versions: Object.freeze(["0.83.0", "0.84.0"]),
|
|
133
105
|
}),
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
106
|
+
]),
|
|
107
|
+
"native-custom-message:rebuild": Object.freeze([
|
|
108
|
+
Object.freeze({
|
|
109
|
+
name: "rebuild",
|
|
110
|
+
arity: 0,
|
|
111
|
+
fingerprint: "76ae2e3a",
|
|
112
|
+
versions: Object.freeze(["0.83.0", "0.84.0"]),
|
|
113
|
+
}),
|
|
114
|
+
]),
|
|
115
|
+
"tool-call-renderer:getCallRenderer": Object.freeze([
|
|
116
|
+
Object.freeze({
|
|
117
|
+
name: "getCallRenderer",
|
|
118
|
+
arity: 0,
|
|
119
|
+
fingerprint: "951ea0e0",
|
|
120
|
+
versions: Object.freeze(["0.83.0", "0.84.0"]),
|
|
143
121
|
}),
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
122
|
+
]),
|
|
123
|
+
"tool-result-renderer:getResultRenderer": Object.freeze([
|
|
124
|
+
Object.freeze({
|
|
125
|
+
name: "getResultRenderer",
|
|
126
|
+
arity: 0,
|
|
127
|
+
fingerprint: "8a25cd71",
|
|
128
|
+
versions: Object.freeze(["0.83.0", "0.84.0"]),
|
|
129
|
+
}),
|
|
130
|
+
]),
|
|
131
|
+
"native-bash-execution:render": Object.freeze([
|
|
132
|
+
Object.freeze({
|
|
151
133
|
// The additive render patch is certified by the class constructor identity
|
|
152
134
|
// (name/arity/source fingerprint): the class defines no own `render`, so
|
|
153
135
|
// the installed own method is the only one and the inherited Container
|
|
154
136
|
// render is the native fallback.
|
|
155
137
|
name: "BashExecutionComponent",
|
|
156
138
|
arity: 2,
|
|
157
|
-
fingerprint:
|
|
158
|
-
|
|
159
|
-
status: "certified" as const,
|
|
139
|
+
fingerprint: "a5b5abca",
|
|
140
|
+
versions: Object.freeze(["0.83.0", "0.84.0"]),
|
|
160
141
|
}),
|
|
161
|
-
|
|
142
|
+
]),
|
|
162
143
|
});
|
|
163
144
|
|
|
145
|
+
/** Primary (first-recorded) fingerprint per surface, for diagnostics and back-compat. */
|
|
146
|
+
export const TRUSTED_NATIVE_FINGERPRINTS: Readonly<Record<string, string>> = Object.freeze(
|
|
147
|
+
Object.fromEntries(
|
|
148
|
+
Object.entries(KNOWN_NATIVE_IDENTITIES).map(([key, identities]) => [key, identities[0]!.fingerprint]),
|
|
149
|
+
),
|
|
150
|
+
);
|
|
151
|
+
|
|
164
152
|
export interface CompatibilityDescriptorSnapshot {
|
|
165
153
|
readonly kind: "data" | "accessor";
|
|
166
154
|
readonly value?: unknown;
|
|
@@ -185,7 +173,7 @@ export interface CompatibilityRecordSnapshot {
|
|
|
185
173
|
|
|
186
174
|
export interface CompatibilityProbeReport {
|
|
187
175
|
attemptedVersion: string;
|
|
188
|
-
|
|
176
|
+
supportedVersions: readonly string[];
|
|
189
177
|
certificationTable: typeof CERTIFICATION_TABLE;
|
|
190
178
|
piVersion: string;
|
|
191
179
|
versionRange: string;
|
|
@@ -196,9 +184,8 @@ export interface CompatibilityProbeReport {
|
|
|
196
184
|
certification: readonly {
|
|
197
185
|
readonly version: string;
|
|
198
186
|
readonly attemptedVersion: string;
|
|
199
|
-
readonly
|
|
200
|
-
readonly
|
|
201
|
-
readonly actualPreinstall: CompatibilityDescriptorSnapshot | undefined;
|
|
187
|
+
readonly matchedIdentity: KnownNativeIdentity | undefined;
|
|
188
|
+
readonly knownIdentities: readonly KnownNativeIdentity[];
|
|
202
189
|
readonly feature: CompatibilityRecord["feature"];
|
|
203
190
|
readonly subtype: CompatibilityRecord["subtype"];
|
|
204
191
|
readonly target: object;
|
|
@@ -210,6 +197,7 @@ export interface CompatibilityProbeReport {
|
|
|
210
197
|
readonly adapterId: string | undefined;
|
|
211
198
|
readonly status: "certified" | "native-fallback";
|
|
212
199
|
readonly fallbackReason?: string;
|
|
200
|
+
readonly actualPreinstall: CompatibilityDescriptorSnapshot | undefined;
|
|
213
201
|
}[];
|
|
214
202
|
getRuntimeDiagnostics: () => ReadonlyMap<string, number>;
|
|
215
203
|
getFinalDiagnostics: () => Readonly<import("../features/tools/index.js").ToolDiagnosticArchive> | undefined;
|
|
@@ -243,118 +231,38 @@ export function fingerprint(value: unknown): string | undefined {
|
|
|
243
231
|
return hash.toString(16).padStart(8, "0");
|
|
244
232
|
}
|
|
245
233
|
|
|
246
|
-
function
|
|
247
|
-
if (
|
|
234
|
+
function knownIdentityMatches(spec: TargetSpec, value: unknown): KnownNativeIdentity | undefined {
|
|
235
|
+
if (typeof value !== "function") return undefined;
|
|
236
|
+
const hash = fingerprint(value);
|
|
237
|
+
const key = `${spec.subtype}:${spec.method}`;
|
|
238
|
+
return (KNOWN_NATIVE_IDENTITIES[key] ?? []).find(
|
|
239
|
+
(identity) => value.name === identity.name && value.length === identity.arity && hash === identity.fingerprint,
|
|
240
|
+
);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
function matchedNativeIdentity(spec: TargetSpec): KnownNativeIdentity | undefined {
|
|
248
244
|
if (spec.kind === "add-method") {
|
|
249
245
|
// Additive install: the prototype must not already own the method (it is
|
|
250
|
-
// inherited), the class constructor identity must match
|
|
246
|
+
// inherited), the class constructor identity must match a recorded build,
|
|
251
247
|
// and the inherited method becomes the native fallback for the delegate.
|
|
252
248
|
if (Object.getOwnPropertyDescriptor(spec.target, spec.method)) return undefined;
|
|
253
249
|
const ctor = Object.getOwnPropertyDescriptor(spec.target, "constructor")?.value;
|
|
254
|
-
|
|
255
|
-
if (
|
|
256
|
-
typeof ctor !== "function" ||
|
|
257
|
-
ctor.name !== (spec.identityName ?? spec.method) ||
|
|
258
|
-
ctor.length !== (spec.arity ?? 0) ||
|
|
259
|
-
fingerprint(ctor) !== TRUSTED_NATIVE_FINGERPRINTS[key]
|
|
260
|
-
)
|
|
261
|
-
return undefined;
|
|
262
|
-
const inherited = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(spec.target), spec.method)?.value;
|
|
263
|
-
return typeof inherited === "function" ? inherited : undefined;
|
|
250
|
+
return knownIdentityMatches(spec, ctor);
|
|
264
251
|
}
|
|
265
252
|
const descriptor = Object.getOwnPropertyDescriptor(spec.target, spec.method);
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
const expectedArity = spec.arity ?? (spec.method === "render" || spec.method === "updateContent" ? 1 : 0);
|
|
269
|
-
if (
|
|
270
|
-
descriptor?.writable !== true ||
|
|
271
|
-
descriptor.configurable !== true ||
|
|
272
|
-
typeof value !== "function" ||
|
|
273
|
-
value.name !== (spec.identityName ?? spec.method) ||
|
|
274
|
-
value.length !== expectedArity ||
|
|
275
|
-
fingerprint(value) !== TRUSTED_NATIVE_FINGERPRINTS[key]
|
|
276
|
-
)
|
|
277
|
-
return undefined;
|
|
278
|
-
return value;
|
|
253
|
+
if (descriptor?.writable !== true || descriptor.configurable !== true) return undefined;
|
|
254
|
+
return knownIdentityMatches(spec, descriptor.value);
|
|
279
255
|
}
|
|
280
256
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
target
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
{
|
|
291
|
-
feature: "messages",
|
|
292
|
-
subtype: "native-assistant-message",
|
|
293
|
-
target: AssistantMessageComponent.prototype,
|
|
294
|
-
method: "updateContent",
|
|
295
|
-
adapterId: "message-thinking-collapse-v1",
|
|
296
|
-
status: "certified",
|
|
297
|
-
},
|
|
298
|
-
{
|
|
299
|
-
feature: "messages",
|
|
300
|
-
subtype: "native-compaction-message",
|
|
301
|
-
target: CompactionSummaryMessageComponent.prototype,
|
|
302
|
-
method: "updateDisplay",
|
|
303
|
-
adapterId: "message-block-boxed-v1",
|
|
304
|
-
status: "certified",
|
|
305
|
-
},
|
|
306
|
-
{
|
|
307
|
-
feature: "messages",
|
|
308
|
-
subtype: "native-branch-message",
|
|
309
|
-
target: BranchSummaryMessageComponent.prototype,
|
|
310
|
-
method: "updateDisplay",
|
|
311
|
-
adapterId: "message-block-boxed-v1",
|
|
312
|
-
status: "certified",
|
|
313
|
-
},
|
|
314
|
-
{
|
|
315
|
-
feature: "messages",
|
|
316
|
-
subtype: "native-skill-message",
|
|
317
|
-
target: SkillInvocationMessageComponent.prototype,
|
|
318
|
-
method: "updateDisplay",
|
|
319
|
-
adapterId: "message-block-boxed-v1",
|
|
320
|
-
status: "certified",
|
|
321
|
-
},
|
|
322
|
-
{
|
|
323
|
-
feature: "messages",
|
|
324
|
-
subtype: "native-custom-message",
|
|
325
|
-
target: CustomMessageComponent.prototype,
|
|
326
|
-
method: "rebuild",
|
|
327
|
-
adapterId: "message-block-boxed-v1",
|
|
328
|
-
status: "certified",
|
|
329
|
-
},
|
|
330
|
-
{
|
|
331
|
-
feature: "tools",
|
|
332
|
-
subtype: "tool-call-renderer",
|
|
333
|
-
target: ToolExecutionComponent.prototype,
|
|
334
|
-
method: "getCallRenderer",
|
|
335
|
-
adapterId: "tool-renderer-component-v1",
|
|
336
|
-
status: "certified",
|
|
337
|
-
},
|
|
338
|
-
{
|
|
339
|
-
feature: "tools",
|
|
340
|
-
subtype: "tool-result-renderer",
|
|
341
|
-
target: ToolExecutionComponent.prototype,
|
|
342
|
-
method: "getResultRenderer",
|
|
343
|
-
adapterId: "tool-renderer-component-v1",
|
|
344
|
-
status: "certified",
|
|
345
|
-
},
|
|
346
|
-
{
|
|
347
|
-
feature: "tools",
|
|
348
|
-
subtype: "native-bash-execution",
|
|
349
|
-
target: BashExecutionComponent.prototype,
|
|
350
|
-
method: "render",
|
|
351
|
-
kind: "add-method",
|
|
352
|
-
identityName: "BashExecutionComponent",
|
|
353
|
-
arity: 2,
|
|
354
|
-
adapterId: "bash-execution-box-v1",
|
|
355
|
-
status: "certified",
|
|
356
|
-
},
|
|
357
|
-
];
|
|
257
|
+
function trustedNativeIdentity(spec: TargetSpec): unknown {
|
|
258
|
+
const identity = matchedNativeIdentity(spec);
|
|
259
|
+
if (!identity) return undefined;
|
|
260
|
+
if (spec.kind === "add-method") {
|
|
261
|
+
const inherited = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(spec.target), spec.method)?.value;
|
|
262
|
+
return typeof inherited === "function" ? inherited : undefined;
|
|
263
|
+
}
|
|
264
|
+
return Object.getOwnPropertyDescriptor(spec.target, spec.method)?.value;
|
|
265
|
+
}
|
|
358
266
|
|
|
359
267
|
export interface PiVersionResolution {
|
|
360
268
|
resolvePackageEntry?: (packageName: string) => string;
|
|
@@ -426,6 +334,7 @@ function descriptorSnapshot(descriptor: PropertyDescriptor | undefined): Compati
|
|
|
426
334
|
function certificationRecord(
|
|
427
335
|
spec: TargetSpec,
|
|
428
336
|
attemptedVersion: string | undefined,
|
|
337
|
+
matchedIdentity: KnownNativeIdentity | undefined,
|
|
429
338
|
evidence = Object.getOwnPropertyDescriptor(spec.target, spec.method),
|
|
430
339
|
) {
|
|
431
340
|
const descriptor = evidence;
|
|
@@ -433,9 +342,8 @@ function certificationRecord(
|
|
|
433
342
|
return {
|
|
434
343
|
version: attemptedVersion ?? "unknown",
|
|
435
344
|
attemptedVersion: attemptedVersion ?? "unknown",
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
actualPreinstall: descriptorSnapshot(descriptor),
|
|
345
|
+
matchedIdentity,
|
|
346
|
+
knownIdentities: KNOWN_NATIVE_IDENTITIES[`${spec.subtype}:${spec.method}`] ?? [],
|
|
439
347
|
feature: spec.feature,
|
|
440
348
|
subtype: spec.subtype,
|
|
441
349
|
target: spec.target,
|
|
@@ -450,10 +358,6 @@ function certificationRecord(
|
|
|
450
358
|
};
|
|
451
359
|
}
|
|
452
360
|
|
|
453
|
-
function versionInRange(version: string | undefined): boolean {
|
|
454
|
-
return version === TRUSTED_PI_VERSION;
|
|
455
|
-
}
|
|
456
|
-
|
|
457
361
|
function shape(spec: TargetSpec): boolean {
|
|
458
362
|
const descriptor = Object.getOwnPropertyDescriptor(spec.target, spec.method);
|
|
459
363
|
// Additive installs need an unowned slot (the method is inherited); every
|
|
@@ -491,7 +395,7 @@ function createFallbackRecord(
|
|
|
491
395
|
method: spec.method,
|
|
492
396
|
originalIdentity: Reflect.get(spec.target, spec.method),
|
|
493
397
|
piVersion: piVersion ?? "unknown",
|
|
494
|
-
versionRange:
|
|
398
|
+
versionRange: SUPPORTED_VERSION_RANGE,
|
|
495
399
|
shape: "unsupported",
|
|
496
400
|
diagnostic: reason,
|
|
497
401
|
generation,
|
|
@@ -500,10 +404,10 @@ function createFallbackRecord(
|
|
|
500
404
|
};
|
|
501
405
|
}
|
|
502
406
|
|
|
503
|
-
function probeDiagnostic(spec: TargetSpec,
|
|
504
|
-
if (!versionInRange(piVersion)) return "Pi version is unknown or outside the recorded 0.83.0 support build";
|
|
407
|
+
function probeDiagnostic(spec: TargetSpec, identity: unknown): string {
|
|
505
408
|
if (!shape(spec)) return "target method shape is not an own writable/configurable function";
|
|
506
|
-
if (identity === undefined)
|
|
409
|
+
if (identity === undefined)
|
|
410
|
+
return "runtime native identity (name, arity, or source fingerprint) matched no recorded Pi surface";
|
|
507
411
|
return "exact native identity verified; certified guarded decoration enabled";
|
|
508
412
|
}
|
|
509
413
|
|
|
@@ -528,8 +432,8 @@ function probeSpec(options: {
|
|
|
528
432
|
toolOwner: ReturnType<typeof createToolDecorationOwner> | undefined;
|
|
529
433
|
}) {
|
|
530
434
|
const { spec, piVersion, generation, markers, config, toolOwner, messageSnapshot } = options;
|
|
531
|
-
const identity = trustedNativeIdentity(spec
|
|
532
|
-
const diagnostic = probeDiagnostic(spec,
|
|
435
|
+
const identity = trustedNativeIdentity(spec);
|
|
436
|
+
const diagnostic = probeDiagnostic(spec, identity);
|
|
533
437
|
const disabled = surfaceDisabled(spec, config);
|
|
534
438
|
if (disabled) {
|
|
535
439
|
const reason = "native fallback: surface disabled by normalized configuration";
|
|
@@ -541,8 +445,8 @@ function probeSpec(options: {
|
|
|
541
445
|
target: spec.target,
|
|
542
446
|
method: spec.method,
|
|
543
447
|
piVersion: piVersion ?? "unknown",
|
|
544
|
-
versionRange:
|
|
545
|
-
shape: identity !== undefined &&
|
|
448
|
+
versionRange: SUPPORTED_VERSION_RANGE,
|
|
449
|
+
shape: identity !== undefined && shape(spec),
|
|
546
450
|
generation,
|
|
547
451
|
expectedIdentity: identity,
|
|
548
452
|
hasExpectedIdentity: true,
|
|
@@ -578,6 +482,153 @@ function probeSpec(options: {
|
|
|
578
482
|
};
|
|
579
483
|
}
|
|
580
484
|
|
|
485
|
+
export const targetSpecs: readonly TargetSpec[] = [
|
|
486
|
+
{
|
|
487
|
+
feature: "messages",
|
|
488
|
+
subtype: "native-assistant-message",
|
|
489
|
+
target: AssistantMessageComponent.prototype,
|
|
490
|
+
method: "render",
|
|
491
|
+
adapterId: "message-prefix-osc133-v1",
|
|
492
|
+
status: "certified",
|
|
493
|
+
},
|
|
494
|
+
{
|
|
495
|
+
feature: "messages",
|
|
496
|
+
subtype: "native-assistant-message",
|
|
497
|
+
target: AssistantMessageComponent.prototype,
|
|
498
|
+
method: "updateContent",
|
|
499
|
+
adapterId: "message-thinking-collapse-v1",
|
|
500
|
+
status: "certified",
|
|
501
|
+
},
|
|
502
|
+
{
|
|
503
|
+
feature: "messages",
|
|
504
|
+
subtype: "native-compaction-message",
|
|
505
|
+
target: CompactionSummaryMessageComponent.prototype,
|
|
506
|
+
method: "updateDisplay",
|
|
507
|
+
adapterId: "message-block-boxed-v1",
|
|
508
|
+
status: "certified",
|
|
509
|
+
},
|
|
510
|
+
{
|
|
511
|
+
feature: "messages",
|
|
512
|
+
subtype: "native-branch-message",
|
|
513
|
+
target: BranchSummaryMessageComponent.prototype,
|
|
514
|
+
method: "updateDisplay",
|
|
515
|
+
adapterId: "message-block-boxed-v1",
|
|
516
|
+
status: "certified",
|
|
517
|
+
},
|
|
518
|
+
{
|
|
519
|
+
feature: "messages",
|
|
520
|
+
subtype: "native-skill-message",
|
|
521
|
+
target: SkillInvocationMessageComponent.prototype,
|
|
522
|
+
method: "updateDisplay",
|
|
523
|
+
adapterId: "message-block-boxed-v1",
|
|
524
|
+
status: "certified",
|
|
525
|
+
},
|
|
526
|
+
{
|
|
527
|
+
feature: "messages",
|
|
528
|
+
subtype: "native-custom-message",
|
|
529
|
+
target: CustomMessageComponent.prototype,
|
|
530
|
+
method: "rebuild",
|
|
531
|
+
adapterId: "message-block-boxed-v1",
|
|
532
|
+
status: "certified",
|
|
533
|
+
},
|
|
534
|
+
{
|
|
535
|
+
feature: "tools",
|
|
536
|
+
subtype: "tool-call-renderer",
|
|
537
|
+
target: ToolExecutionComponent.prototype,
|
|
538
|
+
method: "getCallRenderer",
|
|
539
|
+
adapterId: "tool-renderer-component-v1",
|
|
540
|
+
status: "certified",
|
|
541
|
+
},
|
|
542
|
+
{
|
|
543
|
+
feature: "tools",
|
|
544
|
+
subtype: "tool-result-renderer",
|
|
545
|
+
target: ToolExecutionComponent.prototype,
|
|
546
|
+
method: "getResultRenderer",
|
|
547
|
+
adapterId: "tool-renderer-component-v1",
|
|
548
|
+
status: "certified",
|
|
549
|
+
},
|
|
550
|
+
{
|
|
551
|
+
feature: "tools",
|
|
552
|
+
subtype: "native-bash-execution",
|
|
553
|
+
target: BashExecutionComponent.prototype,
|
|
554
|
+
method: "render",
|
|
555
|
+
kind: "add-method",
|
|
556
|
+
identityName: "BashExecutionComponent",
|
|
557
|
+
arity: 2,
|
|
558
|
+
adapterId: "bash-execution-box-v1",
|
|
559
|
+
status: "certified",
|
|
560
|
+
},
|
|
561
|
+
];
|
|
562
|
+
|
|
563
|
+
/**
|
|
564
|
+
* Version → surface → recorded certified identity (informational). Certification
|
|
565
|
+
* itself is decided per-surface by the runtime identity; this table only documents
|
|
566
|
+
* which identity each supported Pi version is known to carry.
|
|
567
|
+
*/
|
|
568
|
+
export const CERTIFICATION_TABLE: Readonly<
|
|
569
|
+
Record<
|
|
570
|
+
string,
|
|
571
|
+
Readonly<
|
|
572
|
+
Record<
|
|
573
|
+
string,
|
|
574
|
+
Readonly<{
|
|
575
|
+
feature: CompatibilityRecord["feature"];
|
|
576
|
+
subtype: CompatibilityRecord["subtype"];
|
|
577
|
+
target: object;
|
|
578
|
+
method: string;
|
|
579
|
+
writable: boolean;
|
|
580
|
+
configurable: boolean;
|
|
581
|
+
name: string;
|
|
582
|
+
arity: number;
|
|
583
|
+
fingerprint: string;
|
|
584
|
+
adapterId: string | undefined;
|
|
585
|
+
status: "certified";
|
|
586
|
+
}>
|
|
587
|
+
>
|
|
588
|
+
>
|
|
589
|
+
>
|
|
590
|
+
> = Object.freeze(
|
|
591
|
+
Object.fromEntries(
|
|
592
|
+
SUPPORTED_PI_VERSIONS.map((version) => [
|
|
593
|
+
version,
|
|
594
|
+
Object.freeze(
|
|
595
|
+
Object.fromEntries(
|
|
596
|
+
targetSpecs.flatMap((spec) => {
|
|
597
|
+
const key = `${spec.subtype}:${spec.method}`;
|
|
598
|
+
const identity = (KNOWN_NATIVE_IDENTITIES[key] ?? []).find((candidate) =>
|
|
599
|
+
candidate.versions.includes(version),
|
|
600
|
+
);
|
|
601
|
+
if (!identity) return [];
|
|
602
|
+
return [
|
|
603
|
+
[
|
|
604
|
+
key,
|
|
605
|
+
Object.freeze({
|
|
606
|
+
feature: spec.feature,
|
|
607
|
+
subtype: spec.subtype,
|
|
608
|
+
target: spec.target,
|
|
609
|
+
method: spec.method,
|
|
610
|
+
writable: true,
|
|
611
|
+
configurable: true,
|
|
612
|
+
name: identity.name,
|
|
613
|
+
arity: identity.arity,
|
|
614
|
+
fingerprint: identity.fingerprint,
|
|
615
|
+
adapterId: spec.adapterId,
|
|
616
|
+
status: "certified" as const,
|
|
617
|
+
}),
|
|
618
|
+
],
|
|
619
|
+
];
|
|
620
|
+
}),
|
|
621
|
+
),
|
|
622
|
+
),
|
|
623
|
+
]),
|
|
624
|
+
),
|
|
625
|
+
);
|
|
626
|
+
|
|
627
|
+
const reportStates = new WeakMap<
|
|
628
|
+
object,
|
|
629
|
+
{ records: CompatibilityRecord[]; toolOwner: ReturnType<typeof createToolDecorationOwner> | undefined }
|
|
630
|
+
>();
|
|
631
|
+
|
|
581
632
|
export function probePiCompatibility(
|
|
582
633
|
piVersion: string | undefined,
|
|
583
634
|
options: Set<string> | CompatibilityProbeOptions = new Set(),
|
|
@@ -587,7 +638,7 @@ export function probePiCompatibility(
|
|
|
587
638
|
const toolSpecs = targetSpecs.filter((spec) => spec.feature === "tools");
|
|
588
639
|
let toolOwner: ReturnType<typeof createToolDecorationOwner> | undefined;
|
|
589
640
|
if (
|
|
590
|
-
toolSpecs.some((spec) => trustedNativeIdentity(spec
|
|
641
|
+
toolSpecs.some((spec) => trustedNativeIdentity(spec) !== undefined) &&
|
|
591
642
|
(options instanceof Set || options.config?.tools.enabled !== false)
|
|
592
643
|
) {
|
|
593
644
|
toolOwner = createToolDecorationOwner(options instanceof Set ? {} : options.toolSnapshot);
|
|
@@ -610,6 +661,9 @@ export function probePiCompatibility(
|
|
|
610
661
|
for (const spec of targetSpecs) {
|
|
611
662
|
const captured = evidenceByKey.get(`${spec.subtype}:${String(spec.method)}`);
|
|
612
663
|
const preinstallDescriptor = captured?.descriptor;
|
|
664
|
+
// Captured before install: the runtime identity is still the pristine native
|
|
665
|
+
// method (or class constructor for additive installs) at this point.
|
|
666
|
+
const matchedIdentity = matchedNativeIdentity(spec);
|
|
613
667
|
const result = probeSpec({
|
|
614
668
|
messageSnapshot: options instanceof Set ? undefined : options.messageSnapshot,
|
|
615
669
|
spec,
|
|
@@ -620,15 +674,10 @@ export function probePiCompatibility(
|
|
|
620
674
|
toolOwner,
|
|
621
675
|
});
|
|
622
676
|
records.push(result.record);
|
|
623
|
-
const certificate = certificationRecord(spec, piVersion, preinstallDescriptor);
|
|
677
|
+
const certificate = certificationRecord(spec, piVersion, matchedIdentity, preinstallDescriptor);
|
|
624
678
|
certification.push({
|
|
625
679
|
...certificate,
|
|
626
680
|
attemptedVersion: piVersion ?? "unknown",
|
|
627
|
-
matchedCertifiedVersion: piVersion === TRUSTED_PI_VERSION ? TRUSTED_PI_VERSION : undefined,
|
|
628
|
-
expected:
|
|
629
|
-
CERTIFICATION_TABLE[TRUSTED_PI_VERSION][
|
|
630
|
-
`${spec.subtype}:${spec.method}` as keyof (typeof CERTIFICATION_TABLE)["0.83.0"]
|
|
631
|
-
],
|
|
632
681
|
actualPreinstall: descriptorSnapshot(preinstallDescriptor),
|
|
633
682
|
status: result.fallback ? "native-fallback" : "certified",
|
|
634
683
|
...(result.fallback ? { fallbackReason: result.reason } : {}),
|
|
@@ -637,10 +686,10 @@ export function probePiCompatibility(
|
|
|
637
686
|
}
|
|
638
687
|
const report: CompatibilityProbeReport = {
|
|
639
688
|
attemptedVersion: piVersion ?? "unknown",
|
|
640
|
-
|
|
689
|
+
supportedVersions: SUPPORTED_PI_VERSIONS,
|
|
641
690
|
certificationTable: CERTIFICATION_TABLE,
|
|
642
691
|
piVersion: piVersion ?? "unknown",
|
|
643
|
-
versionRange:
|
|
692
|
+
versionRange: SUPPORTED_VERSION_RANGE,
|
|
644
693
|
generation: currentGeneration(),
|
|
645
694
|
recordSnapshots: Object.freeze(
|
|
646
695
|
records.map((record) =>
|
|
@@ -659,14 +708,7 @@ export function probePiCompatibility(
|
|
|
659
708
|
),
|
|
660
709
|
unsupported: Object.freeze(unsupported.map((item) => Object.freeze({ ...item }))),
|
|
661
710
|
delegationMarkers: Object.freeze([...markers]),
|
|
662
|
-
certification: Object.freeze(
|
|
663
|
-
certification.map((item) =>
|
|
664
|
-
Object.freeze({
|
|
665
|
-
...item,
|
|
666
|
-
actualPreinstall: item.actualPreinstall,
|
|
667
|
-
}),
|
|
668
|
-
),
|
|
669
|
-
),
|
|
711
|
+
certification: Object.freeze(certification.map((item) => Object.freeze({ ...item }))),
|
|
670
712
|
getRuntimeDiagnostics: () => toolOwner?.getDiagnostics() ?? new Map(),
|
|
671
713
|
getFinalDiagnostics: () => toolOwner?.getFinalArchive(),
|
|
672
714
|
getActiveToolRecordCount: () => toolOwner?.getActiveRecordCount() ?? 0,
|