@elevasis/sdk 1.36.5 → 1.37.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.
@@ -7561,17 +7561,13 @@ var AcqListMetadataSchema = z.object({
7561
7561
  }).catchall(z.unknown());
7562
7562
  var ProspectingBuildTemplateIdSchema = z.string().trim().min(1).max(100);
7563
7563
  var ListStageCountsSchema = z.object({
7564
- // Attempted counts by canonical lead-gen stage. The detailed status
7565
- // distribution lives on ListProgress; telemetry keeps the overview payload small.
7566
- stageCounts: z.object({
7567
- populated: z.number().int(),
7568
- extracted: z.number().int(),
7569
- qualified: z.number().int(),
7570
- discovered: z.number().int(),
7571
- verified: z.number().int(),
7572
- personalized: z.number().int(),
7573
- uploaded: z.number().int()
7574
- }),
7564
+ // Attempted counts keyed by the tenant's declared lead-gen stage catalog IDs.
7565
+ // The catalog is tenant-owned and OM-derived at compute time; the schema
7566
+ // validates the transport shape (string keys → integer values) rather than
7567
+ // a fixed key set, so tenants with custom stages receive complete telemetry.
7568
+ // Canonical Elevasis stages (populated, extracted, qualified, discovered,
7569
+ // verified, personalized, uploaded) are included when declared in the catalog.
7570
+ stageCounts: z.record(z.string().min(1), z.number().int()),
7575
7571
  deliverability: z.object({
7576
7572
  valid: z.number().int(),
7577
7573
  risky: z.number().int(),
@@ -8775,17 +8771,48 @@ var SYSTEM_INTERFACE_PROFILES = [
8775
8771
  var SYSTEM_INTERFACE_READINESS_PROFILES = SYSTEM_INTERFACE_PROFILES.map(
8776
8772
  (profile) => profile.readinessProfile
8777
8773
  );
8778
- var SystemInterfaceReadinessProfileSchema = z.enum(SYSTEM_INTERFACE_READINESS_PROFILES);
8774
+ var SystemInterfaceReadinessProfileSchema = z.string().trim().min(1);
8779
8775
  var SystemInterfaceResourceScopeSchema = z.array(ModelIdSchema).default([]);
8776
+ var SystemApiInterfaceReadinessContractSchema = z.object({
8777
+ /** Ontology IDs of object types the interface depends on. */
8778
+ requiredObjects: z.array(z.string().trim().min(1)).default([]),
8779
+ /** Ontology IDs of catalog types the interface requires (must be non-empty). */
8780
+ requiredCatalogs: z.array(z.string().trim().min(1)).default([]),
8781
+ /** Optional ontology kind filters (reserved for future profile extensions). */
8782
+ requiredKinds: z.array(z.string().trim().min(1)).optional()
8783
+ }).strict();
8780
8784
  var SystemApiInterfaceSchema = z.object({
8781
8785
  lifecycle: SystemInterfaceLifecycleSchema.default("active"),
8786
+ /**
8787
+ * Open-string profile id. Built-in platform presets are looked up through
8788
+ * the profile registry; custom ids are validated structurally via
8789
+ * `readinessContract`. Optional — `profileForInterface` provides a default.
8790
+ */
8782
8791
  readinessProfile: SystemInterfaceReadinessProfileSchema.optional(),
8783
8792
  /**
8784
8793
  * Resource ids that participate in this API interface. This scopes readiness
8785
8794
  * derivation without duplicating authored required/provided contract refs.
8786
8795
  */
8787
- resourceIds: SystemInterfaceResourceScopeSchema.optional()
8796
+ resourceIds: SystemInterfaceResourceScopeSchema.optional(),
8797
+ /**
8798
+ * Tenant-authorable readiness declaration. Required for custom
8799
+ * (non-built-in) profile ids so structural validation can proceed. Built-in
8800
+ * profiles ignore this field (requirements are derived from platform code).
8801
+ */
8802
+ readinessContract: SystemApiInterfaceReadinessContractSchema.optional()
8788
8803
  }).strict();
8804
+ var _profileRegistry = new Map(
8805
+ SYSTEM_INTERFACE_READINESS_PROFILES.map((profileId) => [
8806
+ profileId,
8807
+ { profileId, kind: "built-in" }
8808
+ ])
8809
+ );
8810
+ function profileForInterface(systemPath, interfaceKey, readinessProfile) {
8811
+ return readinessProfile ?? `${systemPath}.${interfaceKey}`;
8812
+ }
8813
+ function isBuiltInReadinessProfile(profileId) {
8814
+ return _profileRegistry.get(profileId)?.kind === "built-in";
8815
+ }
8789
8816
  z.object({
8790
8817
  systemPath: SystemPathSchema,
8791
8818
  interfaceKey: SystemInterfaceKeySchema
@@ -9032,14 +9059,11 @@ function addReadinessIssue(issues, family, code, message, details = {}) {
9032
9059
  function formatInterfaceIdentity(systemPath, interfaceKey) {
9033
9060
  return `${systemPath}/${interfaceKey}`;
9034
9061
  }
9035
- function profileForInterface(systemPath, interfaceKey, readinessProfile) {
9036
- return readinessProfile ?? `${systemPath}.${interfaceKey}`;
9037
- }
9038
9062
  function readinessMarkerPath(context) {
9039
9063
  return context.interfaceKey === "api" ? `systems.${context.systemPath}.apiInterface` : `systems.${context.systemPath}.derivedCrmHandoffReadiness`;
9040
9064
  }
9041
9065
  function formatSupportedReadinessProfiles() {
9042
- return SYSTEM_INTERFACE_READINESS_PROFILES.map((profile) => `"${profile}"`).join(", ");
9066
+ return SYSTEM_INTERFACE_PROFILES.map((p3) => `"${p3.readinessProfile}"`).join(", ");
9043
9067
  }
9044
9068
  function getActiveScopedResources(model, resourceIds, issues, context) {
9045
9069
  const resources = [];
@@ -9231,9 +9255,6 @@ function getLeadGenCrmHandoffResourceIds(model) {
9231
9255
  function getSystemInterfaceReadinessMarker(model, request) {
9232
9256
  const system = getSystem(model, request.systemPath);
9233
9257
  if (system === void 0) return void 0;
9234
- if (request.interfaceKey === LEAD_GEN_API_INTERFACE.interfaceKey) {
9235
- return system.apiInterface;
9236
- }
9237
9258
  if (request.systemPath === LEAD_GEN_CRM_HANDOFF_INTERFACE.systemPath && request.interfaceKey === LEAD_GEN_CRM_HANDOFF_INTERFACE.interfaceKey) {
9238
9259
  return {
9239
9260
  lifecycle: "active",
@@ -9241,6 +9262,9 @@ function getSystemInterfaceReadinessMarker(model, request) {
9241
9262
  resourceIds: getLeadGenCrmHandoffResourceIds(model)
9242
9263
  };
9243
9264
  }
9265
+ if (request.interfaceKey === "api" && system.apiInterface !== void 0) {
9266
+ return system.apiInterface;
9267
+ }
9244
9268
  return void 0;
9245
9269
  }
9246
9270
  function mergeLeadGenDerivedCatalogs(model) {
@@ -9285,6 +9309,18 @@ function tryCompileBusinessOntology(model, readinessProfile, issues) {
9285
9309
  return void 0;
9286
9310
  }
9287
9311
  }
9312
+ function requireContractReadiness(issues, index2, resources, contract, context) {
9313
+ const reads = resourceBindingIds(resources, "reads");
9314
+ const catalogs = resourceBindingIds(resources, "usesCatalogs");
9315
+ for (const objectId of contract.requiredObjects) {
9316
+ requireObjectReadiness(issues, index2, objectId, context);
9317
+ requireScopedBinding(issues, reads, "reads", objectId, context);
9318
+ }
9319
+ for (const catalogId of contract.requiredCatalogs) {
9320
+ requireCatalogReadiness(issues, index2, catalogId, context);
9321
+ requireScopedBinding(issues, catalogs, "usesCatalogs", catalogId, context);
9322
+ }
9323
+ }
9288
9324
  function computeInterfaceReadiness(model, request) {
9289
9325
  const issues = [];
9290
9326
  const system = getSystem(model, request.systemPath);
@@ -9332,20 +9368,22 @@ function computeInterfaceReadiness(model, request) {
9332
9368
  { path: `${readinessMarkerPath(request)}.lifecycle` }
9333
9369
  );
9334
9370
  }
9335
- const supportedProfile = readinessProfile !== void 0 && SYSTEM_INTERFACE_PROFILES.some((profile) => profile.readinessProfile === readinessProfile);
9336
- if (!supportedProfile) {
9371
+ const checkedReadinessProfile = readinessProfile ?? profileForInterface(request.systemPath, request.interfaceKey);
9372
+ const isBuiltIn = isBuiltInReadinessProfile(checkedReadinessProfile);
9373
+ const readinessContract = systemInterface.readinessContract;
9374
+ if (!isBuiltIn && readinessContract === void 0) {
9337
9375
  addReadinessIssue(
9338
9376
  issues,
9339
9377
  "SYSTEM_INTERFACE_INVALID",
9340
- "unknown-readiness-profile",
9341
- `System Interface "${formatInterfaceIdentity(request.systemPath, request.interfaceKey)}" references unknown readiness profile "${readinessProfile}". Supported profiles: ${formatSupportedReadinessProfiles()}. Custom Systems should not declare apiInterface; route custom behavior through workflows/operations plus ontology, resources, and topology.`,
9342
- { path: `${readinessMarkerPath(request)}.readinessProfile`, ref: readinessProfile }
9378
+ "missing-readiness-contract",
9379
+ `System Interface "${formatInterfaceIdentity(request.systemPath, request.interfaceKey)}" uses custom readiness profile "${checkedReadinessProfile}" but declares no readinessContract. Built-in profiles: ${formatSupportedReadinessProfiles()}.`,
9380
+ { path: `${readinessMarkerPath(request)}.readinessContract`, ref: checkedReadinessProfile }
9343
9381
  );
9344
9382
  return {
9345
9383
  ready: false,
9346
9384
  systemPath: request.systemPath,
9347
9385
  interfaceKey: request.interfaceKey,
9348
- readinessProfile,
9386
+ readinessProfile: checkedReadinessProfile,
9349
9387
  scopedResourceIds,
9350
9388
  issues
9351
9389
  };
@@ -9359,10 +9397,6 @@ function computeInterfaceReadiness(model, request) {
9359
9397
  { path: `${readinessMarkerPath(request)}.resourceIds` }
9360
9398
  );
9361
9399
  }
9362
- const checkedReadinessProfile = readinessProfile;
9363
- if (checkedReadinessProfile === void 0) {
9364
- throw new Error("Supported readiness profile unexpectedly resolved to undefined");
9365
- }
9366
9400
  const resources = getActiveScopedResources(model, scopedResourceIds, issues, request);
9367
9401
  const index2 = tryCompileBusinessOntology(model, checkedReadinessProfile, issues);
9368
9402
  if (index2 !== void 0) {
@@ -9374,13 +9408,15 @@ function computeInterfaceReadiness(model, request) {
9374
9408
  requireLeadGenInterfaceReadiness(issues, index2, resources, request);
9375
9409
  requireCrmInterfaceReadiness(issues, index2, resources, { ...request, allowForeignOwner: true });
9376
9410
  requireHandoffBridgeReadiness(issues, model, request);
9411
+ } else if (readinessContract !== void 0) {
9412
+ requireContractReadiness(issues, index2, resources, readinessContract, request);
9377
9413
  }
9378
9414
  }
9379
9415
  return {
9380
9416
  ready: issues.length === 0,
9381
9417
  systemPath: request.systemPath,
9382
9418
  interfaceKey: request.interfaceKey,
9383
- readinessProfile,
9419
+ readinessProfile: checkedReadinessProfile,
9384
9420
  scopedResourceIds,
9385
9421
  issues
9386
9422
  };
@@ -5537,17 +5537,13 @@ var AcqListMetadataSchema = z.object({
5537
5537
  }).catchall(z.unknown());
5538
5538
  var ProspectingBuildTemplateIdSchema = z.string().trim().min(1).max(100);
5539
5539
  var ListStageCountsSchema = z.object({
5540
- // Attempted counts by canonical lead-gen stage. The detailed status
5541
- // distribution lives on ListProgress; telemetry keeps the overview payload small.
5542
- stageCounts: z.object({
5543
- populated: z.number().int(),
5544
- extracted: z.number().int(),
5545
- qualified: z.number().int(),
5546
- discovered: z.number().int(),
5547
- verified: z.number().int(),
5548
- personalized: z.number().int(),
5549
- uploaded: z.number().int()
5550
- }),
5540
+ // Attempted counts keyed by the tenant's declared lead-gen stage catalog IDs.
5541
+ // The catalog is tenant-owned and OM-derived at compute time; the schema
5542
+ // validates the transport shape (string keys → integer values) rather than
5543
+ // a fixed key set, so tenants with custom stages receive complete telemetry.
5544
+ // Canonical Elevasis stages (populated, extracted, qualified, discovered,
5545
+ // verified, personalized, uploaded) are included when declared in the catalog.
5546
+ stageCounts: z.record(z.string().min(1), z.number().int()),
5551
5547
  deliverability: z.object({
5552
5548
  valid: z.number().int(),
5553
5549
  risky: z.number().int(),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elevasis/sdk",
3
- "version": "1.36.5",
3
+ "version": "1.37.0",
4
4
  "description": "SDK for building Elevasis organization resources",
5
5
  "type": "module",
6
6
  "bin": {
@@ -58,9 +58,9 @@
58
58
  "tsup": "^8.0.0",
59
59
  "typescript": "5.9.2",
60
60
  "zod": "^4.1.0",
61
- "@repo/core": "0.51.0",
62
- "@repo/typescript-config": "0.0.0",
63
- "@repo/eslint-config": "0.0.0"
61
+ "@repo/core": "0.53.0",
62
+ "@repo/eslint-config": "0.0.0",
63
+ "@repo/typescript-config": "0.0.0"
64
64
  },
65
65
  "scripts": {
66
66
  "lint": "eslint src --max-warnings 0",
@@ -0,0 +1,46 @@
1
+ # Session Chat Zero-Wiring Default Slot
2
+
3
+ ## Why this note exists
4
+
5
+ `@elevasis/ui` (>= 2.56.0) makes `SessionChatPage`'s `renderConversationView` slot
6
+ optional and self-defaulting: when omitted, the page renders the shared
7
+ `SessionConversationView` itself, resolving `apiUrl` from the service context
8
+ (now exposed on `ElevasisServiceContextValue`). The template `SessionChatPage`
9
+ now mounts the shared page with NO slot, and the orphan null-stub
10
+ `ui/src/features/assistant/components/ConversationView.tsx` is deleted. Projects
11
+ that omit the slot get a working session chat out of the box; customization stays
12
+ opt-in via the same prop. Backward-compatible: hosts that still pass the slot are
13
+ unaffected.
14
+
15
+ ## Applies to
16
+
17
+ - All template-derived projects with the agent-sessions page
18
+ (`ui/src/features/operations/sessions/SessionChatPage.tsx`).
19
+ - Any project still wiring a local `ConversationView` stub
20
+ (`ui/src/features/assistant/components/ConversationView.tsx`) -> these render
21
+ a blank chat with a stuck `DISCONNECTED` badge until reconciled.
22
+
23
+ ## Required actions
24
+
25
+ - Bump `@elevasis/ui` to `^2.56.0` (or later) and install. (The ship train's
26
+ `external-sync` stage does this automatically via the package-cascade baseline;
27
+ manual `pnpm update` is not required.)
28
+ - Drop the explicit `renderConversationView={...}` slot from your
29
+ `SessionChatPage.tsx` and remove the local stub import, relying on the new
30
+ default. (To keep a custom body, keep passing the slot.)
31
+ - Delete the now-unused local null-stub
32
+ `ui/src/features/assistant/components/ConversationView.tsx`.
33
+
34
+ ## Verification
35
+
36
+ - `pnpm -C ui check-types` passes against `@elevasis/ui@^2.56.0`.
37
+ - The session-detail chat page (`/operations/sessions/$sessionId`) renders
38
+ history + live messages and the `DISCONNECTED` badge clears, with NO slot wired.
39
+
40
+ ## Not handled by /git-sync
41
+
42
+ - `/git-sync` surfaces this note and pulls the template `SessionChatPage`
43
+ baseline, but the diverged tenant copy is preserved (merge-managed) -- you must
44
+ manually drop the explicit slot.
45
+ - `/git-sync` does NOT delete the local `ConversationView` stub
46
+ (`delete_policy: none`); remove it manually.
@@ -0,0 +1,34 @@
1
+ # Agent session UX features (End Conversation, intake form, session naming)
2
+
3
+ ## Why this note exists
4
+
5
+ This train bumps `@elevasis/core` and `@elevasis/ui` with three tenant-facing agent-session features that ship entirely inside the published packages (no template source edit, package-cascade-only):
6
+
7
+ - **End Conversation** (`@elevasis/ui`) — both the internal Agent Sessions surface (`features/operations/sessions/SessionDetailsPanel`) and the public agent-chat surface (`features/public-agent-chat/PublicAgentChat`) now render an "End conversation" control. Ending preserves history and blocks new turns (distinct from Delete, which removes). The public composer locks out after end with a "This conversation has ended" placeholder.
8
+ - **Welcome intake form** (`@elevasis/ui` + `@elevasis/core`) — the public chat intro screen renders an optional intake form driven by the grant's `capture_fields` column (now typed as `CaptureField[]` in `@elevasis/core`'s public-agent-chat schema). Collected values flow into `session.metadata`. All fields are optional.
9
+ - **Session naming from intake** (`@elevasis/ui` + platform API) — sessions are titled from the collected `name` (server-side, with a first-user-message fallback), and the Agent Sessions list now renders `session.title` as the row label.
10
+
11
+ The session `session:end` / `session:ended` WebSocket messages, the internal `POST /sessions/:id/end` route, and server-side title derivation live in the Elevasis-deployed platform API — tenants receive that behavior automatically; the package bump only delivers the frontend.
12
+
13
+ ## Applies to
14
+
15
+ - All template-derived projects that expose the Agent Sessions page (`ui/src/features/operations/sessions/`) or the public agent-chat surface (`ui/src/features/public-agent-chat/`).
16
+ - Projects that configure public agent grants and want to collect intake fields (Name plus arbitrary configurable fields) on the public intro screen.
17
+
18
+ ## Required actions
19
+
20
+ - Bump `@elevasis/core` to `^0.52.0` and `@elevasis/ui` to `^2.59.0` (or later) and install. The ship train's `external-sync` stage does this automatically via the package-cascade baselines — manual `pnpm update` is not required.
21
+ - No source changes are required to receive End Conversation, the intake form, or title-in-list — they ship inside `@elevasis/ui` / `@elevasis/core`.
22
+ - To enable an intake form on a public agent, populate the grant's `capture_fields` (array of `{ key, label, type?, required? }`). There is no Command Center editor for `capture_fields` yet — configure it via a grant write. Leaving `capture_fields` empty renders the intro exactly as before (no form).
23
+
24
+ ## Verification
25
+
26
+ - `pnpm -C ui check-types` passes against `@elevasis/ui@^2.59.0`.
27
+ - Open the public agent chat for a grant with `capture_fields` set → the intro renders the configured fields; entering a name and starting the session titles the session by that name in the Agent Sessions list.
28
+ - With no `capture_fields` → the intro renders unchanged; the session is titled from the first user message.
29
+ - Click "End conversation" on either the public header or the internal session detail panel → the session ends, history is preserved, and a new turn is rejected ("Session has ended").
30
+
31
+ ## Not handled by /git-sync
32
+
33
+ - `/git-sync` surfaces this note and pulls the propagated package baselines, but it does not run the `@elevasis/core` / `@elevasis/ui` install for you when reconciling manually outside the ship train.
34
+ - The intake/title and End features depend on the Elevasis-deployed platform API (`session:end` handling, `/sessions/:id/end`, server-side title derivation). They are not part of a tenant's own backend and require no tenant action — but they only work once the platform API carrying them is deployed.
@@ -270,3 +270,4 @@ Layers 2 (Public API), 3 (UI Shell Runtime), 5 (Toolkit), and 6 (Graph) require
270
270
  - Vibe is not a skill. It lives in this rule file + CLAUDE.md + the PreToolUse hook -- not in `.claude/skills/`.
271
271
  - Vibe does not own the codify ceremony. `/om` owns draft, confirm, write, and typecheck for both Level A and Level B codify pipelines (decision #21 -- Codify ceremony delegated to `/om`). Vibe detects intent and hands off.
272
272
  - Vibe is not active in the monorepo. If working inside the monorepo (not an `external/` project), this ambient routing does not apply.
273
+ - Vibe does not flip **public agent exposure**. Making a deployed agent reachable on the public internet (the `agent_access_grants` row behind `/public/agents/:slug`, managed via `grant:create` / `grant:update` / `grant:disable` or the Resource-page public/private toggle) is a **security boundary deliberately kept out of ambient routing** — a non-technical user describing their business must never be able to expose an agent by accident. This is a deliberate non-route, not an unhandled gap: do NOT classify "make my agent public" / "put the interview online" as Toggle (which is System on/off) and do NOT auto-execute. Surface the `grant:*` CLI or the Resource-page toggle in plain language and require explicit confirmation.