@contractspec/lib.surface-runtime 0.2.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/README.md +164 -0
- package/dist/adapters/ai-sdk-stub.d.ts +5 -0
- package/dist/adapters/ai-sdk-stub.js +13 -0
- package/dist/adapters/blocknote-stub.d.ts +6 -0
- package/dist/adapters/blocknote-stub.js +31 -0
- package/dist/adapters/dnd-kit-adapter.d.ts +13 -0
- package/dist/adapters/dnd-kit-adapter.js +44 -0
- package/dist/adapters/dnd-kit-stub.d.ts +6 -0
- package/dist/adapters/dnd-kit-stub.js +8 -0
- package/dist/adapters/floating-ui-stub.d.ts +6 -0
- package/dist/adapters/floating-ui-stub.js +19 -0
- package/dist/adapters/index.d.ts +11 -0
- package/dist/adapters/index.js +176 -0
- package/dist/adapters/interfaces.d.ts +75 -0
- package/dist/adapters/interfaces.js +1 -0
- package/dist/adapters/motion-stub.d.ts +7 -0
- package/dist/adapters/motion-stub.js +27 -0
- package/dist/adapters/motion-stub.test.d.ts +1 -0
- package/dist/adapters/resizable-panels-stub.d.ts +6 -0
- package/dist/adapters/resizable-panels-stub.js +46 -0
- package/dist/adapters/resizable-panels-stub.test.d.ts +1 -0
- package/dist/browser/adapters/ai-sdk-stub.js +12 -0
- package/dist/browser/adapters/blocknote-stub.js +30 -0
- package/dist/browser/adapters/dnd-kit-adapter.js +43 -0
- package/dist/browser/adapters/dnd-kit-stub.js +7 -0
- package/dist/browser/adapters/floating-ui-stub.js +18 -0
- package/dist/browser/adapters/index.js +175 -0
- package/dist/browser/adapters/interfaces.js +0 -0
- package/dist/browser/adapters/motion-stub.js +26 -0
- package/dist/browser/adapters/resizable-panels-stub.js +45 -0
- package/dist/browser/evals/golden-context.js +0 -0
- package/dist/browser/evals/golden-harness.js +848 -0
- package/dist/browser/examples/pm-workbench.bundle.js +476 -0
- package/dist/browser/i18n/catalogs/en.js +71 -0
- package/dist/browser/i18n/catalogs/es.js +32 -0
- package/dist/browser/i18n/catalogs/fr.js +32 -0
- package/dist/browser/i18n/catalogs/index.js +133 -0
- package/dist/browser/i18n/index.js +173 -0
- package/dist/browser/i18n/keys.js +19 -0
- package/dist/browser/i18n/messages.js +143 -0
- package/dist/browser/index.js +2466 -0
- package/dist/browser/react/BundleProvider.js +47 -0
- package/dist/browser/react/BundleRenderer.js +726 -0
- package/dist/browser/react/OverlayConflictResolver.js +255 -0
- package/dist/browser/react/PatchProposalCard.js +255 -0
- package/dist/browser/react/RegionRenderer.js +128 -0
- package/dist/browser/react/SlotRenderer.js +118 -0
- package/dist/browser/react/WidgetPalette.js +59 -0
- package/dist/browser/react/index.js +792 -0
- package/dist/browser/runtime/apply-surface-patch.js +322 -0
- package/dist/browser/runtime/audit-events.js +137 -0
- package/dist/browser/runtime/build-context.js +55 -0
- package/dist/browser/runtime/extension-registry.js +58 -0
- package/dist/browser/runtime/field-renderer-registry.js +145 -0
- package/dist/browser/runtime/index.js +1496 -0
- package/dist/browser/runtime/overlay-alignment.js +83 -0
- package/dist/browser/runtime/overlay-signer.js +15 -0
- package/dist/browser/runtime/override-store.js +52 -0
- package/dist/browser/runtime/planner-prompt.js +67 -0
- package/dist/browser/runtime/planner-tools.js +77 -0
- package/dist/browser/runtime/policy-eval.js +155 -0
- package/dist/browser/runtime/preference-adapter.js +67 -0
- package/dist/browser/runtime/resolve-bundle.js +767 -0
- package/dist/browser/runtime/resolve-preferences.js +59 -0
- package/dist/browser/runtime/rollback.js +347 -0
- package/dist/browser/runtime/widget-registry.js +36 -0
- package/dist/browser/spec/define-module-bundle.js +113 -0
- package/dist/browser/spec/index.js +319 -0
- package/dist/browser/spec/types.js +0 -0
- package/dist/browser/spec/validate-bundle.js +65 -0
- package/dist/browser/spec/validate-surface-patch.js +206 -0
- package/dist/browser/spec/verification-snapshot-types.js +0 -0
- package/dist/browser/telemetry/index.js +20 -0
- package/dist/browser/telemetry/surface-metrics.js +20 -0
- package/dist/evals/golden-context.d.ts +24 -0
- package/dist/evals/golden-context.js +1 -0
- package/dist/evals/golden-harness.d.ts +29 -0
- package/dist/evals/golden-harness.js +849 -0
- package/dist/evals/golden-harness.test.d.ts +1 -0
- package/dist/examples/pm-workbench.bundle.d.ts +177 -0
- package/dist/examples/pm-workbench.bundle.js +477 -0
- package/dist/i18n/catalogs/en.d.ts +1 -0
- package/dist/i18n/catalogs/en.js +72 -0
- package/dist/i18n/catalogs/es.d.ts +1 -0
- package/dist/i18n/catalogs/es.js +33 -0
- package/dist/i18n/catalogs/fr.d.ts +1 -0
- package/dist/i18n/catalogs/fr.js +33 -0
- package/dist/i18n/catalogs/index.d.ts +3 -0
- package/dist/i18n/catalogs/index.js +134 -0
- package/dist/i18n/index.d.ts +5 -0
- package/dist/i18n/index.js +174 -0
- package/dist/i18n/keys.d.ts +20 -0
- package/dist/i18n/keys.js +20 -0
- package/dist/i18n/messages.d.ts +5 -0
- package/dist/i18n/messages.js +144 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +2467 -0
- package/dist/node/adapters/ai-sdk-stub.js +12 -0
- package/dist/node/adapters/blocknote-stub.js +30 -0
- package/dist/node/adapters/dnd-kit-adapter.js +43 -0
- package/dist/node/adapters/dnd-kit-stub.js +7 -0
- package/dist/node/adapters/floating-ui-stub.js +18 -0
- package/dist/node/adapters/index.js +175 -0
- package/dist/node/adapters/interfaces.js +0 -0
- package/dist/node/adapters/motion-stub.js +26 -0
- package/dist/node/adapters/resizable-panels-stub.js +45 -0
- package/dist/node/evals/golden-context.js +0 -0
- package/dist/node/evals/golden-harness.js +848 -0
- package/dist/node/examples/pm-workbench.bundle.js +476 -0
- package/dist/node/i18n/catalogs/en.js +71 -0
- package/dist/node/i18n/catalogs/es.js +32 -0
- package/dist/node/i18n/catalogs/fr.js +32 -0
- package/dist/node/i18n/catalogs/index.js +133 -0
- package/dist/node/i18n/index.js +173 -0
- package/dist/node/i18n/keys.js +19 -0
- package/dist/node/i18n/messages.js +143 -0
- package/dist/node/index.js +2466 -0
- package/dist/node/react/BundleProvider.js +47 -0
- package/dist/node/react/BundleRenderer.js +726 -0
- package/dist/node/react/OverlayConflictResolver.js +255 -0
- package/dist/node/react/PatchProposalCard.js +255 -0
- package/dist/node/react/RegionRenderer.js +128 -0
- package/dist/node/react/SlotRenderer.js +118 -0
- package/dist/node/react/WidgetPalette.js +59 -0
- package/dist/node/react/index.js +792 -0
- package/dist/node/runtime/apply-surface-patch.js +322 -0
- package/dist/node/runtime/audit-events.js +137 -0
- package/dist/node/runtime/build-context.js +55 -0
- package/dist/node/runtime/extension-registry.js +58 -0
- package/dist/node/runtime/field-renderer-registry.js +145 -0
- package/dist/node/runtime/index.js +1496 -0
- package/dist/node/runtime/overlay-alignment.js +83 -0
- package/dist/node/runtime/overlay-signer.js +15 -0
- package/dist/node/runtime/override-store.js +52 -0
- package/dist/node/runtime/planner-prompt.js +67 -0
- package/dist/node/runtime/planner-tools.js +77 -0
- package/dist/node/runtime/policy-eval.js +155 -0
- package/dist/node/runtime/preference-adapter.js +67 -0
- package/dist/node/runtime/resolve-bundle.js +767 -0
- package/dist/node/runtime/resolve-preferences.js +59 -0
- package/dist/node/runtime/rollback.js +347 -0
- package/dist/node/runtime/widget-registry.js +36 -0
- package/dist/node/spec/define-module-bundle.js +113 -0
- package/dist/node/spec/index.js +319 -0
- package/dist/node/spec/types.js +0 -0
- package/dist/node/spec/validate-bundle.js +65 -0
- package/dist/node/spec/validate-surface-patch.js +206 -0
- package/dist/node/spec/verification-snapshot-types.js +0 -0
- package/dist/node/telemetry/index.js +20 -0
- package/dist/node/telemetry/surface-metrics.js +20 -0
- package/dist/react/BundleProvider.d.ts +13 -0
- package/dist/react/BundleProvider.js +48 -0
- package/dist/react/BundleRenderer.d.ts +22 -0
- package/dist/react/BundleRenderer.js +727 -0
- package/dist/react/OverlayConflictResolver.d.ts +15 -0
- package/dist/react/OverlayConflictResolver.js +256 -0
- package/dist/react/PatchProposalCard.d.ts +13 -0
- package/dist/react/PatchProposalCard.js +256 -0
- package/dist/react/RegionRenderer.d.ts +13 -0
- package/dist/react/RegionRenderer.js +129 -0
- package/dist/react/SlotRenderer.d.ts +13 -0
- package/dist/react/SlotRenderer.js +119 -0
- package/dist/react/WidgetPalette.d.ts +12 -0
- package/dist/react/WidgetPalette.js +60 -0
- package/dist/react/index.d.ts +7 -0
- package/dist/react/index.js +793 -0
- package/dist/runtime/apply-surface-patch.d.ts +15 -0
- package/dist/runtime/apply-surface-patch.js +323 -0
- package/dist/runtime/apply-surface-patch.test.d.ts +1 -0
- package/dist/runtime/audit-events.d.ts +70 -0
- package/dist/runtime/audit-events.js +138 -0
- package/dist/runtime/audit-events.test.d.ts +1 -0
- package/dist/runtime/build-context.d.ts +9 -0
- package/dist/runtime/build-context.js +56 -0
- package/dist/runtime/extension-registry.d.ts +39 -0
- package/dist/runtime/extension-registry.js +59 -0
- package/dist/runtime/field-renderer-registry.d.ts +23 -0
- package/dist/runtime/field-renderer-registry.js +146 -0
- package/dist/runtime/field-renderer-registry.test.d.ts +1 -0
- package/dist/runtime/index.d.ts +16 -0
- package/dist/runtime/index.js +1497 -0
- package/dist/runtime/overlay-alignment.d.ts +49 -0
- package/dist/runtime/overlay-alignment.js +84 -0
- package/dist/runtime/overlay-alignment.test.d.ts +1 -0
- package/dist/runtime/overlay-signer.d.ts +15 -0
- package/dist/runtime/overlay-signer.js +16 -0
- package/dist/runtime/override-store.d.ts +44 -0
- package/dist/runtime/override-store.js +53 -0
- package/dist/runtime/override-store.test.d.ts +1 -0
- package/dist/runtime/planner-prompt.d.ts +39 -0
- package/dist/runtime/planner-prompt.js +68 -0
- package/dist/runtime/planner-prompt.test.d.ts +1 -0
- package/dist/runtime/planner-tools.d.ts +106 -0
- package/dist/runtime/planner-tools.js +78 -0
- package/dist/runtime/planner-tools.test.d.ts +1 -0
- package/dist/runtime/policy-eval.d.ts +23 -0
- package/dist/runtime/policy-eval.js +156 -0
- package/dist/runtime/preference-adapter.d.ts +6 -0
- package/dist/runtime/preference-adapter.js +68 -0
- package/dist/runtime/resolve-bundle.d.ts +68 -0
- package/dist/runtime/resolve-bundle.js +768 -0
- package/dist/runtime/resolve-bundle.test.d.ts +1 -0
- package/dist/runtime/resolve-preferences.d.ts +9 -0
- package/dist/runtime/resolve-preferences.js +60 -0
- package/dist/runtime/resolve-preferences.test.d.ts +1 -0
- package/dist/runtime/rollback.d.ts +21 -0
- package/dist/runtime/rollback.js +348 -0
- package/dist/runtime/rollback.test.d.ts +1 -0
- package/dist/runtime/widget-registry.d.ts +26 -0
- package/dist/runtime/widget-registry.js +37 -0
- package/dist/runtime/widget-registry.test.d.ts +1 -0
- package/dist/spec/define-module-bundle.d.ts +17 -0
- package/dist/spec/define-module-bundle.js +114 -0
- package/dist/spec/define-module-bundle.test.d.ts +1 -0
- package/dist/spec/index.d.ts +5 -0
- package/dist/spec/index.js +320 -0
- package/dist/spec/types.d.ts +494 -0
- package/dist/spec/types.js +1 -0
- package/dist/spec/validate-bundle.d.ts +23 -0
- package/dist/spec/validate-bundle.js +66 -0
- package/dist/spec/validate-bundle.test.d.ts +1 -0
- package/dist/spec/validate-surface-patch.d.ts +39 -0
- package/dist/spec/validate-surface-patch.js +207 -0
- package/dist/spec/validate-surface-patch.test.d.ts +1 -0
- package/dist/spec/verification-snapshot-types.d.ts +23 -0
- package/dist/spec/verification-snapshot-types.js +1 -0
- package/dist/spec/verification-snapshot.test.d.ts +5 -0
- package/dist/telemetry/index.d.ts +5 -0
- package/dist/telemetry/index.js +21 -0
- package/dist/telemetry/surface-metrics.d.ts +17 -0
- package/dist/telemetry/surface-metrics.js +21 -0
- package/package.json +920 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Overlay alignment: maps surface runtime types to lib.overlay-engine.
|
|
3
|
+
* Aligns with 09_extension_and_override_model.md.
|
|
4
|
+
*
|
|
5
|
+
* OverlayTargetRef: capability, workflow, dataView, presentation, operation.
|
|
6
|
+
* OverlayRenderableField: key, label, visible, required, helpText, defaultValue, order.
|
|
7
|
+
* OverlayScopeContext: tenantId, role, userId, device, tags.
|
|
8
|
+
*/
|
|
9
|
+
import type { OverlayTargetRef, OverlayScopeContext, OverlayAppliesTo, SignedOverlaySpec } from '@contractspec/lib.overlay-engine/spec';
|
|
10
|
+
import type { OverlayRenderableField } from '@contractspec/lib.overlay-engine/types';
|
|
11
|
+
import type { BundleContext, ResolvedField, BundleScope } from '../spec/types';
|
|
12
|
+
/** Surface-specific target ref extensions for overlay matching. */
|
|
13
|
+
export interface SurfaceOverlayTargetRef extends OverlayTargetRef {
|
|
14
|
+
/** Bundle key (e.g. "workspace.pm"). */
|
|
15
|
+
bundleKey?: string;
|
|
16
|
+
/** Surface ID (e.g. "issue-detail"). */
|
|
17
|
+
surfaceId?: string;
|
|
18
|
+
/** Route ID (e.g. "issue-detail"). */
|
|
19
|
+
routeId?: string;
|
|
20
|
+
/** Entity type when targeting entity surfaces (e.g. "pm.issue"). */
|
|
21
|
+
entityType?: string;
|
|
22
|
+
}
|
|
23
|
+
/** Build OverlayScopeContext from BundleContext. */
|
|
24
|
+
export declare function toOverlayScopeContext(ctx: BundleContext): OverlayScopeContext;
|
|
25
|
+
/** Build OverlayTargetRef from BundleContext and surface target. */
|
|
26
|
+
export declare function toOverlayTargetRef(_ctx: BundleContext, target: {
|
|
27
|
+
bundleKey?: string;
|
|
28
|
+
surfaceId?: string;
|
|
29
|
+
routeId?: string;
|
|
30
|
+
entityType?: string;
|
|
31
|
+
}): SurfaceOverlayTargetRef;
|
|
32
|
+
/** Build OverlayAppliesTo for surface overlays. */
|
|
33
|
+
export declare function toOverlayAppliesTo(ctx: BundleContext, target: SurfaceOverlayTargetRef, scope: BundleScope): OverlayAppliesTo;
|
|
34
|
+
/** Map ResolvedField to OverlayRenderableField. */
|
|
35
|
+
export declare function toOverlayRenderableField(field: ResolvedField): OverlayRenderableField;
|
|
36
|
+
/** Map OverlayRenderableField back to partial ResolvedField (for merge result). */
|
|
37
|
+
export declare function fromOverlayRenderableField(overlay: OverlayRenderableField): Partial<ResolvedField>;
|
|
38
|
+
/** Convert ResolvedEntitySchema fields to OverlayRenderable for overlay-engine merger. */
|
|
39
|
+
export declare function toOverlayRenderable(fields: ResolvedField[]): {
|
|
40
|
+
fields: OverlayRenderableField[];
|
|
41
|
+
};
|
|
42
|
+
/** Apply overlay-engine merger result back to ResolvedField[]. */
|
|
43
|
+
export declare function mergeOverlayResultIntoFields(fields: ResolvedField[], merged: {
|
|
44
|
+
fields: OverlayRenderableField[];
|
|
45
|
+
}): ResolvedField[];
|
|
46
|
+
/** Apply overlay-engine merger to entity fields. Returns merged ResolvedField[]. */
|
|
47
|
+
export declare function applyEntityFieldOverlays(fields: ResolvedField[], overlays: SignedOverlaySpec[], options?: {
|
|
48
|
+
strict?: boolean;
|
|
49
|
+
}): ResolvedField[];
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// src/runtime/overlay-alignment.ts
|
|
3
|
+
import { applyOverlayModifications } from "@contractspec/lib.overlay-engine/merger";
|
|
4
|
+
function toOverlayScopeContext(ctx) {
|
|
5
|
+
return {
|
|
6
|
+
tenantId: ctx.tenantId,
|
|
7
|
+
userId: ctx.actorId,
|
|
8
|
+
device: ctx.device,
|
|
9
|
+
tags: ctx.featureFlags
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
function toOverlayTargetRef(_ctx, target) {
|
|
13
|
+
return {
|
|
14
|
+
presentation: target.surfaceId ?? target.routeId,
|
|
15
|
+
bundleKey: target.bundleKey,
|
|
16
|
+
surfaceId: target.surfaceId,
|
|
17
|
+
routeId: target.routeId,
|
|
18
|
+
entityType: target.entityType
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
function toOverlayAppliesTo(ctx, target, scope) {
|
|
22
|
+
const scopeCtx = toOverlayScopeContext(ctx);
|
|
23
|
+
return {
|
|
24
|
+
...scopeCtx,
|
|
25
|
+
...target,
|
|
26
|
+
...scope === "user" && ctx.actorId ? { userId: ctx.actorId } : {},
|
|
27
|
+
...scope === "workspace" && ctx.workspaceId ? { tags: [...scopeCtx.tags ?? [], `workspace:${ctx.workspaceId}`] } : {}
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
function toOverlayRenderableField(field) {
|
|
31
|
+
return {
|
|
32
|
+
key: field.fieldId,
|
|
33
|
+
label: field.title,
|
|
34
|
+
visible: field.visible,
|
|
35
|
+
required: field.required,
|
|
36
|
+
order: 0
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
function fromOverlayRenderableField(overlay) {
|
|
40
|
+
return {
|
|
41
|
+
fieldId: overlay.key,
|
|
42
|
+
title: overlay.label ?? overlay.key,
|
|
43
|
+
visible: overlay.visible ?? true,
|
|
44
|
+
required: overlay.required ?? false
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
function toOverlayRenderable(fields) {
|
|
48
|
+
return {
|
|
49
|
+
fields: fields.map(toOverlayRenderableField)
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
function mergeOverlayResultIntoFields(fields, merged) {
|
|
53
|
+
const fieldMap = new Map(fields.map((f) => [f.fieldId, { ...f }]));
|
|
54
|
+
const result = [];
|
|
55
|
+
for (const overlay of merged.fields) {
|
|
56
|
+
const existing = fieldMap.get(overlay.key);
|
|
57
|
+
if (existing) {
|
|
58
|
+
result.push({
|
|
59
|
+
...existing,
|
|
60
|
+
title: overlay.label ?? existing.title,
|
|
61
|
+
visible: overlay.visible ?? existing.visible,
|
|
62
|
+
required: overlay.required ?? existing.required
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return result;
|
|
67
|
+
}
|
|
68
|
+
function applyEntityFieldOverlays(fields, overlays, options) {
|
|
69
|
+
if (!overlays.length)
|
|
70
|
+
return fields;
|
|
71
|
+
const target = toOverlayRenderable(fields);
|
|
72
|
+
const merged = applyOverlayModifications(target, overlays, options);
|
|
73
|
+
return mergeOverlayResultIntoFields(fields, merged);
|
|
74
|
+
}
|
|
75
|
+
export {
|
|
76
|
+
toOverlayTargetRef,
|
|
77
|
+
toOverlayScopeContext,
|
|
78
|
+
toOverlayRenderableField,
|
|
79
|
+
toOverlayRenderable,
|
|
80
|
+
toOverlayAppliesTo,
|
|
81
|
+
mergeOverlayResultIntoFields,
|
|
82
|
+
fromOverlayRenderableField,
|
|
83
|
+
applyEntityFieldOverlays
|
|
84
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workspace overlay signing using lib.overlay-engine signer.
|
|
3
|
+
* Aligns with 09_extension_and_override_model.md.
|
|
4
|
+
*
|
|
5
|
+
* Workspace overlays require signing for audit and provenance.
|
|
6
|
+
* Never use ephemeral-ai trust for durable registration.
|
|
7
|
+
*/
|
|
8
|
+
import { type SignOverlayOptions } from '@contractspec/lib.overlay-engine/signer';
|
|
9
|
+
import type { OverlaySpec, SignedOverlaySpec } from '@contractspec/lib.overlay-engine/spec';
|
|
10
|
+
/** Private key for signing (PEM string, Buffer, or crypto.KeyObject). */
|
|
11
|
+
export type OverlaySigningKey = string | Buffer | import('crypto').KeyLike;
|
|
12
|
+
/** Sign a workspace overlay for durable persistence. */
|
|
13
|
+
export declare function signWorkspaceOverlay(spec: OverlaySpec, privateKey: OverlaySigningKey, options?: SignOverlayOptions): SignedOverlaySpec;
|
|
14
|
+
/** Verify a signed workspace overlay. */
|
|
15
|
+
export declare function verifyWorkspaceOverlay(overlay: SignedOverlaySpec): boolean;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// src/runtime/overlay-signer.ts
|
|
3
|
+
import {
|
|
4
|
+
signOverlay,
|
|
5
|
+
verifyOverlaySignature
|
|
6
|
+
} from "@contractspec/lib.overlay-engine/signer";
|
|
7
|
+
function signWorkspaceOverlay(spec, privateKey, options) {
|
|
8
|
+
return signOverlay(spec, privateKey, options);
|
|
9
|
+
}
|
|
10
|
+
function verifyWorkspaceOverlay(overlay) {
|
|
11
|
+
return verifyOverlaySignature(overlay);
|
|
12
|
+
}
|
|
13
|
+
export {
|
|
14
|
+
verifyWorkspaceOverlay,
|
|
15
|
+
signWorkspaceOverlay
|
|
16
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Overlay persistence for surface runtime.
|
|
3
|
+
* Aligns with 09_extension_and_override_model.md.
|
|
4
|
+
*
|
|
5
|
+
* Merge order: base → system → workspace → user → session → AI proposals.
|
|
6
|
+
* User and workspace overlays are durable; session and AI are ephemeral.
|
|
7
|
+
*/
|
|
8
|
+
import type { BundleScope, SurfacePatchOp } from '../spec/types';
|
|
9
|
+
export interface StoredOverride {
|
|
10
|
+
overrideId: string;
|
|
11
|
+
scope: BundleScope;
|
|
12
|
+
targetKey: string;
|
|
13
|
+
patch: SurfacePatchOp[];
|
|
14
|
+
createdAt: string;
|
|
15
|
+
createdBy?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface BundleOverrideStore {
|
|
18
|
+
list(scope: BundleScope, targetKey: string): Promise<StoredOverride[]>;
|
|
19
|
+
save(scope: BundleScope, targetKey: string, patch: SurfacePatchOp[], options?: {
|
|
20
|
+
overrideId?: string;
|
|
21
|
+
createdBy?: string;
|
|
22
|
+
}): Promise<string>;
|
|
23
|
+
remove(overrideId: string): Promise<void>;
|
|
24
|
+
}
|
|
25
|
+
/** Build target key for overlay lookup (bundleKey:surfaceId or bundleKey:routeId). */
|
|
26
|
+
export declare function buildOverrideTargetKey(bundleKey: string, surfaceId: string, routeId?: string): string;
|
|
27
|
+
export interface ApprovalGateOptions {
|
|
28
|
+
/** When true, workspace scope saves require approval before persisting. */
|
|
29
|
+
requireApprovalForWorkspacePatches?: boolean;
|
|
30
|
+
/** Called when workspace save is attempted. Return true to allow, false to reject. */
|
|
31
|
+
requestApproval?: (args: {
|
|
32
|
+
scope: BundleScope;
|
|
33
|
+
targetKey: string;
|
|
34
|
+
patch: SurfacePatchOp[];
|
|
35
|
+
}) => Promise<boolean>;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Wraps a store with an approval gate for workspace overlays.
|
|
39
|
+
* When requireApprovalForWorkspacePatches is true and scope is 'workspace',
|
|
40
|
+
* calls requestApproval before save. Rejects if requestApproval returns false.
|
|
41
|
+
*/
|
|
42
|
+
export declare function createOverrideStoreWithApprovalGate(store: BundleOverrideStore, options: ApprovalGateOptions): BundleOverrideStore;
|
|
43
|
+
/** In-memory override store. For production, replace with persisted backend. */
|
|
44
|
+
export declare function createInMemoryOverrideStore(): BundleOverrideStore;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// src/runtime/override-store.ts
|
|
3
|
+
function buildOverrideTargetKey(bundleKey, surfaceId, routeId) {
|
|
4
|
+
return routeId ? `${bundleKey}:${routeId}:${surfaceId}` : `${bundleKey}:${surfaceId}`;
|
|
5
|
+
}
|
|
6
|
+
function createOverrideStoreWithApprovalGate(store, options) {
|
|
7
|
+
const { requireApprovalForWorkspacePatches = false, requestApproval } = options;
|
|
8
|
+
return {
|
|
9
|
+
list: store.list.bind(store),
|
|
10
|
+
async save(scope, targetKey, patch, saveOptions) {
|
|
11
|
+
if (requireApprovalForWorkspacePatches && scope === "workspace" && requestApproval) {
|
|
12
|
+
const approved = await requestApproval({ scope, targetKey, patch });
|
|
13
|
+
if (!approved) {
|
|
14
|
+
throw new Error("Workspace overlay save rejected: approval required and not granted");
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return store.save(scope, targetKey, patch, saveOptions);
|
|
18
|
+
},
|
|
19
|
+
remove: store.remove.bind(store)
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
function createInMemoryOverrideStore() {
|
|
23
|
+
const overrides = new Map;
|
|
24
|
+
function nextId() {
|
|
25
|
+
return `ov_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;
|
|
26
|
+
}
|
|
27
|
+
return {
|
|
28
|
+
async list(scope, targetKey) {
|
|
29
|
+
return Array.from(overrides.values()).filter((o) => o.scope === scope && o.targetKey === targetKey);
|
|
30
|
+
},
|
|
31
|
+
async save(scope, targetKey, patch, options) {
|
|
32
|
+
const overrideId = options?.overrideId ?? nextId();
|
|
33
|
+
const stored = {
|
|
34
|
+
overrideId,
|
|
35
|
+
scope,
|
|
36
|
+
targetKey,
|
|
37
|
+
patch,
|
|
38
|
+
createdAt: new Date().toISOString(),
|
|
39
|
+
createdBy: options?.createdBy
|
|
40
|
+
};
|
|
41
|
+
overrides.set(overrideId, stored);
|
|
42
|
+
return overrideId;
|
|
43
|
+
},
|
|
44
|
+
async remove(overrideId) {
|
|
45
|
+
overrides.delete(overrideId);
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
export {
|
|
50
|
+
createOverrideStoreWithApprovalGate,
|
|
51
|
+
createInMemoryOverrideStore,
|
|
52
|
+
buildOverrideTargetKey
|
|
53
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Planner prompt compiler for AI-native surface patches.
|
|
3
|
+
* Compiles bundle metadata, allowed ops, slots, and node kinds into a system prompt.
|
|
4
|
+
* Aligns with 07_ai_native_chat_and_generative_ui.md.
|
|
5
|
+
*/
|
|
6
|
+
import type { BundleMeta, BundleNodeKind, PreferenceDimensions, SurfacePatchOp } from '../spec/types';
|
|
7
|
+
import type { ActionSpec } from '../spec/types';
|
|
8
|
+
export interface PlannerPromptInput {
|
|
9
|
+
/** Bundle metadata. */
|
|
10
|
+
bundleMeta: BundleMeta;
|
|
11
|
+
/** Current surface ID. */
|
|
12
|
+
surfaceId: string;
|
|
13
|
+
/** Allowed patch operations. */
|
|
14
|
+
allowedPatchOps: SurfacePatchOp['op'][];
|
|
15
|
+
/** Allowed slot IDs for insert-node and move-node. */
|
|
16
|
+
allowedSlots: string[];
|
|
17
|
+
/** Allowed node kinds for new nodes. */
|
|
18
|
+
allowedNodeKinds: BundleNodeKind[];
|
|
19
|
+
/** Visible actions (actionId, title). */
|
|
20
|
+
actions: Pick<ActionSpec, 'actionId' | 'title'>[];
|
|
21
|
+
/** Current preference profile. */
|
|
22
|
+
preferences: PreferenceDimensions;
|
|
23
|
+
/** Optional base planner prompt from spec. */
|
|
24
|
+
basePrompt?: string;
|
|
25
|
+
/** Optional plan summary (e.g. layout, node count). */
|
|
26
|
+
planSummary?: string;
|
|
27
|
+
/** Optional entity metadata. */
|
|
28
|
+
entity?: {
|
|
29
|
+
type: string;
|
|
30
|
+
id: string;
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Compiles planner prompt from bundle and surface context.
|
|
35
|
+
*
|
|
36
|
+
* @param input - Bundle metadata, allowed ops, slots, node kinds, preferences
|
|
37
|
+
* @returns System prompt string for the planner
|
|
38
|
+
*/
|
|
39
|
+
export declare function compilePlannerPrompt(input: PlannerPromptInput): string;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// src/runtime/planner-prompt.ts
|
|
3
|
+
var SAFETY_INSTRUCTIONS = `
|
|
4
|
+
## Safety instructions (mandatory)
|
|
5
|
+
- Do NOT emit JSX, HTML, or raw markup.
|
|
6
|
+
- Do NOT invent node kinds; use only the allowed kinds listed above.
|
|
7
|
+
- Do NOT call undeclared tools.
|
|
8
|
+
- Prefer fewer high-confidence patches over many speculative ones.
|
|
9
|
+
- Explain why a patch helps the user.
|
|
10
|
+
`;
|
|
11
|
+
function compilePlannerPrompt(input) {
|
|
12
|
+
const {
|
|
13
|
+
bundleMeta,
|
|
14
|
+
surfaceId,
|
|
15
|
+
allowedPatchOps,
|
|
16
|
+
allowedSlots,
|
|
17
|
+
allowedNodeKinds,
|
|
18
|
+
actions,
|
|
19
|
+
preferences,
|
|
20
|
+
basePrompt,
|
|
21
|
+
planSummary,
|
|
22
|
+
entity
|
|
23
|
+
} = input;
|
|
24
|
+
const parts = [];
|
|
25
|
+
parts.push(`# Bundle: ${bundleMeta.title} (${bundleMeta.key}@${bundleMeta.version})`);
|
|
26
|
+
parts.push(`# Surface: ${surfaceId}`);
|
|
27
|
+
parts.push("");
|
|
28
|
+
if (basePrompt) {
|
|
29
|
+
parts.push("## Base instructions");
|
|
30
|
+
parts.push(basePrompt);
|
|
31
|
+
parts.push("");
|
|
32
|
+
}
|
|
33
|
+
parts.push("## Allowed patch operations");
|
|
34
|
+
parts.push(allowedPatchOps.join(", "));
|
|
35
|
+
parts.push("");
|
|
36
|
+
parts.push("## Allowed slots");
|
|
37
|
+
parts.push(allowedSlots.join(", "));
|
|
38
|
+
parts.push("");
|
|
39
|
+
parts.push("## Allowed node kinds");
|
|
40
|
+
parts.push(allowedNodeKinds.join(", "));
|
|
41
|
+
parts.push("");
|
|
42
|
+
if (actions.length > 0) {
|
|
43
|
+
parts.push("## Visible actions");
|
|
44
|
+
for (const a of actions) {
|
|
45
|
+
parts.push(`- ${a.actionId}: ${a.title}`);
|
|
46
|
+
}
|
|
47
|
+
parts.push("");
|
|
48
|
+
}
|
|
49
|
+
parts.push("## Current preference profile");
|
|
50
|
+
parts.push(`guidance=${preferences.guidance}, density=${preferences.density}, ` + `dataDepth=${preferences.dataDepth}, control=${preferences.control}, ` + `media=${preferences.media}, pace=${preferences.pace}, narrative=${preferences.narrative}`);
|
|
51
|
+
parts.push("");
|
|
52
|
+
if (planSummary) {
|
|
53
|
+
parts.push("## Current plan summary");
|
|
54
|
+
parts.push(planSummary);
|
|
55
|
+
parts.push("");
|
|
56
|
+
}
|
|
57
|
+
if (entity) {
|
|
58
|
+
parts.push("## Entity context");
|
|
59
|
+
parts.push(`${entity.type}: ${entity.id}`);
|
|
60
|
+
parts.push("");
|
|
61
|
+
}
|
|
62
|
+
parts.push(SAFETY_INSTRUCTIONS.trim());
|
|
63
|
+
return parts.join(`
|
|
64
|
+
`);
|
|
65
|
+
}
|
|
66
|
+
export {
|
|
67
|
+
compilePlannerPrompt
|
|
68
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Planner tool schemas for ContractSpecAgent/AgentSpec.
|
|
3
|
+
* Maps to AgentToolConfig; tool handlers are wired by the bundle layer.
|
|
4
|
+
* Aligns with 07_ai_native_chat_and_generative_ui.md.
|
|
5
|
+
*/
|
|
6
|
+
import type { SurfacePatchProposal } from '../spec/types';
|
|
7
|
+
/** Compatible with AgentToolConfig from @contractspec/lib.ai-agent. */
|
|
8
|
+
export interface PlannerToolConfig {
|
|
9
|
+
name: string;
|
|
10
|
+
description?: string;
|
|
11
|
+
schema?: Record<string, unknown>;
|
|
12
|
+
automationSafe?: boolean;
|
|
13
|
+
requiresApproval?: boolean;
|
|
14
|
+
}
|
|
15
|
+
/** JSON Schema for propose-patch tool parameters. */
|
|
16
|
+
export declare const PROPOSE_PATCH_TOOL_SCHEMA: {
|
|
17
|
+
readonly type: "object";
|
|
18
|
+
readonly properties: {
|
|
19
|
+
readonly proposalId: {
|
|
20
|
+
readonly type: "string";
|
|
21
|
+
readonly description: "Unique proposal identifier";
|
|
22
|
+
};
|
|
23
|
+
readonly ops: {
|
|
24
|
+
readonly type: "array";
|
|
25
|
+
readonly description: "Surface patch operations to propose";
|
|
26
|
+
readonly items: {
|
|
27
|
+
readonly type: "object";
|
|
28
|
+
readonly required: readonly ["op"];
|
|
29
|
+
readonly properties: {
|
|
30
|
+
readonly op: {
|
|
31
|
+
readonly type: "string";
|
|
32
|
+
readonly enum: readonly ["insert-node", "replace-node", "remove-node", "move-node", "resize-panel", "set-layout", "reveal-field", "hide-field", "promote-action", "set-focus"];
|
|
33
|
+
};
|
|
34
|
+
readonly slotId: {
|
|
35
|
+
readonly type: "string";
|
|
36
|
+
};
|
|
37
|
+
readonly nodeId: {
|
|
38
|
+
readonly type: "string";
|
|
39
|
+
};
|
|
40
|
+
readonly toSlotId: {
|
|
41
|
+
readonly type: "string";
|
|
42
|
+
};
|
|
43
|
+
readonly index: {
|
|
44
|
+
readonly type: "number";
|
|
45
|
+
};
|
|
46
|
+
readonly node: {
|
|
47
|
+
readonly type: "object";
|
|
48
|
+
readonly properties: {
|
|
49
|
+
readonly nodeId: {
|
|
50
|
+
readonly type: "string";
|
|
51
|
+
};
|
|
52
|
+
readonly kind: {
|
|
53
|
+
readonly type: "string";
|
|
54
|
+
};
|
|
55
|
+
readonly title: {
|
|
56
|
+
readonly type: "string";
|
|
57
|
+
};
|
|
58
|
+
readonly props: {
|
|
59
|
+
readonly type: "object";
|
|
60
|
+
};
|
|
61
|
+
readonly children: {
|
|
62
|
+
readonly type: "array";
|
|
63
|
+
};
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
readonly persistKey: {
|
|
67
|
+
readonly type: "string";
|
|
68
|
+
};
|
|
69
|
+
readonly sizes: {
|
|
70
|
+
readonly type: "array";
|
|
71
|
+
readonly items: {
|
|
72
|
+
readonly type: "number";
|
|
73
|
+
};
|
|
74
|
+
};
|
|
75
|
+
readonly layoutId: {
|
|
76
|
+
readonly type: "string";
|
|
77
|
+
};
|
|
78
|
+
readonly fieldId: {
|
|
79
|
+
readonly type: "string";
|
|
80
|
+
};
|
|
81
|
+
readonly actionId: {
|
|
82
|
+
readonly type: "string";
|
|
83
|
+
};
|
|
84
|
+
readonly placement: {
|
|
85
|
+
readonly type: "string";
|
|
86
|
+
readonly enum: readonly ["header", "inline", "context", "assistant"];
|
|
87
|
+
};
|
|
88
|
+
readonly targetId: {
|
|
89
|
+
readonly type: "string";
|
|
90
|
+
};
|
|
91
|
+
};
|
|
92
|
+
};
|
|
93
|
+
};
|
|
94
|
+
};
|
|
95
|
+
readonly required: readonly ["proposalId", "ops"];
|
|
96
|
+
};
|
|
97
|
+
/**
|
|
98
|
+
* Tool config for propose-patch. Use with ContractSpecAgent toolHandlers.
|
|
99
|
+
* Handler should validate via validatePatchProposal and return SurfacePatchProposal.
|
|
100
|
+
*/
|
|
101
|
+
export declare const proposePatchToolConfig: PlannerToolConfig;
|
|
102
|
+
/**
|
|
103
|
+
* Builds a SurfacePatchProposal from validated tool output.
|
|
104
|
+
* Call after validatePatchProposal passes.
|
|
105
|
+
*/
|
|
106
|
+
export declare function buildSurfacePatchProposal(proposalId: string, ops: SurfacePatchProposal['ops']): SurfacePatchProposal;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// src/runtime/planner-tools.ts
|
|
3
|
+
var PROPOSE_PATCH_TOOL_SCHEMA = {
|
|
4
|
+
type: "object",
|
|
5
|
+
properties: {
|
|
6
|
+
proposalId: { type: "string", description: "Unique proposal identifier" },
|
|
7
|
+
ops: {
|
|
8
|
+
type: "array",
|
|
9
|
+
description: "Surface patch operations to propose",
|
|
10
|
+
items: {
|
|
11
|
+
type: "object",
|
|
12
|
+
required: ["op"],
|
|
13
|
+
properties: {
|
|
14
|
+
op: {
|
|
15
|
+
type: "string",
|
|
16
|
+
enum: [
|
|
17
|
+
"insert-node",
|
|
18
|
+
"replace-node",
|
|
19
|
+
"remove-node",
|
|
20
|
+
"move-node",
|
|
21
|
+
"resize-panel",
|
|
22
|
+
"set-layout",
|
|
23
|
+
"reveal-field",
|
|
24
|
+
"hide-field",
|
|
25
|
+
"promote-action",
|
|
26
|
+
"set-focus"
|
|
27
|
+
]
|
|
28
|
+
},
|
|
29
|
+
slotId: { type: "string" },
|
|
30
|
+
nodeId: { type: "string" },
|
|
31
|
+
toSlotId: { type: "string" },
|
|
32
|
+
index: { type: "number" },
|
|
33
|
+
node: {
|
|
34
|
+
type: "object",
|
|
35
|
+
properties: {
|
|
36
|
+
nodeId: { type: "string" },
|
|
37
|
+
kind: { type: "string" },
|
|
38
|
+
title: { type: "string" },
|
|
39
|
+
props: { type: "object" },
|
|
40
|
+
children: { type: "array" }
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
persistKey: { type: "string" },
|
|
44
|
+
sizes: { type: "array", items: { type: "number" } },
|
|
45
|
+
layoutId: { type: "string" },
|
|
46
|
+
fieldId: { type: "string" },
|
|
47
|
+
actionId: { type: "string" },
|
|
48
|
+
placement: {
|
|
49
|
+
type: "string",
|
|
50
|
+
enum: ["header", "inline", "context", "assistant"]
|
|
51
|
+
},
|
|
52
|
+
targetId: { type: "string" }
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
required: ["proposalId", "ops"]
|
|
58
|
+
};
|
|
59
|
+
var proposePatchToolConfig = {
|
|
60
|
+
name: "propose-patch",
|
|
61
|
+
description: "Propose surface patches (layout changes, node insertions, etc.) for user approval. " + "Only use allowed ops, slots, and node kinds from the planner context.",
|
|
62
|
+
schema: PROPOSE_PATCH_TOOL_SCHEMA,
|
|
63
|
+
automationSafe: false,
|
|
64
|
+
requiresApproval: true
|
|
65
|
+
};
|
|
66
|
+
function buildSurfacePatchProposal(proposalId, ops) {
|
|
67
|
+
return {
|
|
68
|
+
proposalId,
|
|
69
|
+
source: "assistant",
|
|
70
|
+
ops,
|
|
71
|
+
approvalState: "proposed"
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
export {
|
|
75
|
+
proposePatchToolConfig,
|
|
76
|
+
buildSurfacePatchProposal,
|
|
77
|
+
PROPOSE_PATCH_TOOL_SCHEMA
|
|
78
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Policy evaluation helpers for patch proposals.
|
|
3
|
+
* Gate patch application with PDP; emit policy.denied when blocked.
|
|
4
|
+
*/
|
|
5
|
+
import type { BundleContext, SurfacePatchOp, BundleAuditEmitter } from '../spec/types';
|
|
6
|
+
import type { PolicyHooks, PatchPolicyEffect } from './resolve-bundle';
|
|
7
|
+
/**
|
|
8
|
+
* Evaluates a patch proposal with policy hooks.
|
|
9
|
+
* Returns allow | deny | require-approval.
|
|
10
|
+
* When policy hook is absent, returns allow (stub PDP).
|
|
11
|
+
*/
|
|
12
|
+
export declare function evaluatePatchProposalPolicy<C extends BundleContext>(ops: SurfacePatchOp[], ctx: C, policy?: PolicyHooks<C>): PatchPolicyEffect;
|
|
13
|
+
/**
|
|
14
|
+
* Evaluates and optionally emits policy.denied when blocked.
|
|
15
|
+
* Call before applying patches. If returns false, do not apply.
|
|
16
|
+
*/
|
|
17
|
+
export declare function evaluateAndEmitPatchPolicy<C extends BundleContext>(ops: SurfacePatchOp[], ctx: C, args: {
|
|
18
|
+
policy?: PolicyHooks<C>;
|
|
19
|
+
audit?: BundleAuditEmitter;
|
|
20
|
+
bundleKey: string;
|
|
21
|
+
surfaceId?: string;
|
|
22
|
+
targetId?: string;
|
|
23
|
+
}): boolean;
|