@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,83 @@
|
|
|
1
|
+
// src/runtime/overlay-alignment.ts
|
|
2
|
+
import { applyOverlayModifications } from "@contractspec/lib.overlay-engine/merger";
|
|
3
|
+
function toOverlayScopeContext(ctx) {
|
|
4
|
+
return {
|
|
5
|
+
tenantId: ctx.tenantId,
|
|
6
|
+
userId: ctx.actorId,
|
|
7
|
+
device: ctx.device,
|
|
8
|
+
tags: ctx.featureFlags
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
function toOverlayTargetRef(_ctx, target) {
|
|
12
|
+
return {
|
|
13
|
+
presentation: target.surfaceId ?? target.routeId,
|
|
14
|
+
bundleKey: target.bundleKey,
|
|
15
|
+
surfaceId: target.surfaceId,
|
|
16
|
+
routeId: target.routeId,
|
|
17
|
+
entityType: target.entityType
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
function toOverlayAppliesTo(ctx, target, scope) {
|
|
21
|
+
const scopeCtx = toOverlayScopeContext(ctx);
|
|
22
|
+
return {
|
|
23
|
+
...scopeCtx,
|
|
24
|
+
...target,
|
|
25
|
+
...scope === "user" && ctx.actorId ? { userId: ctx.actorId } : {},
|
|
26
|
+
...scope === "workspace" && ctx.workspaceId ? { tags: [...scopeCtx.tags ?? [], `workspace:${ctx.workspaceId}`] } : {}
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
function toOverlayRenderableField(field) {
|
|
30
|
+
return {
|
|
31
|
+
key: field.fieldId,
|
|
32
|
+
label: field.title,
|
|
33
|
+
visible: field.visible,
|
|
34
|
+
required: field.required,
|
|
35
|
+
order: 0
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
function fromOverlayRenderableField(overlay) {
|
|
39
|
+
return {
|
|
40
|
+
fieldId: overlay.key,
|
|
41
|
+
title: overlay.label ?? overlay.key,
|
|
42
|
+
visible: overlay.visible ?? true,
|
|
43
|
+
required: overlay.required ?? false
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
function toOverlayRenderable(fields) {
|
|
47
|
+
return {
|
|
48
|
+
fields: fields.map(toOverlayRenderableField)
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
function mergeOverlayResultIntoFields(fields, merged) {
|
|
52
|
+
const fieldMap = new Map(fields.map((f) => [f.fieldId, { ...f }]));
|
|
53
|
+
const result = [];
|
|
54
|
+
for (const overlay of merged.fields) {
|
|
55
|
+
const existing = fieldMap.get(overlay.key);
|
|
56
|
+
if (existing) {
|
|
57
|
+
result.push({
|
|
58
|
+
...existing,
|
|
59
|
+
title: overlay.label ?? existing.title,
|
|
60
|
+
visible: overlay.visible ?? existing.visible,
|
|
61
|
+
required: overlay.required ?? existing.required
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return result;
|
|
66
|
+
}
|
|
67
|
+
function applyEntityFieldOverlays(fields, overlays, options) {
|
|
68
|
+
if (!overlays.length)
|
|
69
|
+
return fields;
|
|
70
|
+
const target = toOverlayRenderable(fields);
|
|
71
|
+
const merged = applyOverlayModifications(target, overlays, options);
|
|
72
|
+
return mergeOverlayResultIntoFields(fields, merged);
|
|
73
|
+
}
|
|
74
|
+
export {
|
|
75
|
+
toOverlayTargetRef,
|
|
76
|
+
toOverlayScopeContext,
|
|
77
|
+
toOverlayRenderableField,
|
|
78
|
+
toOverlayRenderable,
|
|
79
|
+
toOverlayAppliesTo,
|
|
80
|
+
mergeOverlayResultIntoFields,
|
|
81
|
+
fromOverlayRenderableField,
|
|
82
|
+
applyEntityFieldOverlays
|
|
83
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// src/runtime/overlay-signer.ts
|
|
2
|
+
import {
|
|
3
|
+
signOverlay,
|
|
4
|
+
verifyOverlaySignature
|
|
5
|
+
} from "@contractspec/lib.overlay-engine/signer";
|
|
6
|
+
function signWorkspaceOverlay(spec, privateKey, options) {
|
|
7
|
+
return signOverlay(spec, privateKey, options);
|
|
8
|
+
}
|
|
9
|
+
function verifyWorkspaceOverlay(overlay) {
|
|
10
|
+
return verifyOverlaySignature(overlay);
|
|
11
|
+
}
|
|
12
|
+
export {
|
|
13
|
+
verifyWorkspaceOverlay,
|
|
14
|
+
signWorkspaceOverlay
|
|
15
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// src/runtime/override-store.ts
|
|
2
|
+
function buildOverrideTargetKey(bundleKey, surfaceId, routeId) {
|
|
3
|
+
return routeId ? `${bundleKey}:${routeId}:${surfaceId}` : `${bundleKey}:${surfaceId}`;
|
|
4
|
+
}
|
|
5
|
+
function createOverrideStoreWithApprovalGate(store, options) {
|
|
6
|
+
const { requireApprovalForWorkspacePatches = false, requestApproval } = options;
|
|
7
|
+
return {
|
|
8
|
+
list: store.list.bind(store),
|
|
9
|
+
async save(scope, targetKey, patch, saveOptions) {
|
|
10
|
+
if (requireApprovalForWorkspacePatches && scope === "workspace" && requestApproval) {
|
|
11
|
+
const approved = await requestApproval({ scope, targetKey, patch });
|
|
12
|
+
if (!approved) {
|
|
13
|
+
throw new Error("Workspace overlay save rejected: approval required and not granted");
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return store.save(scope, targetKey, patch, saveOptions);
|
|
17
|
+
},
|
|
18
|
+
remove: store.remove.bind(store)
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
function createInMemoryOverrideStore() {
|
|
22
|
+
const overrides = new Map;
|
|
23
|
+
function nextId() {
|
|
24
|
+
return `ov_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;
|
|
25
|
+
}
|
|
26
|
+
return {
|
|
27
|
+
async list(scope, targetKey) {
|
|
28
|
+
return Array.from(overrides.values()).filter((o) => o.scope === scope && o.targetKey === targetKey);
|
|
29
|
+
},
|
|
30
|
+
async save(scope, targetKey, patch, options) {
|
|
31
|
+
const overrideId = options?.overrideId ?? nextId();
|
|
32
|
+
const stored = {
|
|
33
|
+
overrideId,
|
|
34
|
+
scope,
|
|
35
|
+
targetKey,
|
|
36
|
+
patch,
|
|
37
|
+
createdAt: new Date().toISOString(),
|
|
38
|
+
createdBy: options?.createdBy
|
|
39
|
+
};
|
|
40
|
+
overrides.set(overrideId, stored);
|
|
41
|
+
return overrideId;
|
|
42
|
+
},
|
|
43
|
+
async remove(overrideId) {
|
|
44
|
+
overrides.delete(overrideId);
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
export {
|
|
49
|
+
createOverrideStoreWithApprovalGate,
|
|
50
|
+
createInMemoryOverrideStore,
|
|
51
|
+
buildOverrideTargetKey
|
|
52
|
+
};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
// src/runtime/planner-prompt.ts
|
|
2
|
+
var SAFETY_INSTRUCTIONS = `
|
|
3
|
+
## Safety instructions (mandatory)
|
|
4
|
+
- Do NOT emit JSX, HTML, or raw markup.
|
|
5
|
+
- Do NOT invent node kinds; use only the allowed kinds listed above.
|
|
6
|
+
- Do NOT call undeclared tools.
|
|
7
|
+
- Prefer fewer high-confidence patches over many speculative ones.
|
|
8
|
+
- Explain why a patch helps the user.
|
|
9
|
+
`;
|
|
10
|
+
function compilePlannerPrompt(input) {
|
|
11
|
+
const {
|
|
12
|
+
bundleMeta,
|
|
13
|
+
surfaceId,
|
|
14
|
+
allowedPatchOps,
|
|
15
|
+
allowedSlots,
|
|
16
|
+
allowedNodeKinds,
|
|
17
|
+
actions,
|
|
18
|
+
preferences,
|
|
19
|
+
basePrompt,
|
|
20
|
+
planSummary,
|
|
21
|
+
entity
|
|
22
|
+
} = input;
|
|
23
|
+
const parts = [];
|
|
24
|
+
parts.push(`# Bundle: ${bundleMeta.title} (${bundleMeta.key}@${bundleMeta.version})`);
|
|
25
|
+
parts.push(`# Surface: ${surfaceId}`);
|
|
26
|
+
parts.push("");
|
|
27
|
+
if (basePrompt) {
|
|
28
|
+
parts.push("## Base instructions");
|
|
29
|
+
parts.push(basePrompt);
|
|
30
|
+
parts.push("");
|
|
31
|
+
}
|
|
32
|
+
parts.push("## Allowed patch operations");
|
|
33
|
+
parts.push(allowedPatchOps.join(", "));
|
|
34
|
+
parts.push("");
|
|
35
|
+
parts.push("## Allowed slots");
|
|
36
|
+
parts.push(allowedSlots.join(", "));
|
|
37
|
+
parts.push("");
|
|
38
|
+
parts.push("## Allowed node kinds");
|
|
39
|
+
parts.push(allowedNodeKinds.join(", "));
|
|
40
|
+
parts.push("");
|
|
41
|
+
if (actions.length > 0) {
|
|
42
|
+
parts.push("## Visible actions");
|
|
43
|
+
for (const a of actions) {
|
|
44
|
+
parts.push(`- ${a.actionId}: ${a.title}`);
|
|
45
|
+
}
|
|
46
|
+
parts.push("");
|
|
47
|
+
}
|
|
48
|
+
parts.push("## Current preference profile");
|
|
49
|
+
parts.push(`guidance=${preferences.guidance}, density=${preferences.density}, ` + `dataDepth=${preferences.dataDepth}, control=${preferences.control}, ` + `media=${preferences.media}, pace=${preferences.pace}, narrative=${preferences.narrative}`);
|
|
50
|
+
parts.push("");
|
|
51
|
+
if (planSummary) {
|
|
52
|
+
parts.push("## Current plan summary");
|
|
53
|
+
parts.push(planSummary);
|
|
54
|
+
parts.push("");
|
|
55
|
+
}
|
|
56
|
+
if (entity) {
|
|
57
|
+
parts.push("## Entity context");
|
|
58
|
+
parts.push(`${entity.type}: ${entity.id}`);
|
|
59
|
+
parts.push("");
|
|
60
|
+
}
|
|
61
|
+
parts.push(SAFETY_INSTRUCTIONS.trim());
|
|
62
|
+
return parts.join(`
|
|
63
|
+
`);
|
|
64
|
+
}
|
|
65
|
+
export {
|
|
66
|
+
compilePlannerPrompt
|
|
67
|
+
};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
// src/runtime/planner-tools.ts
|
|
2
|
+
var PROPOSE_PATCH_TOOL_SCHEMA = {
|
|
3
|
+
type: "object",
|
|
4
|
+
properties: {
|
|
5
|
+
proposalId: { type: "string", description: "Unique proposal identifier" },
|
|
6
|
+
ops: {
|
|
7
|
+
type: "array",
|
|
8
|
+
description: "Surface patch operations to propose",
|
|
9
|
+
items: {
|
|
10
|
+
type: "object",
|
|
11
|
+
required: ["op"],
|
|
12
|
+
properties: {
|
|
13
|
+
op: {
|
|
14
|
+
type: "string",
|
|
15
|
+
enum: [
|
|
16
|
+
"insert-node",
|
|
17
|
+
"replace-node",
|
|
18
|
+
"remove-node",
|
|
19
|
+
"move-node",
|
|
20
|
+
"resize-panel",
|
|
21
|
+
"set-layout",
|
|
22
|
+
"reveal-field",
|
|
23
|
+
"hide-field",
|
|
24
|
+
"promote-action",
|
|
25
|
+
"set-focus"
|
|
26
|
+
]
|
|
27
|
+
},
|
|
28
|
+
slotId: { type: "string" },
|
|
29
|
+
nodeId: { type: "string" },
|
|
30
|
+
toSlotId: { type: "string" },
|
|
31
|
+
index: { type: "number" },
|
|
32
|
+
node: {
|
|
33
|
+
type: "object",
|
|
34
|
+
properties: {
|
|
35
|
+
nodeId: { type: "string" },
|
|
36
|
+
kind: { type: "string" },
|
|
37
|
+
title: { type: "string" },
|
|
38
|
+
props: { type: "object" },
|
|
39
|
+
children: { type: "array" }
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
persistKey: { type: "string" },
|
|
43
|
+
sizes: { type: "array", items: { type: "number" } },
|
|
44
|
+
layoutId: { type: "string" },
|
|
45
|
+
fieldId: { type: "string" },
|
|
46
|
+
actionId: { type: "string" },
|
|
47
|
+
placement: {
|
|
48
|
+
type: "string",
|
|
49
|
+
enum: ["header", "inline", "context", "assistant"]
|
|
50
|
+
},
|
|
51
|
+
targetId: { type: "string" }
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
required: ["proposalId", "ops"]
|
|
57
|
+
};
|
|
58
|
+
var proposePatchToolConfig = {
|
|
59
|
+
name: "propose-patch",
|
|
60
|
+
description: "Propose surface patches (layout changes, node insertions, etc.) for user approval. " + "Only use allowed ops, slots, and node kinds from the planner context.",
|
|
61
|
+
schema: PROPOSE_PATCH_TOOL_SCHEMA,
|
|
62
|
+
automationSafe: false,
|
|
63
|
+
requiresApproval: true
|
|
64
|
+
};
|
|
65
|
+
function buildSurfacePatchProposal(proposalId, ops) {
|
|
66
|
+
return {
|
|
67
|
+
proposalId,
|
|
68
|
+
source: "assistant",
|
|
69
|
+
ops,
|
|
70
|
+
approvalState: "proposed"
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
export {
|
|
74
|
+
proposePatchToolConfig,
|
|
75
|
+
buildSurfacePatchProposal,
|
|
76
|
+
PROPOSE_PATCH_TOOL_SCHEMA
|
|
77
|
+
};
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
// src/runtime/audit-events.ts
|
|
2
|
+
function generateEventId() {
|
|
3
|
+
return `evt_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;
|
|
4
|
+
}
|
|
5
|
+
function emitPatchProposed(audit, args) {
|
|
6
|
+
audit.emit({
|
|
7
|
+
eventId: generateEventId(),
|
|
8
|
+
at: new Date().toISOString(),
|
|
9
|
+
actorId: args.actorId,
|
|
10
|
+
source: args.proposal.source === "assistant" ? "assistant" : "user",
|
|
11
|
+
bundleKey: args.bundleKey,
|
|
12
|
+
surfaceId: args.surfaceId,
|
|
13
|
+
eventType: "patch.proposed",
|
|
14
|
+
payload: {
|
|
15
|
+
proposalId: args.proposal.proposalId,
|
|
16
|
+
source: args.proposal.source,
|
|
17
|
+
opsCount: args.proposal.ops.length
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
function emitPatchApproved(audit, args) {
|
|
22
|
+
audit.emit({
|
|
23
|
+
eventId: generateEventId(),
|
|
24
|
+
at: new Date().toISOString(),
|
|
25
|
+
actorId: args.actorId,
|
|
26
|
+
source: "user",
|
|
27
|
+
bundleKey: args.bundleKey,
|
|
28
|
+
surfaceId: args.surfaceId,
|
|
29
|
+
eventType: "patch.approved",
|
|
30
|
+
payload: {
|
|
31
|
+
proposalId: args.proposalId,
|
|
32
|
+
source: args.source,
|
|
33
|
+
opsCount: args.opsCount,
|
|
34
|
+
reason: args.reason
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
function emitPatchRejected(audit, args) {
|
|
39
|
+
audit.emit({
|
|
40
|
+
eventId: generateEventId(),
|
|
41
|
+
at: new Date().toISOString(),
|
|
42
|
+
actorId: args.actorId,
|
|
43
|
+
source: "user",
|
|
44
|
+
bundleKey: args.bundleKey,
|
|
45
|
+
surfaceId: args.surfaceId,
|
|
46
|
+
eventType: "patch.rejected",
|
|
47
|
+
payload: {
|
|
48
|
+
proposalId: args.proposalId,
|
|
49
|
+
source: args.source,
|
|
50
|
+
opsCount: args.opsCount,
|
|
51
|
+
reason: args.reason
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
function emitOverlaySaved(audit, args) {
|
|
56
|
+
audit.emit({
|
|
57
|
+
eventId: generateEventId(),
|
|
58
|
+
at: new Date().toISOString(),
|
|
59
|
+
actorId: args.actorId,
|
|
60
|
+
source: "user",
|
|
61
|
+
bundleKey: args.bundleKey,
|
|
62
|
+
eventType: "overlay.saved",
|
|
63
|
+
payload: {
|
|
64
|
+
overlayId: args.overlayId,
|
|
65
|
+
scope: args.scope,
|
|
66
|
+
opsCount: args.opsCount
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
function emitOverlayApplied(audit, args) {
|
|
71
|
+
audit.emit({
|
|
72
|
+
eventId: generateEventId(),
|
|
73
|
+
at: new Date().toISOString(),
|
|
74
|
+
source: "system",
|
|
75
|
+
bundleKey: args.bundleKey,
|
|
76
|
+
surfaceId: args.surfaceId,
|
|
77
|
+
eventType: "overlay.applied",
|
|
78
|
+
payload: {
|
|
79
|
+
overlayId: args.overlayId,
|
|
80
|
+
opsCount: args.opsCount
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
function emitOverlayFailed(audit, args) {
|
|
85
|
+
audit.emit({
|
|
86
|
+
eventId: generateEventId(),
|
|
87
|
+
at: new Date().toISOString(),
|
|
88
|
+
source: "system",
|
|
89
|
+
bundleKey: args.bundleKey,
|
|
90
|
+
surfaceId: args.surfaceId,
|
|
91
|
+
eventType: "overlay.failed",
|
|
92
|
+
payload: {
|
|
93
|
+
overlayId: args.overlayId,
|
|
94
|
+
error: args.error
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
function emitPolicyDenied(audit, args) {
|
|
99
|
+
audit.emit({
|
|
100
|
+
eventId: generateEventId(),
|
|
101
|
+
at: new Date().toISOString(),
|
|
102
|
+
actorId: args.actorId,
|
|
103
|
+
source: "policy",
|
|
104
|
+
bundleKey: args.bundleKey,
|
|
105
|
+
surfaceId: args.surfaceId,
|
|
106
|
+
eventType: "policy.denied",
|
|
107
|
+
payload: {
|
|
108
|
+
targetId: args.targetId,
|
|
109
|
+
reason: args.reason
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
function emitPolicyRedacted(audit, args) {
|
|
114
|
+
audit.emit({
|
|
115
|
+
eventId: generateEventId(),
|
|
116
|
+
at: new Date().toISOString(),
|
|
117
|
+
actorId: args.actorId,
|
|
118
|
+
source: "policy",
|
|
119
|
+
bundleKey: args.bundleKey,
|
|
120
|
+
surfaceId: args.surfaceId,
|
|
121
|
+
eventType: "policy.redacted",
|
|
122
|
+
payload: {
|
|
123
|
+
targetId: args.targetId,
|
|
124
|
+
redactions: args.redactions
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// src/runtime/policy-eval.ts
|
|
130
|
+
function evaluatePatchProposalPolicy(ops, ctx, policy) {
|
|
131
|
+
const evaluate = policy?.evaluatePatchProposal;
|
|
132
|
+
if (!evaluate)
|
|
133
|
+
return "allow";
|
|
134
|
+
return evaluate(ops, ctx);
|
|
135
|
+
}
|
|
136
|
+
function evaluateAndEmitPatchPolicy(ops, ctx, args) {
|
|
137
|
+
const effect = evaluatePatchProposalPolicy(ops, ctx, args.policy);
|
|
138
|
+
if (effect === "deny") {
|
|
139
|
+
if (args.audit) {
|
|
140
|
+
emitPolicyDenied(args.audit, {
|
|
141
|
+
bundleKey: args.bundleKey,
|
|
142
|
+
surfaceId: args.surfaceId,
|
|
143
|
+
targetId: args.targetId ?? "patch-proposal",
|
|
144
|
+
reason: "Policy denied patch proposal",
|
|
145
|
+
actorId: ctx.actorId
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
return true;
|
|
151
|
+
}
|
|
152
|
+
export {
|
|
153
|
+
evaluatePatchProposalPolicy,
|
|
154
|
+
evaluateAndEmitPatchPolicy
|
|
155
|
+
};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
// src/runtime/resolve-preferences.ts
|
|
2
|
+
var DIMENSION_KEYS = [
|
|
3
|
+
"guidance",
|
|
4
|
+
"density",
|
|
5
|
+
"dataDepth",
|
|
6
|
+
"control",
|
|
7
|
+
"media",
|
|
8
|
+
"pace",
|
|
9
|
+
"narrative"
|
|
10
|
+
];
|
|
11
|
+
var SCOPE_ORDER = [
|
|
12
|
+
"user",
|
|
13
|
+
"workspace-user",
|
|
14
|
+
"bundle",
|
|
15
|
+
"surface",
|
|
16
|
+
"entity",
|
|
17
|
+
"session"
|
|
18
|
+
];
|
|
19
|
+
function mergeByScope(layers, ctx) {
|
|
20
|
+
const merged = { ...ctx.preferences };
|
|
21
|
+
const sourceByDimension = {};
|
|
22
|
+
for (const scope of SCOPE_ORDER) {
|
|
23
|
+
const layer = layers[scope];
|
|
24
|
+
if (!layer)
|
|
25
|
+
continue;
|
|
26
|
+
for (const dim of DIMENSION_KEYS) {
|
|
27
|
+
const val = layer[dim];
|
|
28
|
+
if (val !== undefined) {
|
|
29
|
+
merged[dim] = val;
|
|
30
|
+
sourceByDimension[dim] = scope;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
for (const dim of DIMENSION_KEYS) {
|
|
35
|
+
if (sourceByDimension[dim] === undefined) {
|
|
36
|
+
sourceByDimension[dim] = "session";
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return { canonical: merged, sourceByDimension };
|
|
40
|
+
}
|
|
41
|
+
function resolveConstraints(_canonical, _ctx) {
|
|
42
|
+
return { constrained: {}, notes: [] };
|
|
43
|
+
}
|
|
44
|
+
function resolvePreferenceProfile(ctx) {
|
|
45
|
+
const layers = {
|
|
46
|
+
session: ctx.preferences
|
|
47
|
+
};
|
|
48
|
+
const { canonical, sourceByDimension } = mergeByScope(layers, ctx);
|
|
49
|
+
const { constrained, notes } = resolveConstraints(canonical, ctx);
|
|
50
|
+
return {
|
|
51
|
+
canonical,
|
|
52
|
+
sourceByDimension,
|
|
53
|
+
constrained,
|
|
54
|
+
notes
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// src/runtime/preference-adapter.ts
|
|
59
|
+
var defaultPreferenceAdapter = {
|
|
60
|
+
async resolve(ctx) {
|
|
61
|
+
return resolvePreferenceProfile(ctx);
|
|
62
|
+
},
|
|
63
|
+
async savePreferencePatch(_args) {}
|
|
64
|
+
};
|
|
65
|
+
export {
|
|
66
|
+
defaultPreferenceAdapter
|
|
67
|
+
};
|