@granular-software/sdk 0.4.72 → 0.4.73

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/dist/index.js CHANGED
@@ -4300,8 +4300,8 @@ function normalizeFeedItems(values) {
4300
4300
  return { items: Object.freeze(items), error };
4301
4301
  }
4302
4302
  function normalizeTransients(values) {
4303
- const record2 = asRecord(values);
4304
- if (!record2) {
4303
+ const record3 = asRecord(values);
4304
+ if (!record3) {
4305
4305
  return {
4306
4306
  items: [],
4307
4307
  error: new Error("Canonical feed transientById is not an object.")
@@ -4310,7 +4310,7 @@ function normalizeTransients(values) {
4310
4310
  let error = null;
4311
4311
  const byId = /* @__PURE__ */ new Map();
4312
4312
  const idByOrdinal = /* @__PURE__ */ new Map();
4313
- for (const [key, value] of Object.entries(record2)) {
4313
+ for (const [key, value] of Object.entries(record3)) {
4314
4314
  const item = normalizeTransientFeedItem(value);
4315
4315
  if (!item || item.id !== key) {
4316
4316
  error ||= new Error("Canonical feed contains an invalid transient item.");
@@ -5183,11 +5183,11 @@ function operationId(prefix) {
5183
5183
  return randomUuid ? `${prefix}_${randomUuid}` : `${prefix}_${Date.now()}_${Math.random().toString(36).slice(2)}`;
5184
5184
  }
5185
5185
  function unwrapPublishedItem(value) {
5186
- const record2 = asRecord(value);
5187
- const directItems = Array.isArray(record2?.items) ? record2.items : [];
5188
- const durable = asRecord(record2?.durable);
5186
+ const record3 = asRecord(value);
5187
+ const directItems = Array.isArray(record3?.items) ? record3.items : [];
5188
+ const durable = asRecord(record3?.durable);
5189
5189
  const durableItems = Array.isArray(durable?.items) ? durable.items : [];
5190
- return record2?.item || directItems[0] || durableItems[0] || value;
5190
+ return record3?.item || directItems[0] || durableItems[0] || value;
5191
5191
  }
5192
5192
  function requireFeedbackItem(value) {
5193
5193
  const item = normalizeFeedItem(unwrapPublishedItem(value));
@@ -5309,9 +5309,9 @@ var DEFAULT_MAX_RECONNECT_ATTEMPTS = 5;
5309
5309
  var DOCUMENT_RESYNC_CLOSE_CODE = 4e3;
5310
5310
  var DOCUMENT_RESYNC_CLOSE_REASON = "Document resync required";
5311
5311
  function documentVersion(document) {
5312
- const record2 = document;
5313
- const epochValue = record2.documentEpoch;
5314
- const revisionValue = record2.documentRevision;
5312
+ const record3 = document;
5313
+ const epochValue = record3.documentEpoch;
5314
+ const revisionValue = record3.documentRevision;
5315
5315
  const epoch = epochValue === void 0 ? 0 : epochValue;
5316
5316
  const revision = revisionValue === void 0 ? 0 : revisionValue;
5317
5317
  if (!Number.isSafeInteger(epoch) || Number(epoch) < 0 || !Number.isSafeInteger(revision) || Number(revision) < 0) {
@@ -5333,9 +5333,9 @@ function stableDocumentFingerprint(value) {
5333
5333
  if (Array.isArray(value)) {
5334
5334
  return `[${value.map(stableDocumentFingerprint).join(",")}]`;
5335
5335
  }
5336
- const record2 = value;
5337
- return `{${Object.keys(record2).sort().map(
5338
- (key) => `${JSON.stringify(key)}:${stableDocumentFingerprint(record2[key])}`
5336
+ const record3 = value;
5337
+ return `{${Object.keys(record3).sort().map(
5338
+ (key) => `${JSON.stringify(key)}:${stableDocumentFingerprint(record3[key])}`
5339
5339
  ).join(",")}}`;
5340
5340
  }
5341
5341
  function canonicalDocumentFingerprint(value) {
@@ -5345,9 +5345,9 @@ function canonicalDocumentFingerprint(value) {
5345
5345
  if (Array.isArray(input)) {
5346
5346
  return input.map((entry) => stripPresentation(entry, path));
5347
5347
  }
5348
- const record2 = input;
5348
+ const record3 = input;
5349
5349
  const output = {};
5350
- for (const [key, entry] of Object.entries(record2)) {
5350
+ for (const [key, entry] of Object.entries(record3)) {
5351
5351
  if (path.length === 1 && path[0] === "feed" && [
5352
5352
  "transientById",
5353
5353
  "feedbackUsageByJob",
@@ -6451,30 +6451,30 @@ function parseJsonPromptChoiceOption(option) {
6451
6451
  }
6452
6452
  function normalizePromptChoiceOption(option) {
6453
6453
  if (typeof option === "string") {
6454
- const record3 = parseJsonPromptChoiceOption(option);
6455
- if (!record3) {
6454
+ const record4 = parseJsonPromptChoiceOption(option);
6455
+ if (!record4) {
6456
6456
  return { value: option, label: option };
6457
6457
  }
6458
- const value2 = typeof record3.value === "string" ? record3.value : typeof record3.id === "string" ? record3.id : typeof record3.label === "string" ? record3.label : JSON.stringify(record3);
6458
+ const value2 = typeof record4.value === "string" ? record4.value : typeof record4.id === "string" ? record4.id : typeof record4.label === "string" ? record4.label : JSON.stringify(record4);
6459
6459
  return {
6460
6460
  value: value2,
6461
- label: typeof record3.label === "string" ? record3.label : value2,
6462
- description: typeof record3.description === "string" ? record3.description : void 0
6461
+ label: typeof record4.label === "string" ? record4.label : value2,
6462
+ description: typeof record4.description === "string" ? record4.description : void 0
6463
6463
  };
6464
6464
  }
6465
- const record2 = option;
6466
- if (!record2) {
6465
+ const record3 = option;
6466
+ if (!record3) {
6467
6467
  return { value: "", label: "" };
6468
6468
  }
6469
- const nestedJson = (typeof record2.value === "string" ? parseJsonPromptChoiceOption(record2.value) : null) || (typeof record2.label === "string" ? parseJsonPromptChoiceOption(record2.label) : null);
6469
+ const nestedJson = (typeof record3.value === "string" ? parseJsonPromptChoiceOption(record3.value) : null) || (typeof record3.label === "string" ? parseJsonPromptChoiceOption(record3.label) : null);
6470
6470
  if (nestedJson) {
6471
6471
  return normalizePromptChoiceOption(nestedJson);
6472
6472
  }
6473
- const value = typeof record2.value === "string" ? record2.value : typeof record2.label === "string" ? record2.label : JSON.stringify(record2);
6473
+ const value = typeof record3.value === "string" ? record3.value : typeof record3.label === "string" ? record3.label : JSON.stringify(record3);
6474
6474
  return {
6475
6475
  value,
6476
- label: typeof record2.label === "string" ? record2.label : value,
6477
- description: typeof record2.description === "string" ? record2.description : void 0
6476
+ label: typeof record3.label === "string" ? record3.label : value,
6477
+ description: typeof record3.description === "string" ? record3.description : void 0
6478
6478
  };
6479
6479
  }
6480
6480
  function scorePromptChoiceMatch(answer, answerTokens, option) {
@@ -7982,8 +7982,8 @@ function artifactRecordsById(liveDoc) {
7982
7982
  const byId = asRecord3(artifacts?.byId) || {};
7983
7983
  return Object.fromEntries(
7984
7984
  Object.entries(byId).map(([artifactId, value]) => {
7985
- const record2 = asRecord3(value);
7986
- return record2 ? [artifactId, record2] : null;
7985
+ const record3 = asRecord3(value);
7986
+ return record3 ? [artifactId, record3] : null;
7987
7987
  }).filter((entry) => Boolean(entry))
7988
7988
  );
7989
7989
  }
@@ -8016,8 +8016,8 @@ function latestInputEditSummary(metadata) {
8016
8016
  ].filter(Boolean);
8017
8017
  return `lastEdit=${source}${actor ? ` by ${actor}` : ""}${changed.length ? ` (${changed.join("; ")})` : ""}`;
8018
8018
  }
8019
- function artifactIssueSummary(record2) {
8020
- const validation = asRecord3(record2.validation);
8019
+ function artifactIssueSummary(record3) {
8020
+ const validation = asRecord3(record3.validation);
8021
8021
  if (!validation) return null;
8022
8022
  const issues = Array.isArray(validation.issues) ? validation.issues.map((issue) => asRecord3(issue)).filter((issue) => Boolean(issue)).slice(0, 3) : [];
8023
8023
  if (issues.length > 0) {
@@ -8064,18 +8064,18 @@ function artifactStatePathSummary(metadata) {
8064
8064
  ].filter(Boolean);
8065
8065
  return pieces.length ? pieces.join("; ") : null;
8066
8066
  }
8067
- function artifactSummaryLine(artifactId, record2) {
8068
- if (!record2) return `- ${artifactId}: unavailable in session artifact store`;
8069
- const label = trimString(record2.label) || artifactId;
8070
- const kind = asString(record2.kind) || "artifact";
8071
- const status = asString(record2.status) || "unknown";
8072
- const createdByJobId = asString(record2.createdByJobId);
8073
- const target = asRecord3(record2.target);
8074
- const metadata = asRecord3(record2.metadata) || {};
8075
- const subArtifactIds = Array.isArray(record2.subArtifactIds) ? record2.subArtifactIds.filter(
8067
+ function artifactSummaryLine(artifactId, record3) {
8068
+ if (!record3) return `- ${artifactId}: unavailable in session artifact store`;
8069
+ const label = trimString(record3.label) || artifactId;
8070
+ const kind = asString(record3.kind) || "artifact";
8071
+ const status = asString(record3.status) || "unknown";
8072
+ const createdByJobId = asString(record3.createdByJobId);
8073
+ const target = asRecord3(record3.target);
8074
+ const metadata = asRecord3(record3.metadata) || {};
8075
+ const subArtifactIds = Array.isArray(record3.subArtifactIds) ? record3.subArtifactIds.filter(
8076
8076
  (id) => typeof id === "string" && id.trim().length > 0
8077
8077
  ).slice(0, 8) : [];
8078
- const relationships = compactJson(record2.relationships, 220);
8078
+ const relationships = compactJson(record3.relationships, 220);
8079
8079
  const pieces = [
8080
8080
  `kind=${kind}`,
8081
8081
  `status=${status}`,
@@ -8083,7 +8083,7 @@ function artifactSummaryLine(artifactId, record2) {
8083
8083
  target ? `target=${asString(target.className) || "record"}:${asString(target.id) || "unknown"}${asString(target.label) ? ` (${asString(target.label)})` : ""}` : null,
8084
8084
  artifactStatePathSummary(metadata),
8085
8085
  artifactExecutionSummary(metadata),
8086
- artifactIssueSummary(record2),
8086
+ artifactIssueSummary(record3),
8087
8087
  latestInputEditSummary(metadata),
8088
8088
  subArtifactIds.length ? `subArtifacts=${subArtifactIds.join(",")}` : null,
8089
8089
  relationships ? `relationships=${relationships}` : null
@@ -13194,6 +13194,300 @@ var effectBehaviorsMetamodelPackage = defineMetamodelPackage({
13194
13194
  }
13195
13195
  });
13196
13196
 
13197
+ // src/record-snapshot-projection.ts
13198
+ function stableValue(value) {
13199
+ if (Array.isArray(value)) return value.map(stableValue);
13200
+ if (value && typeof value === "object") {
13201
+ return Object.fromEntries(
13202
+ Object.entries(value).filter(([, item]) => item !== void 0).sort(([left], [right]) => left.localeCompare(right)).map(([key, item]) => [key, stableValue(item)])
13203
+ );
13204
+ }
13205
+ return value;
13206
+ }
13207
+ function stableJson(value) {
13208
+ return JSON.stringify(stableValue(value));
13209
+ }
13210
+ function recordKey(record3) {
13211
+ return `${record3.className}\0${record3.id}`;
13212
+ }
13213
+ function recordReference(className, id) {
13214
+ return { className, id };
13215
+ }
13216
+ function changedRecordSnapshots(beforeRecords, afterRecords) {
13217
+ const before = new Map(
13218
+ beforeRecords.map((record3) => [recordKey(record3), record3])
13219
+ );
13220
+ const after = new Map(
13221
+ afterRecords.map((record3) => [recordKey(record3), record3])
13222
+ );
13223
+ const changedKeys = /* @__PURE__ */ new Set();
13224
+ for (const key of /* @__PURE__ */ new Set([...before.keys(), ...after.keys()])) {
13225
+ if (stableJson(before.get(key)) !== stableJson(after.get(key))) {
13226
+ changedKeys.add(key);
13227
+ }
13228
+ }
13229
+ return {
13230
+ beforeRecords: beforeRecords.filter(
13231
+ (record3) => changedKeys.has(recordKey(record3))
13232
+ ),
13233
+ afterRecords: afterRecords.filter(
13234
+ (record3) => changedKeys.has(recordKey(record3))
13235
+ )
13236
+ };
13237
+ }
13238
+ function relationshipTargets(manifest) {
13239
+ const targets = /* @__PURE__ */ new Map();
13240
+ for (const volume of manifest.volumes) {
13241
+ for (const operation of volume.operations) {
13242
+ const relationship = operation.defineRelationship;
13243
+ if (!relationship) continue;
13244
+ targets.set(`${relationship.left}\0${relationship.leftSubmodel}`, {
13245
+ className: relationship.right
13246
+ });
13247
+ targets.set(`${relationship.right}\0${relationship.rightSubmodel}`, {
13248
+ className: relationship.left
13249
+ });
13250
+ }
13251
+ }
13252
+ return targets;
13253
+ }
13254
+ function stateName(value) {
13255
+ return typeof value === "string" ? value : value.state;
13256
+ }
13257
+ function asIds(value) {
13258
+ return value === void 0 ? [] : Array.isArray(value) ? value : [value];
13259
+ }
13260
+ function changedObjectProjection(before, after) {
13261
+ const beforeFields = before?.fields || {};
13262
+ const afterFields = after.fields || {};
13263
+ const fields = { ...afterFields };
13264
+ for (const fieldName of Object.keys(beforeFields)) {
13265
+ if (!(fieldName in afterFields)) fields[fieldName] = null;
13266
+ }
13267
+ if (before && before.label === after.label && stableJson(beforeFields) === stableJson(afterFields)) {
13268
+ return null;
13269
+ }
13270
+ return {
13271
+ kind: "object",
13272
+ operation: before ? "updated" : "created",
13273
+ record: {
13274
+ className: after.className,
13275
+ id: after.id,
13276
+ ...after.label !== void 0 ? { label: after.label } : {},
13277
+ fields
13278
+ }
13279
+ };
13280
+ }
13281
+ function projectionChanges(input) {
13282
+ const before = new Map(
13283
+ input.beforeRecords.map((record3) => [recordKey(record3), record3])
13284
+ );
13285
+ const after = new Map(
13286
+ input.afterRecords.map((record3) => [recordKey(record3), record3])
13287
+ );
13288
+ const targets = relationshipTargets(input.manifest);
13289
+ const changes = [];
13290
+ for (const record3 of input.afterRecords) {
13291
+ const previous = before.get(recordKey(record3));
13292
+ const objectChange = changedObjectProjection(previous, record3);
13293
+ if (objectChange) changes.push(objectChange);
13294
+ const relationshipNames = /* @__PURE__ */ new Set([
13295
+ ...Object.keys(previous?.relationships || {}),
13296
+ ...Object.keys(record3.relationships || {})
13297
+ ]);
13298
+ for (const relationshipName of [...relationshipNames].sort()) {
13299
+ const target = targets.get(
13300
+ `${record3.className}\0${relationshipName}`
13301
+ );
13302
+ if (!target) {
13303
+ throw new Error(
13304
+ `No ontology relationship target is declared for ${record3.className}.${relationshipName}`
13305
+ );
13306
+ }
13307
+ const previousIds = new Set(
13308
+ asIds(previous?.relationships?.[relationshipName])
13309
+ );
13310
+ const currentIds = new Set(
13311
+ asIds(record3.relationships?.[relationshipName])
13312
+ );
13313
+ for (const id of [...previousIds].sort()) {
13314
+ if (currentIds.has(id)) continue;
13315
+ changes.push({
13316
+ kind: "relationship",
13317
+ operation: "disconnected",
13318
+ relationship: relationshipName,
13319
+ from: recordReference(record3.className, record3.id),
13320
+ to: recordReference(target.className, id)
13321
+ });
13322
+ }
13323
+ for (const id of [...currentIds].sort()) {
13324
+ if (previousIds.has(id)) continue;
13325
+ changes.push({
13326
+ kind: "relationship",
13327
+ operation: "connected",
13328
+ relationship: relationshipName,
13329
+ from: recordReference(record3.className, record3.id),
13330
+ to: recordReference(target.className, id)
13331
+ });
13332
+ }
13333
+ }
13334
+ const machines = /* @__PURE__ */ new Set([
13335
+ ...Object.keys(previous?.states || {}),
13336
+ ...Object.keys(record3.states || {})
13337
+ ]);
13338
+ for (const machine of [...machines].sort()) {
13339
+ const next = record3.states?.[machine];
13340
+ if (next === void 0) continue;
13341
+ const prior = previous?.states?.[machine];
13342
+ if (prior !== void 0 && stateName(prior) === stateName(next)) continue;
13343
+ if (input.transition && input.transition.className === record3.className && input.transition.objectId === record3.id && input.transition.machine === machine) {
13344
+ continue;
13345
+ }
13346
+ changes.push({
13347
+ kind: "state_observation",
13348
+ target: recordReference(record3.className, record3.id),
13349
+ machine,
13350
+ state: stateName(next)
13351
+ });
13352
+ }
13353
+ }
13354
+ for (const record3 of input.beforeRecords) {
13355
+ if (after.has(recordKey(record3))) continue;
13356
+ changes.push({
13357
+ kind: "object",
13358
+ operation: "deleted",
13359
+ target: recordReference(record3.className, record3.id)
13360
+ });
13361
+ }
13362
+ return changes;
13363
+ }
13364
+ function valueAtPath(value, path) {
13365
+ return path.split(".").filter(Boolean).reduce((current, segment) => {
13366
+ if (!current || typeof current !== "object" || Array.isArray(current)) {
13367
+ return void 0;
13368
+ }
13369
+ return current[segment];
13370
+ }, value);
13371
+ }
13372
+ function primaryTarget(input) {
13373
+ if (input.transition) {
13374
+ return recordReference(
13375
+ input.transition.className,
13376
+ input.transition.objectId
13377
+ );
13378
+ }
13379
+ const creates = input.effect.metamodels?.creates;
13380
+ if (creates) {
13381
+ const declaration = typeof creates === "string" ? { className: creates } : creates;
13382
+ const id = declaration.idPath ? valueAtPath(input.result, declaration.idPath) : void 0;
13383
+ if (typeof id === "string" && id) {
13384
+ return recordReference(declaration.className, id);
13385
+ }
13386
+ }
13387
+ if (input.effect.className && !input.effect.static) {
13388
+ const objectId = input.effectInput && typeof input.effectInput === "object" && !Array.isArray(input.effectInput) ? input.effectInput._objectId : void 0;
13389
+ if (typeof objectId === "string" && objectId) {
13390
+ return recordReference(input.effect.className, objectId);
13391
+ }
13392
+ }
13393
+ const created = input.changes.filter(
13394
+ (change) => change.kind === "object" && change.operation === "created"
13395
+ );
13396
+ const onlyCreated = created.length === 1 ? created[0] : void 0;
13397
+ return onlyCreated ? recordReference(onlyCreated.record.className, onlyCreated.record.id) : void 0;
13398
+ }
13399
+ function assertRecordSnapshotTransitionMapping(transition) {
13400
+ if (!transition)
13401
+ throw new Error("A transition commit has no authored transition context.");
13402
+ if (!transition.outcomes || !Object.keys(transition.outcomes).length) {
13403
+ throw new Error(
13404
+ "Automatic product-state mapping requires at least one declared outcome."
13405
+ );
13406
+ }
13407
+ const destinations = /* @__PURE__ */ new Map();
13408
+ for (const [key, outcome] of Object.entries(transition.outcomes)) {
13409
+ if (!outcome || typeof outcome.to !== "string" || !outcome.to) {
13410
+ throw new Error(
13411
+ `Automatic product-state mapping requires a destination for outcome ${key}.`
13412
+ );
13413
+ }
13414
+ const destination = outcome.to === "$current" ? transition.from : outcome.to;
13415
+ const previous = destinations.get(destination);
13416
+ if (previous !== void 0) {
13417
+ throw new Error(
13418
+ `Ambiguous product-state mapping for ${transition.machine}.${transition.transition}: outcomes ${previous} and ${key} both resolve to ${destination}; automatic mapping requires distinct outcome destinations.`
13419
+ );
13420
+ }
13421
+ destinations.set(destination, key);
13422
+ }
13423
+ }
13424
+ function transitionOutcome(transition, afterRecords) {
13425
+ assertRecordSnapshotTransitionMapping(transition);
13426
+ const target = afterRecords.find(
13427
+ (record3) => record3.className === transition.className && record3.id === transition.objectId
13428
+ );
13429
+ const observed = target?.states?.[transition.machine];
13430
+ if (!observed) {
13431
+ throw new Error(
13432
+ `The product result did not expose ${transition.className}:${transition.objectId}.${transition.machine}`
13433
+ );
13434
+ }
13435
+ const finalState = stateName(observed);
13436
+ const matches = Object.entries(transition.outcomes).filter(
13437
+ ([, outcome]) => outcome.to === finalState || outcome.to === "$current" && finalState === transition.from
13438
+ );
13439
+ if (matches.length !== 1) {
13440
+ throw new Error(
13441
+ `Product state ${finalState} maps to ${matches.length} authored outcomes for ${transition.machine}.${transition.transition}`
13442
+ );
13443
+ }
13444
+ const [key, declaration] = matches[0];
13445
+ return {
13446
+ key,
13447
+ ...declaration.disposition === "error" ? {
13448
+ error: {
13449
+ code: `product_outcome_${key}`,
13450
+ message: declaration.label || `The product completed in ${finalState} instead of continuing.`,
13451
+ retryable: false
13452
+ }
13453
+ } : {}
13454
+ };
13455
+ }
13456
+ function projectRecordSnapshotMutation(input) {
13457
+ const changes = projectionChanges({
13458
+ manifest: input.manifest,
13459
+ beforeRecords: input.source.beforeRecords,
13460
+ afterRecords: input.source.afterRecords,
13461
+ transition: input.transition
13462
+ });
13463
+ const target = primaryTarget({
13464
+ effect: input.effect,
13465
+ effectInput: input.effectInput,
13466
+ result: input.result,
13467
+ changes,
13468
+ transition: input.transition
13469
+ });
13470
+ const base = {
13471
+ source: {
13472
+ reference: input.source.reference,
13473
+ ...input.source.version ? { version: input.source.version } : {},
13474
+ ...input.source.versionScope ? { versionScope: input.source.versionScope } : {}
13475
+ },
13476
+ ...target ? { primaryTarget: target } : {},
13477
+ changes,
13478
+ safeSummary: {
13479
+ effect: input.effect.name,
13480
+ affectedChanges: changes.length
13481
+ }
13482
+ };
13483
+ if (input.commitKind === "effect") return base;
13484
+ return {
13485
+ ...base,
13486
+ outcome: transitionOutcome(input.transition, input.source.afterRecords)
13487
+ };
13488
+ }
13489
+ projectRecordSnapshotMutation.validateTransition = assertRecordSnapshotTransitionMapping;
13490
+
13197
13491
  // src/commit.ts
13198
13492
  var MAX_PROJECTION_CHANGES = 1e3;
13199
13493
  var MAX_SAFE_SUMMARY_KEYS = 32;
@@ -13287,18 +13581,18 @@ function validateScalarRecord(value, path) {
13287
13581
  }
13288
13582
  function validateProjectedRecord(value, path) {
13289
13583
  validateObjectReference(value, path);
13290
- const record2 = value;
13291
- if (record2.label !== void 0) {
13292
- if (typeof record2.label !== "string") {
13584
+ const record3 = value;
13585
+ if (record3.label !== void 0) {
13586
+ if (typeof record3.label !== "string") {
13293
13587
  throw new Error(`${path}.label must be a string`);
13294
13588
  }
13295
- if (record2.label.length > MAX_SAFE_TEXT_LENGTH) {
13589
+ if (record3.label.length > MAX_SAFE_TEXT_LENGTH) {
13296
13590
  throw new Error(
13297
13591
  `${path}.label exceeds ${MAX_SAFE_TEXT_LENGTH} characters`
13298
13592
  );
13299
13593
  }
13300
13594
  }
13301
- validateScalarRecord(record2.fields, `${path}.fields`);
13595
+ validateScalarRecord(record3.fields, `${path}.fields`);
13302
13596
  }
13303
13597
  function validateBoundedJson(value, path, depth = 0) {
13304
13598
  if (depth > 12) throw new Error(`${path} is nested too deeply`);
@@ -13802,6 +14096,11 @@ async function invokeRegisteredEffect(effectMap, request, options = {}) {
13802
14096
  `Transition effect ${request.effectKey} has no resolved transition context; customer code was not invoked`
13803
14097
  );
13804
14098
  }
14099
+ if (commitRequired && declaration?.kind === "transition" && declaration.outcomeSelection === "product_state") {
14100
+ assertRecordSnapshotTransitionMapping(
14101
+ request.context?.invocation?.transition
14102
+ );
14103
+ }
13805
14104
  const idempotencyKey = commitRequired ? await resolveInvocationIdempotencyKey(request) : request.context?.idempotencyKey;
13806
14105
  let commitStarted = false;
13807
14106
  let commitPromise = null;
@@ -16365,7 +16664,7 @@ function stateTransitionSteps(artifact) {
16365
16664
  {
16366
16665
  index: typeof step.index === "number" ? step.index : fallbackIndex,
16367
16666
  transition,
16368
- label: text(step.label) || humanize(transition),
16667
+ label: text(transitionDescription?.label) || text(step.label) || humanize(transition),
16369
16668
  description: text(step.description) || text(record(step.expectedOutcome)?.summary) || null,
16370
16669
  status: text(step.status) || "pending",
16371
16670
  // State plans may contain bookkeeping transitions that are necessary
@@ -17047,17 +17346,17 @@ function planRecordObjectsChunks(records, batchSize) {
17047
17346
  }
17048
17347
  return plans;
17049
17348
  }
17050
- function preserveRecordObjectRealId(record2) {
17051
- const realId = record2.id.trim();
17349
+ function preserveRecordObjectRealId(record3) {
17350
+ const realId = record3.id.trim();
17052
17351
  if (!realId) {
17053
- return record2;
17352
+ return record3;
17054
17353
  }
17055
- const fields = record2.fields || {};
17354
+ const fields = record3.fields || {};
17056
17355
  if (typeof fields.real_id === "string" && fields.real_id.trim()) {
17057
- return record2;
17356
+ return record3;
17058
17357
  }
17059
17358
  return {
17060
- ...record2,
17359
+ ...record3,
17061
17360
  fields: {
17062
17361
  ...fields,
17063
17362
  real_id: realId
@@ -17389,7 +17688,7 @@ var Environment = class _Environment {
17389
17688
  }
17390
17689
  get data() {
17391
17690
  return {
17392
- record: async (record2) => this.recordObject(record2),
17691
+ record: async (record3) => this.recordObject(record3),
17393
17692
  recordMany: async (records, options) => this.recordObjects(records, options),
17394
17693
  import: async (records, options) => this.enqueueRecordImport(records, options),
17395
17694
  listImports: async (status) => this.listRecordImports(status),
@@ -17886,6 +18185,11 @@ var Environment = class _Environment {
17886
18185
  classNames: options.classNames?.length ? options.classNames : []
17887
18186
  }
17888
18187
  );
18188
+ if (response.errors?.length) {
18189
+ throw new Error(
18190
+ `Record search failed: ${response.errors.map((error) => error.message).join("; ")}`
18191
+ );
18192
+ }
17889
18193
  const seen = /* @__PURE__ */ new Set();
17890
18194
  const results = (response.data?.record_search || []).flatMap((entry) => {
17891
18195
  const className = entry.className?.trim();
@@ -21044,13 +21348,13 @@ var Granular = class _Granular {
21044
21348
  * Permission Profile management for sandboxes
21045
21349
  */
21046
21350
  get permissionProfiles() {
21047
- const profileSourceFromRecord = (record2) => {
21048
- const profile = record2.profile || record2.rules || {};
21351
+ const profileSourceFromRecord = (record3) => {
21352
+ const profile = record3.profile || record3.rules || {};
21049
21353
  return {
21050
21354
  ...profile,
21051
21355
  schemaVersion: profile.schemaVersion || 1,
21052
- name: profile.name || record2.name,
21053
- description: profile.description || record2.description
21356
+ name: profile.name || record3.name,
21357
+ description: profile.description || record3.description
21054
21358
  };
21055
21359
  };
21056
21360
  return {
@@ -21620,276 +21924,6 @@ async function pollEnvironmentSetup(input) {
21620
21924
  }
21621
21925
  }
21622
21926
 
21623
- // src/record-snapshot-projection.ts
21624
- function stableValue(value) {
21625
- if (Array.isArray(value)) return value.map(stableValue);
21626
- if (value && typeof value === "object") {
21627
- return Object.fromEntries(
21628
- Object.entries(value).filter(([, item]) => item !== void 0).sort(([left], [right]) => left.localeCompare(right)).map(([key, item]) => [key, stableValue(item)])
21629
- );
21630
- }
21631
- return value;
21632
- }
21633
- function stableJson(value) {
21634
- return JSON.stringify(stableValue(value));
21635
- }
21636
- function recordKey(record2) {
21637
- return `${record2.className}\0${record2.id}`;
21638
- }
21639
- function recordReference(className, id) {
21640
- return { className, id };
21641
- }
21642
- function changedRecordSnapshots(beforeRecords, afterRecords) {
21643
- const before = new Map(
21644
- beforeRecords.map((record2) => [recordKey(record2), record2])
21645
- );
21646
- const after = new Map(
21647
- afterRecords.map((record2) => [recordKey(record2), record2])
21648
- );
21649
- const changedKeys = /* @__PURE__ */ new Set();
21650
- for (const key of /* @__PURE__ */ new Set([...before.keys(), ...after.keys()])) {
21651
- if (stableJson(before.get(key)) !== stableJson(after.get(key))) {
21652
- changedKeys.add(key);
21653
- }
21654
- }
21655
- return {
21656
- beforeRecords: beforeRecords.filter(
21657
- (record2) => changedKeys.has(recordKey(record2))
21658
- ),
21659
- afterRecords: afterRecords.filter(
21660
- (record2) => changedKeys.has(recordKey(record2))
21661
- )
21662
- };
21663
- }
21664
- function relationshipTargets(manifest) {
21665
- const targets = /* @__PURE__ */ new Map();
21666
- for (const volume of manifest.volumes) {
21667
- for (const operation of volume.operations) {
21668
- const relationship = operation.defineRelationship;
21669
- if (!relationship) continue;
21670
- targets.set(`${relationship.left}\0${relationship.leftSubmodel}`, {
21671
- className: relationship.right
21672
- });
21673
- targets.set(`${relationship.right}\0${relationship.rightSubmodel}`, {
21674
- className: relationship.left
21675
- });
21676
- }
21677
- }
21678
- return targets;
21679
- }
21680
- function stateName(value) {
21681
- return typeof value === "string" ? value : value.state;
21682
- }
21683
- function asIds(value) {
21684
- return value === void 0 ? [] : Array.isArray(value) ? value : [value];
21685
- }
21686
- function changedObjectProjection(before, after) {
21687
- const beforeFields = before?.fields || {};
21688
- const afterFields = after.fields || {};
21689
- const fields = { ...afterFields };
21690
- for (const fieldName of Object.keys(beforeFields)) {
21691
- if (!(fieldName in afterFields)) fields[fieldName] = null;
21692
- }
21693
- if (before && before.label === after.label && stableJson(beforeFields) === stableJson(afterFields)) {
21694
- return null;
21695
- }
21696
- return {
21697
- kind: "object",
21698
- operation: before ? "updated" : "created",
21699
- record: {
21700
- className: after.className,
21701
- id: after.id,
21702
- ...after.label !== void 0 ? { label: after.label } : {},
21703
- fields
21704
- }
21705
- };
21706
- }
21707
- function projectionChanges(input) {
21708
- const before = new Map(
21709
- input.beforeRecords.map((record2) => [recordKey(record2), record2])
21710
- );
21711
- const after = new Map(
21712
- input.afterRecords.map((record2) => [recordKey(record2), record2])
21713
- );
21714
- const targets = relationshipTargets(input.manifest);
21715
- const changes = [];
21716
- for (const record2 of input.afterRecords) {
21717
- const previous = before.get(recordKey(record2));
21718
- const objectChange = changedObjectProjection(previous, record2);
21719
- if (objectChange) changes.push(objectChange);
21720
- const relationshipNames = /* @__PURE__ */ new Set([
21721
- ...Object.keys(previous?.relationships || {}),
21722
- ...Object.keys(record2.relationships || {})
21723
- ]);
21724
- for (const relationshipName of [...relationshipNames].sort()) {
21725
- const target = targets.get(
21726
- `${record2.className}\0${relationshipName}`
21727
- );
21728
- if (!target) {
21729
- throw new Error(
21730
- `No ontology relationship target is declared for ${record2.className}.${relationshipName}`
21731
- );
21732
- }
21733
- const previousIds = new Set(
21734
- asIds(previous?.relationships?.[relationshipName])
21735
- );
21736
- const currentIds = new Set(
21737
- asIds(record2.relationships?.[relationshipName])
21738
- );
21739
- for (const id of [...previousIds].sort()) {
21740
- if (currentIds.has(id)) continue;
21741
- changes.push({
21742
- kind: "relationship",
21743
- operation: "disconnected",
21744
- relationship: relationshipName,
21745
- from: recordReference(record2.className, record2.id),
21746
- to: recordReference(target.className, id)
21747
- });
21748
- }
21749
- for (const id of [...currentIds].sort()) {
21750
- if (previousIds.has(id)) continue;
21751
- changes.push({
21752
- kind: "relationship",
21753
- operation: "connected",
21754
- relationship: relationshipName,
21755
- from: recordReference(record2.className, record2.id),
21756
- to: recordReference(target.className, id)
21757
- });
21758
- }
21759
- }
21760
- const machines = /* @__PURE__ */ new Set([
21761
- ...Object.keys(previous?.states || {}),
21762
- ...Object.keys(record2.states || {})
21763
- ]);
21764
- for (const machine of [...machines].sort()) {
21765
- const next = record2.states?.[machine];
21766
- if (next === void 0) continue;
21767
- const prior = previous?.states?.[machine];
21768
- if (prior !== void 0 && stateName(prior) === stateName(next)) continue;
21769
- if (input.transition && input.transition.className === record2.className && input.transition.objectId === record2.id && input.transition.machine === machine) {
21770
- continue;
21771
- }
21772
- changes.push({
21773
- kind: "state_observation",
21774
- target: recordReference(record2.className, record2.id),
21775
- machine,
21776
- state: stateName(next)
21777
- });
21778
- }
21779
- }
21780
- for (const record2 of input.beforeRecords) {
21781
- if (after.has(recordKey(record2))) continue;
21782
- changes.push({
21783
- kind: "object",
21784
- operation: "deleted",
21785
- target: recordReference(record2.className, record2.id)
21786
- });
21787
- }
21788
- return changes;
21789
- }
21790
- function valueAtPath(value, path) {
21791
- return path.split(".").filter(Boolean).reduce((current, segment) => {
21792
- if (!current || typeof current !== "object" || Array.isArray(current)) {
21793
- return void 0;
21794
- }
21795
- return current[segment];
21796
- }, value);
21797
- }
21798
- function primaryTarget(input) {
21799
- if (input.transition) {
21800
- return recordReference(
21801
- input.transition.className,
21802
- input.transition.objectId
21803
- );
21804
- }
21805
- const creates = input.effect.metamodels?.creates;
21806
- if (creates) {
21807
- const declaration = typeof creates === "string" ? { className: creates } : creates;
21808
- const id = declaration.idPath ? valueAtPath(input.result, declaration.idPath) : void 0;
21809
- if (typeof id === "string" && id) {
21810
- return recordReference(declaration.className, id);
21811
- }
21812
- }
21813
- if (input.effect.className && !input.effect.static) {
21814
- const objectId = input.effectInput && typeof input.effectInput === "object" && !Array.isArray(input.effectInput) ? input.effectInput._objectId : void 0;
21815
- if (typeof objectId === "string" && objectId) {
21816
- return recordReference(input.effect.className, objectId);
21817
- }
21818
- }
21819
- const created = input.changes.filter(
21820
- (change) => change.kind === "object" && change.operation === "created"
21821
- );
21822
- const onlyCreated = created.length === 1 ? created[0] : void 0;
21823
- return onlyCreated ? recordReference(onlyCreated.record.className, onlyCreated.record.id) : void 0;
21824
- }
21825
- function transitionOutcome(transition, afterRecords) {
21826
- if (!transition) {
21827
- throw new Error("A transition commit has no authored transition context.");
21828
- }
21829
- const target = afterRecords.find(
21830
- (record2) => record2.className === transition.className && record2.id === transition.objectId
21831
- );
21832
- const observed = target?.states?.[transition.machine];
21833
- if (!observed) {
21834
- throw new Error(
21835
- `The product result did not expose ${transition.className}:${transition.objectId}.${transition.machine}`
21836
- );
21837
- }
21838
- const finalState = stateName(observed);
21839
- const matches = Object.entries(transition.outcomes).filter(
21840
- ([, outcome]) => outcome.to === finalState || outcome.to === "$current" && finalState === transition.from
21841
- );
21842
- if (matches.length !== 1) {
21843
- throw new Error(
21844
- `Product state ${finalState} maps to ${matches.length} authored outcomes for ${transition.machine}.${transition.transition}`
21845
- );
21846
- }
21847
- const [key, declaration] = matches[0];
21848
- return {
21849
- key,
21850
- ...declaration.disposition === "error" ? {
21851
- error: {
21852
- code: `product_outcome_${key}`,
21853
- message: declaration.label || `The product completed in ${finalState} instead of continuing.`,
21854
- retryable: false
21855
- }
21856
- } : {}
21857
- };
21858
- }
21859
- function projectRecordSnapshotMutation(input) {
21860
- const changes = projectionChanges({
21861
- manifest: input.manifest,
21862
- beforeRecords: input.source.beforeRecords,
21863
- afterRecords: input.source.afterRecords,
21864
- transition: input.transition
21865
- });
21866
- const target = primaryTarget({
21867
- effect: input.effect,
21868
- effectInput: input.effectInput,
21869
- result: input.result,
21870
- changes,
21871
- transition: input.transition
21872
- });
21873
- const base = {
21874
- source: {
21875
- reference: input.source.reference,
21876
- ...input.source.version ? { version: input.source.version } : {},
21877
- ...input.source.versionScope ? { versionScope: input.source.versionScope } : {}
21878
- },
21879
- ...target ? { primaryTarget: target } : {},
21880
- changes,
21881
- safeSummary: {
21882
- effect: input.effect.name,
21883
- affectedChanges: changes.length
21884
- }
21885
- };
21886
- if (input.commitKind === "effect") return base;
21887
- return {
21888
- ...base,
21889
- outcome: transitionOutcome(input.transition, input.source.afterRecords)
21890
- };
21891
- }
21892
-
21893
21927
  // src/agent-harness-templates/action-presentation/0.1.0/manifest.json
21894
21928
  var manifest_default = {
21895
21929
  id: "action-presentation",
@@ -22045,29 +22079,29 @@ function requireRecord(value, context) {
22045
22079
  }
22046
22080
  return value;
22047
22081
  }
22048
- function requiredString(record2, key, context) {
22049
- const value = record2[key];
22082
+ function requiredString(record3, key, context) {
22083
+ const value = record3[key];
22050
22084
  if (typeof value !== "string" || !value.trim()) {
22051
22085
  throw new Error(`${context}.${key} must be a non-empty string.`);
22052
22086
  }
22053
22087
  return value;
22054
22088
  }
22055
- function requiredNumber(record2, key, context) {
22056
- const value = record2[key];
22089
+ function requiredNumber(record3, key, context) {
22090
+ const value = record3[key];
22057
22091
  if (typeof value !== "number" || !Number.isFinite(value)) {
22058
22092
  throw new Error(`${context}.${key} must be a finite number.`);
22059
22093
  }
22060
22094
  return value;
22061
22095
  }
22062
- function requiredStringArray(record2, key, context) {
22063
- const value = record2[key];
22096
+ function requiredStringArray(record3, key, context) {
22097
+ const value = record3[key];
22064
22098
  if (!Array.isArray(value) || value.some((item) => typeof item !== "string" || !item.trim())) {
22065
22099
  throw new Error(`${context}.${key} must be an array of non-empty strings.`);
22066
22100
  }
22067
22101
  return [...value];
22068
22102
  }
22069
- function requiredNumberRecord(record2, key, context) {
22070
- const value = requireRecord(record2[key], `${context}.${key}`);
22103
+ function requiredNumberRecord(record3, key, context) {
22104
+ const value = requireRecord(record3[key], `${context}.${key}`);
22071
22105
  const output = {};
22072
22106
  for (const [entryKey, entryValue] of Object.entries(value)) {
22073
22107
  if (typeof entryValue !== "number" || !Number.isFinite(entryValue) || entryValue < 0 || entryValue > 1) {
@@ -22080,22 +22114,22 @@ function requiredNumberRecord(record2, key, context) {
22080
22114
  return output;
22081
22115
  }
22082
22116
  function validateHarnessTemplateManifest(value, context = "HarnessTemplateManifest") {
22083
- const record2 = requireRecord(value, context);
22084
- const status = requiredString(record2, "status", context);
22117
+ const record3 = requireRecord(value, context);
22118
+ const status = requiredString(record3, "status", context);
22085
22119
  if (!HARNESS_TEMPLATE_STATUSES.includes(status)) {
22086
22120
  throw new Error(
22087
22121
  `${context}.status must be one of ${HARNESS_TEMPLATE_STATUSES.join(", ")}.`
22088
22122
  );
22089
22123
  }
22090
- const createdAt = requiredString(record2, "createdAt", context);
22124
+ const createdAt = requiredString(record3, "createdAt", context);
22091
22125
  if (Number.isNaN(Date.parse(createdAt))) {
22092
22126
  throw new Error(`${context}.createdAt must be an ISO timestamp.`);
22093
22127
  }
22094
22128
  const compatibility = requireRecord(
22095
- record2.compatibility,
22129
+ record3.compatibility,
22096
22130
  `${context}.compatibility`
22097
22131
  );
22098
- const evalGates = requireRecord(record2.evalGates, `${context}.evalGates`);
22132
+ const evalGates = requireRecord(record3.evalGates, `${context}.evalGates`);
22099
22133
  const maxRegressionPct = requiredNumber(
22100
22134
  evalGates,
22101
22135
  "maxRegressionPct",
@@ -22107,23 +22141,23 @@ function validateHarnessTemplateManifest(value, context = "HarnessTemplateManife
22107
22141
  );
22108
22142
  }
22109
22143
  return {
22110
- id: requiredString(record2, "id", context),
22111
- version: requiredString(record2, "version", context),
22144
+ id: requiredString(record3, "id", context),
22145
+ version: requiredString(record3, "version", context),
22112
22146
  status,
22113
- owner: requiredString(record2, "owner", context),
22147
+ owner: requiredString(record3, "owner", context),
22114
22148
  createdAt,
22115
- changelog: requiredString(record2, "changelog", context),
22116
- promptBuilder: requiredString(record2, "promptBuilder", context),
22117
- continuationBuilder: requiredString(record2, "continuationBuilder", context),
22149
+ changelog: requiredString(record3, "changelog", context),
22150
+ promptBuilder: requiredString(record3, "promptBuilder", context),
22151
+ continuationBuilder: requiredString(record3, "continuationBuilder", context),
22118
22152
  modelOutputInstruction: requiredString(
22119
- record2,
22153
+ record3,
22120
22154
  "modelOutputInstruction",
22121
22155
  context
22122
22156
  ),
22123
- codeReviewPolicy: requiredString(record2, "codeReviewPolicy", context),
22124
- defaultModel: requiredString(record2, "defaultModel", context),
22125
- modelMatrix: requiredStringArray(record2, "modelMatrix", context),
22126
- temperature: requiredNumber(record2, "temperature", context),
22157
+ codeReviewPolicy: requiredString(record3, "codeReviewPolicy", context),
22158
+ defaultModel: requiredString(record3, "defaultModel", context),
22159
+ modelMatrix: requiredStringArray(record3, "modelMatrix", context),
22160
+ temperature: requiredNumber(record3, "temperature", context),
22127
22161
  compatibility: {
22128
22162
  minSdkVersion: requiredString(
22129
22163
  compatibility,
@@ -22268,8 +22302,8 @@ function stableStringify(value) {
22268
22302
  if (Array.isArray(value)) {
22269
22303
  return `[${value.map((entry) => stableStringify(entry)).join(",")}]`;
22270
22304
  }
22271
- const record2 = value;
22272
- return `{${Object.keys(record2).sort().map((key) => `${JSON.stringify(key)}:${stableStringify(record2[key])}`).join(",")}}`;
22305
+ const record3 = value;
22306
+ return `{${Object.keys(record3).sort().map((key) => `${JSON.stringify(key)}:${stableStringify(record3[key])}`).join(",")}}`;
22273
22307
  }
22274
22308
  function renderConstBlock(name, value) {
22275
22309
  return `const ${name} = ${JSON.stringify(value, null, 2)} as const;`;
@@ -22865,9 +22899,9 @@ function getLatestClosure(liveDoc) {
22865
22899
  }
22866
22900
  const closures = [];
22867
22901
  for (const [closureId, value] of Object.entries(closuresById)) {
22868
- const record2 = asRecord4(value);
22869
- if (!record2) continue;
22870
- closures.push({ ...record2, closureId });
22902
+ const record3 = asRecord4(value);
22903
+ if (!record3) continue;
22904
+ closures.push({ ...record3, closureId });
22871
22905
  }
22872
22906
  closures.sort(
22873
22907
  (left, right) => (Number(right.createdAt) || 0) - (Number(left.createdAt) || 0)
@@ -22905,9 +22939,9 @@ function getJobRecords(liveDoc) {
22905
22939
  const jobsById = asRecord4(asRecord4(liveDoc?.jobs)?.byId) || {};
22906
22940
  const jobs = [];
22907
22941
  for (const [jobId, value] of Object.entries(jobsById)) {
22908
- const record2 = asRecord4(value);
22909
- if (!record2) continue;
22910
- jobs.push({ ...record2, jobId });
22942
+ const record3 = asRecord4(value);
22943
+ if (!record3) continue;
22944
+ jobs.push({ ...record3, jobId });
22911
22945
  }
22912
22946
  jobs.sort(
22913
22947
  (left, right) => getJobTimestamp(right) - getJobTimestamp(left)
@@ -23093,8 +23127,8 @@ function hasOpenPrompt(liveDoc, pendingPrompts) {
23093
23127
  const prompts = asRecord4(asRecord4(job)?.prompts);
23094
23128
  if (!prompts) continue;
23095
23129
  for (const prompt of Object.values(prompts)) {
23096
- const record2 = asRecord4(prompt);
23097
- if (record2?.status === "open") return true;
23130
+ const record3 = asRecord4(prompt);
23131
+ if (record3?.status === "open") return true;
23098
23132
  }
23099
23133
  }
23100
23134
  return false;
@@ -23153,13 +23187,13 @@ function projectLoopSummary(liveDoc, pendingPrompts = [], options) {
23153
23187
  title: typeof decision.title === "string" && decision.title.trim() ? decision.title.trim() : "Decision",
23154
23188
  status,
23155
23189
  candidates: status === "open" ? asArray(decision.candidates).slice(0, 5).map((candidate) => {
23156
- const record2 = asRecord4(candidate);
23157
- if (!record2) return null;
23190
+ const record3 = asRecord4(candidate);
23191
+ if (!record3) return null;
23158
23192
  return {
23159
- id: typeof record2.id === "string" ? record2.id : "unknown",
23160
- label: typeof record2.label === "string" && record2.label.trim() ? record2.label.trim() : null,
23161
- description: typeof record2.description === "string" && record2.description.trim() ? record2.description.trim() : null,
23162
- metadata: asRecord4(record2.metadata)
23193
+ id: typeof record3.id === "string" ? record3.id : "unknown",
23194
+ label: typeof record3.label === "string" && record3.label.trim() ? record3.label.trim() : null,
23195
+ description: typeof record3.description === "string" && record3.description.trim() ? record3.description.trim() : null,
23196
+ metadata: asRecord4(record3.metadata)
23163
23197
  };
23164
23198
  }).filter(Boolean) : [],
23165
23199
  selected: status === "open" ? null : {
@@ -23794,11 +23828,11 @@ function normalizeJsonSchema(value) {
23794
23828
  return asRecord4(value);
23795
23829
  }
23796
23830
  function jsonSchemaTypeName(schema) {
23797
- const record2 = normalizeJsonSchema(schema);
23798
- if (!record2) return "unknown";
23799
- const type = record2.type;
23800
- if (record2.format === "date-time") return "date-time";
23801
- if (record2.format === "date" || type === "date" || Array.isArray(type) && type.includes("date")) {
23831
+ const record3 = normalizeJsonSchema(schema);
23832
+ if (!record3) return "unknown";
23833
+ const type = record3.type;
23834
+ if (record3.format === "date-time") return "date-time";
23835
+ if (record3.format === "date" || type === "date" || Array.isArray(type) && type.includes("date")) {
23802
23836
  return "date";
23803
23837
  }
23804
23838
  if (typeof type === "string") {
@@ -23809,12 +23843,12 @@ function jsonSchemaTypeName(schema) {
23809
23843
  return "unknown";
23810
23844
  }
23811
23845
  function summarizeObjectSchema(schema) {
23812
- const record2 = normalizeJsonSchema(schema);
23813
- const properties = asRecord4(record2?.properties);
23846
+ const record3 = normalizeJsonSchema(schema);
23847
+ const properties = asRecord4(record3?.properties);
23814
23848
  if (!properties || Object.keys(properties).length === 0) {
23815
- return record2 ? "{}" : null;
23849
+ return record3 ? "{}" : null;
23816
23850
  }
23817
- const required = new Set(asArray(record2?.required));
23851
+ const required = new Set(asArray(record3?.required));
23818
23852
  const fields = Object.entries(properties).slice(0, 8).map(([name, property]) => {
23819
23853
  const marker = required.has(name) ? "*" : "?";
23820
23854
  return `${name}${marker}: ${jsonSchemaTypeName(property)}`;
@@ -24578,39 +24612,39 @@ function pushStringArray(target, value) {
24578
24612
  pushString(target, item);
24579
24613
  }
24580
24614
  }
24581
- function collectReferencesFromRecord(record2, refs) {
24615
+ function collectReferencesFromRecord(record3, refs) {
24582
24616
  for (const key of ENTRY_KEY_CANDIDATES)
24583
- pushString(refs.entryPaths, record2[key]);
24617
+ pushString(refs.entryPaths, record3[key]);
24584
24618
  for (const key of ENTRY_ARRAY_KEY_CANDIDATES)
24585
- pushStringArray(refs.entryPaths, record2[key]);
24619
+ pushStringArray(refs.entryPaths, record3[key]);
24586
24620
  for (const key of LIST_KEY_CANDIDATES)
24587
- pushString(refs.listNames, record2[key]);
24621
+ pushString(refs.listNames, record3[key]);
24588
24622
  for (const key of LIST_ARRAY_KEY_CANDIDATES)
24589
- pushStringArray(refs.listNames, record2[key]);
24623
+ pushStringArray(refs.listNames, record3[key]);
24590
24624
  for (const key of VARIABLE_KEY_CANDIDATES)
24591
- pushString(refs.variableNames, record2[key]);
24625
+ pushString(refs.variableNames, record3[key]);
24592
24626
  for (const key of VARIABLE_ARRAY_KEY_CANDIDATES)
24593
- pushStringArray(refs.variableNames, record2[key]);
24627
+ pushStringArray(refs.variableNames, record3[key]);
24594
24628
  }
24595
- function stringValue(record2, keys) {
24629
+ function stringValue(record3, keys) {
24596
24630
  for (const key of keys) {
24597
- const value = record2[key];
24631
+ const value = record3[key];
24598
24632
  if (typeof value === "string" && value.trim()) {
24599
24633
  return value.trim();
24600
24634
  }
24601
24635
  }
24602
24636
  return null;
24603
24637
  }
24604
- function findEntryPathForRecord(record2, heap) {
24605
- const directPath = stringValue(record2, ["entryPath", "path"]);
24638
+ function findEntryPathForRecord(record3, heap) {
24639
+ const directPath = stringValue(record3, ["entryPath", "path"]);
24606
24640
  if (directPath && heap.entriesByPath?.[directPath]) {
24607
24641
  return directPath;
24608
24642
  }
24609
- const id = stringValue(record2, ["id", "_id", "recordId", "objectId"]);
24643
+ const id = stringValue(record3, ["id", "_id", "recordId", "objectId"]);
24610
24644
  if (!id) {
24611
24645
  return null;
24612
24646
  }
24613
- const className = stringValue(record2, [
24647
+ const className = stringValue(record3, [
24614
24648
  "className",
24615
24649
  "_className",
24616
24650
  "__className",
@@ -24644,17 +24678,17 @@ function scanForHeapReferences(value, heap, refs, depth = 0, seen = /* @__PURE__
24644
24678
  }
24645
24679
  return;
24646
24680
  }
24647
- const record2 = asRecord5(value);
24648
- if (!record2) return;
24681
+ const record3 = asRecord5(value);
24682
+ if (!record3) return;
24649
24683
  seen.add(value);
24650
- const entryPath = findEntryPathForRecord(record2, heap);
24684
+ const entryPath = findEntryPathForRecord(record3, heap);
24651
24685
  if (entryPath) refs.entryPaths.add(entryPath);
24652
- collectReferencesFromRecord(record2, refs);
24686
+ collectReferencesFromRecord(record3, refs);
24653
24687
  for (const key of UI_CONTAINER_KEYS) {
24654
- const nested = asRecord5(record2[key]);
24688
+ const nested = asRecord5(record3[key]);
24655
24689
  if (nested) collectReferencesFromRecord(nested, refs);
24656
24690
  }
24657
- for (const nested of Object.values(record2).slice(0, 24)) {
24691
+ for (const nested of Object.values(record3).slice(0, 24)) {
24658
24692
  scanForHeapReferences(nested, heap, refs, depth + 1, seen);
24659
24693
  }
24660
24694
  }
@@ -24803,8 +24837,8 @@ var OPENAI_MODEL_PRICING_USD_PER_MILLION = {
24803
24837
  function asRecord6(value) {
24804
24838
  return value && typeof value === "object" ? value : null;
24805
24839
  }
24806
- function numberField(record2, key) {
24807
- const value = record2?.[key];
24840
+ function numberField(record3, key) {
24841
+ const value = record3?.[key];
24808
24842
  return typeof value === "number" && Number.isFinite(value) ? value : 0;
24809
24843
  }
24810
24844
  function microsPerMillion(usdPerMillion) {
@@ -24908,6 +24942,39 @@ function calculateOpenAITokenSpend(model, rawUsage) {
24908
24942
  };
24909
24943
  }
24910
24944
 
24945
+ // src/artifact-action-review.ts
24946
+ function artifactReviewedOperation(artifact, inputValues = artifact.inputValues || {}, relationships = artifact.relationships || {}) {
24947
+ const metadata = artifact.metadata || {};
24948
+ const statePlan = { ...record2(metadata.statePlan) };
24949
+ delete statePlan.approvedTransitions;
24950
+ delete statePlan.approvalDecisions;
24951
+ return {
24952
+ artifactId: artifact.artifactId,
24953
+ sessionId: artifact.sessionId || null,
24954
+ environmentId: artifact.environmentId || null,
24955
+ subjectId: artifact.subjectId || null,
24956
+ buildId: artifact.buildId || null,
24957
+ buildVersionNumber: artifact.buildVersionNumber ?? null,
24958
+ kind: artifact.kind,
24959
+ target: artifact.target || null,
24960
+ policy: artifact.policy ?? null,
24961
+ inputSchema: artifact.inputSchema || null,
24962
+ inputValues,
24963
+ relationships,
24964
+ effectKey: metadata.effectKey || metadata.toolName || null,
24965
+ effect: metadata.effect || null,
24966
+ statePlan,
24967
+ draftRecord: metadata.draftRecord || null,
24968
+ relationshipCreate: metadata.relationshipCreate || null,
24969
+ autonomy: metadata.autonomy || null,
24970
+ batch: metadata.batch || null,
24971
+ subArtifactIds: artifact.subArtifactIds || []
24972
+ };
24973
+ }
24974
+ function record2(value) {
24975
+ return value && typeof value === "object" && !Array.isArray(value) ? value : null;
24976
+ }
24977
+
24911
24978
  // src/artifact-surface.ts
24912
24979
  function operationNode(workflow) {
24913
24980
  return getArtifactWorkflowNodes(workflow).find(
@@ -25127,6 +25194,7 @@ exports.OntologyHandle = OntologyHandle;
25127
25194
  exports.Session = Session;
25128
25195
  exports.SessionFeedController = SessionFeedController;
25129
25196
  exports.WSClient = WSClient;
25197
+ exports.artifactReviewedOperation = artifactReviewedOperation;
25130
25198
  exports.assertArtifactWorkflow = assertArtifactWorkflow;
25131
25199
  exports.buildContinuationInstruction = buildContinuationInstruction;
25132
25200
  exports.buildContinuationInstructionFromTemplate = buildContinuationInstructionFromTemplate;