@granular-software/sdk 0.4.49 → 0.4.50

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/cli/index.js CHANGED
@@ -9880,7 +9880,7 @@ function relationshipEdgesForClass(className, rels) {
9880
9880
  return edges;
9881
9881
  }
9882
9882
  function toPascalCase(name) {
9883
- return name.charAt(0).toUpperCase() + name.slice(1);
9883
+ return name.split(/[_:\-\s]+/).filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
9884
9884
  }
9885
9885
 
9886
9886
  // src/cli/agent-docs/concept-blocks.ts
@@ -14065,16 +14065,107 @@ var StateMachineStateSchema = external_exports.union([
14065
14065
  external_exports.string(),
14066
14066
  external_exports.object({
14067
14067
  name: external_exports.string().min(1),
14068
+ label: external_exports.string().optional(),
14069
+ description: external_exports.string().optional(),
14068
14070
  isFinal: external_exports.boolean().optional()
14069
14071
  }).strict()
14070
14072
  ]);
14073
+ var StateTransitionInputBindingSchema = external_exports.lazy(
14074
+ () => external_exports.union([
14075
+ external_exports.null(),
14076
+ external_exports.string(),
14077
+ external_exports.number(),
14078
+ external_exports.boolean(),
14079
+ external_exports.array(StateTransitionInputBindingSchema),
14080
+ external_exports.object({
14081
+ const: external_exports.unknown()
14082
+ }).strict(),
14083
+ external_exports.object({
14084
+ from: external_exports.literal("object"),
14085
+ path: external_exports.string().min(1),
14086
+ editable: external_exports.boolean().optional()
14087
+ }).strict(),
14088
+ external_exports.object({
14089
+ from: external_exports.literal("field"),
14090
+ name: external_exports.string().min(1),
14091
+ editable: external_exports.boolean().optional()
14092
+ }).strict(),
14093
+ external_exports.object({
14094
+ from: external_exports.literal("relationship"),
14095
+ name: external_exports.string().min(1),
14096
+ path: external_exports.string().min(1).optional(),
14097
+ many: external_exports.boolean().optional(),
14098
+ editable: external_exports.boolean().optional()
14099
+ }).strict(),
14100
+ external_exports.object({
14101
+ from: external_exports.literal("session"),
14102
+ path: external_exports.string().min(1),
14103
+ editable: external_exports.boolean().optional()
14104
+ }).strict(),
14105
+ external_exports.object({
14106
+ from: external_exports.literal("actor"),
14107
+ path: external_exports.string().min(1),
14108
+ editable: external_exports.boolean().optional()
14109
+ }).strict(),
14110
+ external_exports.record(external_exports.string(), StateTransitionInputBindingSchema)
14111
+ ])
14112
+ );
14113
+ var StateTransitionActionSchema = external_exports.object({
14114
+ effect: external_exports.string().min(1),
14115
+ input: external_exports.record(external_exports.string(), StateTransitionInputBindingSchema).optional()
14116
+ }).strict();
14117
+ var StateTransitionAssigneeSchema = external_exports.object({
14118
+ kind: external_exports.string().min(1),
14119
+ from: StateTransitionInputBindingSchema.optional(),
14120
+ role: external_exports.string().optional(),
14121
+ label: external_exports.string().optional()
14122
+ }).strict();
14123
+ var StateTransitionRelatedStateRequirementSchema = external_exports.object({
14124
+ relationship: external_exports.string().min(1),
14125
+ machine: external_exports.string().min(1),
14126
+ state: external_exports.string().min(1),
14127
+ className: external_exports.string().min(1).optional(),
14128
+ label: external_exports.string().optional(),
14129
+ mode: external_exports.enum(["every", "some", "any"]).optional()
14130
+ }).strict();
14131
+ var StateTransitionRequirementsSchema = external_exports.object({
14132
+ fields: external_exports.array(external_exports.string().min(1)).optional(),
14133
+ relationships: external_exports.array(external_exports.string().min(1)).optional(),
14134
+ relatedStates: external_exports.array(StateTransitionRelatedStateRequirementSchema).optional()
14135
+ }).strict();
14136
+ var StateTransitionPermissionSchema = external_exports.union([
14137
+ external_exports.string().min(1),
14138
+ external_exports.object({
14139
+ profile: external_exports.string().min(1).optional(),
14140
+ profileId: external_exports.string().min(1).optional(),
14141
+ label: external_exports.string().optional(),
14142
+ reason: external_exports.string().optional()
14143
+ }).strict()
14144
+ ]);
14145
+ var StateTransitionExpectedOutcomeSchema = external_exports.union([
14146
+ external_exports.string().min(1),
14147
+ external_exports.object({
14148
+ machine: external_exports.string().min(1).optional(),
14149
+ state: external_exports.string().min(1),
14150
+ summary: external_exports.string().optional()
14151
+ }).strict()
14152
+ ]);
14071
14153
  var StateMachineTransitionSchema = external_exports.object({
14072
14154
  name: external_exports.string().min(1),
14073
14155
  from: external_exports.string().min(1),
14074
- to: external_exports.string().min(1)
14156
+ to: external_exports.string().min(1),
14157
+ label: external_exports.string().optional(),
14158
+ description: external_exports.string().optional(),
14159
+ action: StateTransitionActionSchema.optional(),
14160
+ assignee: StateTransitionAssigneeSchema.optional(),
14161
+ requirements: StateTransitionRequirementsSchema.optional(),
14162
+ permission: StateTransitionPermissionSchema.optional(),
14163
+ risk: external_exports.enum(["low", "medium", "high"]).optional(),
14164
+ expectedOutcome: StateTransitionExpectedOutcomeSchema.optional()
14075
14165
  }).strict();
14076
14166
  external_exports.object({
14077
14167
  name: external_exports.string().min(1),
14168
+ stateField: external_exports.string().min(1).optional(),
14078
14169
  entryState: external_exports.string().min(1),
14079
14170
  states: external_exports.array(StateMachineStateSchema).min(1),
14080
14171
  transitions: external_exports.array(StateMachineTransitionSchema),
@@ -14141,6 +14232,16 @@ var PoliciesSchema = external_exports.object({
14141
14232
  confirmWhen: external_exports.array(PolicyRuleSchema).optional(),
14142
14233
  denyWhen: external_exports.array(PolicyRuleSchema).optional()
14143
14234
  }).strict();
14235
+ var CreatesSchema = external_exports.union([
14236
+ external_exports.string().min(1),
14237
+ external_exports.object({
14238
+ className: external_exports.string().min(1),
14239
+ idPath: external_exports.string().min(1).optional(),
14240
+ pathPath: external_exports.string().min(1).optional(),
14241
+ statePath: external_exports.string().min(1).optional(),
14242
+ classStateHandle: external_exports.boolean().optional()
14243
+ }).strict()
14244
+ ]);
14144
14245
  external_exports.object({
14145
14246
  postCondition: external_exports.union([
14146
14247
  external_exports.string(),
@@ -14171,6 +14272,7 @@ external_exports.object({
14171
14272
  mode: external_exports.string().optional()
14172
14273
  }).strict()
14173
14274
  ]).optional(),
14275
+ creates: CreatesSchema.optional(),
14174
14276
  access: external_exports.enum(["read", "write", "ui"]).optional(),
14175
14277
  effectKind: external_exports.enum(["read", "write", "ui"]).optional(),
14176
14278
  sideEffect: external_exports.enum(["read", "write", "ui", "readonly", "read_only"]).optional(),
@@ -14398,6 +14500,7 @@ function mergeMethodSummaryPatch(target, patch) {
14398
14500
  if (patch.metamodels !== void 0) target.metamodels = patch.metamodels;
14399
14501
  if (patch.effectBehaviors !== void 0)
14400
14502
  target.effectBehaviors = patch.effectBehaviors;
14503
+ if (patch.creates !== void 0) target.creates = patch.creates;
14401
14504
  if (patch.static !== void 0) target.static = patch.static;
14402
14505
  }
14403
14506
  function toPascalCase2(value) {
@@ -14458,29 +14561,60 @@ function normalizeEffectBehaviorSummary(metamodels) {
14458
14561
  }
14459
14562
  return Object.keys(result).length > 0 ? result : null;
14460
14563
  }
14461
- function buildEffectBehaviorDocs(effectBehaviors) {
14462
- if (!effectBehaviors) {
14463
- return [];
14564
+ function normalizeCreationSummary(metamodels) {
14565
+ if (!isObject(metamodels)) return null;
14566
+ let raw = metamodels.creates;
14567
+ if (typeof raw === "string" && raw.trim().length > 0) {
14568
+ const trimmed = raw.trim();
14569
+ if (trimmed.startsWith("{") || trimmed.startsWith('"')) {
14570
+ try {
14571
+ raw = JSON.parse(trimmed);
14572
+ } catch {
14573
+ return { className: trimmed };
14574
+ }
14575
+ } else {
14576
+ return { className: trimmed };
14577
+ }
14464
14578
  }
14579
+ if (typeof raw === "string" && raw.trim().length > 0) {
14580
+ return { className: raw.trim() };
14581
+ }
14582
+ if (!isObject(raw)) return null;
14583
+ const className = typeof raw.className === "string" && raw.className.trim() ? raw.className.trim() : "";
14584
+ if (!className) return null;
14585
+ return {
14586
+ className,
14587
+ ...typeof raw.idPath === "string" && raw.idPath.trim() ? { idPath: raw.idPath.trim() } : {},
14588
+ ...typeof raw.pathPath === "string" && raw.pathPath.trim() ? { pathPath: raw.pathPath.trim() } : {},
14589
+ ...typeof raw.statePath === "string" && raw.statePath.trim() ? { statePath: raw.statePath.trim() } : {},
14590
+ ...typeof raw.classStateHandle === "boolean" ? { classStateHandle: raw.classStateHandle } : {}
14591
+ };
14592
+ }
14593
+ function buildEffectBehaviorDocs(effectBehaviors, creates) {
14465
14594
  const docs = [];
14466
- if (effectBehaviors.approvalRequired?.required) {
14595
+ if (creates) {
14596
+ docs.push(
14597
+ `Creation method: creates ${creates.className}. The agent may use generated class-level new-record action methods for this class.`
14598
+ );
14599
+ }
14600
+ if (effectBehaviors?.approvalRequired?.required) {
14467
14601
  docs.push(
14468
14602
  effectBehaviors.approvalRequired.reason ? `Approval required: ${effectBehaviors.approvalRequired.reason}.` : "Approval required before execution."
14469
14603
  );
14470
14604
  }
14471
- if (effectBehaviors.postCondition) {
14605
+ if (effectBehaviors?.postCondition) {
14472
14606
  docs.push(`Post-condition: ${effectBehaviors.postCondition.condition}.`);
14473
14607
  if (effectBehaviors.postCondition.description) {
14474
14608
  docs.push(effectBehaviors.postCondition.description);
14475
14609
  }
14476
14610
  }
14477
- if (effectBehaviors.dryRun?.enabled) {
14611
+ if (effectBehaviors?.dryRun?.enabled) {
14478
14612
  docs.push("Supports dry run.");
14479
14613
  if (effectBehaviors.dryRun.description) {
14480
14614
  docs.push(effectBehaviors.dryRun.description);
14481
14615
  }
14482
14616
  }
14483
- if (effectBehaviors.reverse) {
14617
+ if (effectBehaviors?.reverse) {
14484
14618
  if (effectBehaviors.reverse.handler) {
14485
14619
  docs.push(`Reverse handler: ${effectBehaviors.reverse.handler}.`);
14486
14620
  } else {
@@ -14539,13 +14673,21 @@ function buildEffectBehaviorMutations(toolPath, spec) {
14539
14673
  query: `mutation { at(path: ${JSON.stringify(toolPath)}) { set_approval_required(${args}) { kind } } }`
14540
14674
  });
14541
14675
  }
14676
+ if (spec.creates !== void 0) {
14677
+ mutations.push({
14678
+ label: `set creates on ${toolPath}`,
14679
+ query: `mutation { at(path: ${JSON.stringify(toolPath)}) { create_submodel(subpath: "creates", label: "creates") { set_string_value(value: ${JSON.stringify(
14680
+ JSON.stringify(spec.creates)
14681
+ )}) { done } } } }`
14682
+ });
14683
+ }
14542
14684
  return mutations;
14543
14685
  }
14544
14686
  function readMethodEffectBehaviors(rawMethod) {
14687
+ const metamodels = isObject(rawMethod.metamodels) ? rawMethod.metamodels : null;
14545
14688
  return {
14546
- effectBehaviors: normalizeEffectBehaviorSummary(
14547
- isObject(rawMethod.metamodels) ? rawMethod.metamodels : null
14548
- )
14689
+ effectBehaviors: normalizeEffectBehaviorSummary(metamodels),
14690
+ creates: normalizeCreationSummary(metamodels)
14549
14691
  };
14550
14692
  }
14551
14693
  var effectBehaviorsMetamodelPackage = defineMetamodelPackage({
@@ -14567,6 +14709,10 @@ var effectBehaviorsMetamodelPackage = defineMetamodelPackage({
14567
14709
  {
14568
14710
  key: "approvalRequired",
14569
14711
  description: "Boolean or `{ required, reason, mode }`."
14712
+ },
14713
+ {
14714
+ key: "creates",
14715
+ description: 'Marks a static method as an allowed creator for a class. Use `creates: "class_name"` or `{ className, idPath, pathPath, statePath, classStateHandle }`.'
14570
14716
  }
14571
14717
  ]
14572
14718
  },
@@ -14686,7 +14832,10 @@ var effectBehaviorsMetamodelPackage = defineMetamodelPackage({
14686
14832
  ...methodIR,
14687
14833
  docs: [
14688
14834
  ...methodIR.docs,
14689
- ...buildEffectBehaviorDocs(methodSummary.effectBehaviors)
14835
+ ...buildEffectBehaviorDocs(
14836
+ methodSummary.effectBehaviors,
14837
+ methodSummary.creates
14838
+ )
14690
14839
  ]
14691
14840
  };
14692
14841
  }
@@ -15305,15 +15454,47 @@ var searchableMetamodelPackage = defineMetamodelPackage({
15305
15454
 
15306
15455
  // ../metamodel-state-machine/src/index.ts
15307
15456
  function normalizeStateMachines(values) {
15457
+ const parseJsonRecord = (value) => {
15458
+ if (value && typeof value === "object" && !Array.isArray(value)) {
15459
+ return value;
15460
+ }
15461
+ if (typeof value !== "string" || !value.trim()) return null;
15462
+ try {
15463
+ const parsed = JSON.parse(value);
15464
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
15465
+ } catch {
15466
+ return null;
15467
+ }
15468
+ };
15469
+ const parseJsonValue = (value) => {
15470
+ if (value === null || typeof value === "undefined") return null;
15471
+ if (typeof value !== "string") return value;
15472
+ if (!value.trim()) return null;
15473
+ try {
15474
+ return JSON.parse(value);
15475
+ } catch {
15476
+ return value;
15477
+ }
15478
+ };
15308
15479
  return (values || []).map((machine) => {
15309
15480
  const states = (machine?.states || []).map((state) => ({
15310
15481
  name: String(state?.name || ""),
15311
- isFinal: Boolean(state?.is_final)
15482
+ label: typeof state?.label === "string" ? state.label : null,
15483
+ description: typeof state?.description === "string" ? state.description : null,
15484
+ isFinal: Boolean(state?.is_final ?? state?.isFinal)
15312
15485
  })).filter((state) => state.name.length > 0);
15313
15486
  const transitions = (machine?.transitions || []).map((transition) => ({
15314
15487
  name: String(transition?.name || ""),
15315
15488
  from: String(transition?.from?.name || ""),
15316
- to: String(transition?.to?.name || "")
15489
+ to: String(transition?.to?.name || ""),
15490
+ label: typeof transition?.label === "string" ? transition.label : null,
15491
+ description: typeof transition?.description === "string" ? transition.description : null,
15492
+ action: parseJsonRecord(transition?.action) || parseJsonRecord(transition?.action_json),
15493
+ assignee: parseJsonRecord(transition?.assignee) || parseJsonRecord(transition?.assignee_json),
15494
+ requirements: parseJsonRecord(transition?.requirements) || parseJsonRecord(transition?.requirements_json),
15495
+ permission: parseJsonValue(transition?.permission) ?? parseJsonValue(transition?.permission_json),
15496
+ risk: transition?.risk === "low" || transition?.risk === "medium" || transition?.risk === "high" ? transition.risk : null,
15497
+ expectedOutcome: parseJsonValue(transition?.expectedOutcome) ?? parseJsonValue(transition?.expected_outcome_json)
15317
15498
  })).filter(
15318
15499
  (transition) => transition.name.length > 0 && transition.from.length > 0 && transition.to.length > 0
15319
15500
  );
@@ -15335,6 +15516,15 @@ function transitionTypeName(className, machineName) {
15335
15516
  function pathTypeName(className, machineName) {
15336
15517
  return `${stateTypeName(className, machineName)}Path`;
15337
15518
  }
15519
+ function methodToken(value) {
15520
+ const token = String(value || "").trim().replace(/[^A-Za-z0-9_]+/g, "_").replace(/^_+|_+$/g, "").toLowerCase();
15521
+ return token || "state";
15522
+ }
15523
+ function transitionActionsForMachine(machine) {
15524
+ return Object.fromEntries(
15525
+ (machine.transitions || []).filter((transition) => transition.action?.effect).map((transition) => [transition.name, transition.action])
15526
+ );
15527
+ }
15338
15528
  function normalizeStateDefinitions(machine) {
15339
15529
  const finalStates = new Set(machine.finalStates || []);
15340
15530
  const states = /* @__PURE__ */ new Map();
@@ -15348,6 +15538,8 @@ function normalizeStateDefinitions(machine) {
15348
15538
  }
15349
15539
  states.set(rawState.name, {
15350
15540
  name: rawState.name,
15541
+ label: rawState.label,
15542
+ description: rawState.description,
15351
15543
  isFinal: Boolean(rawState.isFinal) || finalStates.has(rawState.name)
15352
15544
  });
15353
15545
  }
@@ -15359,6 +15551,44 @@ function normalizeStateDefinitions(machine) {
15359
15551
  }
15360
15552
  return [...states.values()];
15361
15553
  }
15554
+ function transitionMetadataGraphqlArgs(transition) {
15555
+ const args = [];
15556
+ if (typeof transition.label === "string") {
15557
+ args.push(`label: ${JSON.stringify(transition.label)}`);
15558
+ }
15559
+ if (typeof transition.description === "string") {
15560
+ args.push(`description: ${JSON.stringify(transition.description)}`);
15561
+ }
15562
+ if (transition.action) {
15563
+ args.push(
15564
+ `action_json: ${JSON.stringify(JSON.stringify(transition.action))}`
15565
+ );
15566
+ }
15567
+ if (transition.assignee) {
15568
+ args.push(
15569
+ `assignee_json: ${JSON.stringify(JSON.stringify(transition.assignee))}`
15570
+ );
15571
+ }
15572
+ if (transition.requirements) {
15573
+ args.push(
15574
+ `requirements_json: ${JSON.stringify(JSON.stringify(transition.requirements))}`
15575
+ );
15576
+ }
15577
+ if (transition.permission) {
15578
+ args.push(
15579
+ `permission_json: ${JSON.stringify(JSON.stringify(transition.permission))}`
15580
+ );
15581
+ }
15582
+ if (transition.risk) {
15583
+ args.push(`risk: ${JSON.stringify(transition.risk)}`);
15584
+ }
15585
+ if (transition.expectedOutcome) {
15586
+ args.push(
15587
+ `expected_outcome_json: ${JSON.stringify(JSON.stringify(transition.expectedOutcome))}`
15588
+ );
15589
+ }
15590
+ return args.length > 0 ? `, ${args.join(", ")}` : "";
15591
+ }
15362
15592
  function buildStateMachineModelMutations(modelPath, machines) {
15363
15593
  const mutations = [];
15364
15594
  for (const machine of machines || []) {
@@ -15369,12 +15599,13 @@ function buildStateMachineModelMutations(modelPath, machines) {
15369
15599
  )}, entry_state: ${JSON.stringify(machine.entryState)}) { name } } }`
15370
15600
  });
15371
15601
  for (const state of normalizeStateDefinitions(machine)) {
15372
- if (state.name === machine.entryState && !state.isFinal) continue;
15602
+ if (state.name === machine.entryState && !state.isFinal && !state.label && !state.description)
15603
+ continue;
15373
15604
  mutations.push({
15374
15605
  label: `add state ${state.name} on ${modelPath}.${machine.name}`,
15375
15606
  query: `mutation { at(path: ${JSON.stringify(modelPath)}) { state_machine(name: ${JSON.stringify(
15376
15607
  machine.name
15377
- )}) { add_state(name: ${JSON.stringify(state.name)}, is_final: ${state.isFinal}) { name } } } }`
15608
+ )}) { add_state(name: ${JSON.stringify(state.name)}, is_final: ${state.isFinal}, label: ${JSON.stringify(state.label || null)}, description: ${JSON.stringify(state.description || null)}) { name } } } }`
15378
15609
  });
15379
15610
  }
15380
15611
  for (const transition of machine.transitions || []) {
@@ -15386,7 +15617,7 @@ function buildStateMachineModelMutations(modelPath, machines) {
15386
15617
  transition.name
15387
15618
  )}, from: ${JSON.stringify(transition.from)}, to: ${JSON.stringify(
15388
15619
  transition.to
15389
- )}) { name } } } }`
15620
+ )}${transitionMetadataGraphqlArgs(transition)}) { name } } } }`
15390
15621
  });
15391
15622
  }
15392
15623
  }
@@ -15413,7 +15644,7 @@ function buildMachineMethods(classSummary, machine) {
15413
15644
  const transitionName = transitionTypeName(classSummary.name, machine.name);
15414
15645
  pathTypeName(classSummary.name, machine.name);
15415
15646
  const docsPrefix = `${classSummary.name}.${machine.name}`;
15416
- return [
15647
+ const methods = [
15417
15648
  {
15418
15649
  name: `get_${machine.name}`,
15419
15650
  docs: [`Get the current ${docsPrefix} state.`],
@@ -15509,6 +15740,99 @@ function buildMachineMethods(classSummary, machine) {
15509
15740
  }
15510
15741
  }
15511
15742
  ];
15743
+ const creationMethods = (classSummary.methods || []).filter(
15744
+ (method) => method.static === true && Boolean(method.creates) && method.creates?.className === classSummary.name && typeof method.effectKey === "string" && method.effectKey.length > 0
15745
+ );
15746
+ for (const state of machine.states) {
15747
+ const stateNameValue = typeof state === "string" ? state : String(state?.name || "");
15748
+ if (!stateNameValue) continue;
15749
+ const token = methodToken(stateNameValue);
15750
+ methods.push(
15751
+ {
15752
+ name: `reach_${machine.name}_to_${token}`,
15753
+ docs: [`Reach ${docsPrefix} state ${stateNameValue}.`],
15754
+ static: false,
15755
+ params: [],
15756
+ returnType: `Promise<${toPascalCase2(classSummary.name)}>`,
15757
+ runtime: {
15758
+ kind: "state_machine",
15759
+ machineName: machine.name,
15760
+ className: classSummary.name,
15761
+ stateTypeName: stateName,
15762
+ transitionTypeName: transitionName,
15763
+ operation: "reach",
15764
+ targetState: stateNameValue,
15765
+ transitionActions: transitionActionsForMachine(machine)
15766
+ }
15767
+ },
15768
+ {
15769
+ name: `prepare_${machine.name}_to_${token}`,
15770
+ docs: [
15771
+ `Prepare a reviewable artifact that can move ${docsPrefix} to ${stateNameValue}.`
15772
+ ],
15773
+ static: false,
15774
+ params: [],
15775
+ returnType: "Promise<SessionArtifactRecord>",
15776
+ runtime: {
15777
+ kind: "state_machine",
15778
+ machineName: machine.name,
15779
+ className: classSummary.name,
15780
+ stateTypeName: stateName,
15781
+ transitionTypeName: transitionName,
15782
+ operation: "prepare_reach",
15783
+ targetState: stateNameValue,
15784
+ transitionActions: transitionActionsForMachine(machine)
15785
+ }
15786
+ }
15787
+ );
15788
+ for (const creationMethod of creationMethods) {
15789
+ const creationRuntime = {
15790
+ kind: "state_machine",
15791
+ machineName: machine.name,
15792
+ className: classSummary.name,
15793
+ stateTypeName: stateName,
15794
+ transitionTypeName: transitionName,
15795
+ operation: "prepare_create_reach",
15796
+ targetState: stateNameValue,
15797
+ transitionActions: transitionActionsForMachine(machine),
15798
+ creation: {
15799
+ methodName: creationMethod.name,
15800
+ effectKey: creationMethod.effectKey || creationMethod.name,
15801
+ inputSchema: creationMethod.inputSchema,
15802
+ outputSchema: creationMethod.outputSchema,
15803
+ creates: creationMethod.creates
15804
+ }
15805
+ };
15806
+ const viaName = `prepare_${machine.name}_to_${token}_via_${methodToken(creationMethod.name)}`;
15807
+ methods.push({
15808
+ name: viaName,
15809
+ docs: [
15810
+ `Prepare a reviewable artifact that will create a new ${classSummary.name} through ${creationMethod.name}, then move ${docsPrefix} to ${stateNameValue}.`
15811
+ ],
15812
+ static: true,
15813
+ params: [
15814
+ { name: "input", type: "Record<string, any>", optional: true }
15815
+ ],
15816
+ returnType: "Promise<SessionArtifactRecord>",
15817
+ runtime: creationRuntime
15818
+ });
15819
+ if (creationMethods.length === 1) {
15820
+ methods.push({
15821
+ name: `prepare_${machine.name}_to_${token}`,
15822
+ docs: [
15823
+ `Prepare a reviewable artifact that will create a new ${classSummary.name}, then move ${docsPrefix} to ${stateNameValue}.`
15824
+ ],
15825
+ static: true,
15826
+ params: [
15827
+ { name: "input", type: "Record<string, any>", optional: true }
15828
+ ],
15829
+ returnType: "Promise<SessionArtifactRecord>",
15830
+ runtime: creationRuntime
15831
+ });
15832
+ }
15833
+ }
15834
+ }
15835
+ return methods;
15512
15836
  }
15513
15837
  function readStateMachineSummaries(rawClass) {
15514
15838
  return {
@@ -15531,8 +15855,8 @@ var stateMachineMetamodelPackage = defineMetamodelPackage({
15531
15855
  type StateMachineMutation {
15532
15856
  name: String!
15533
15857
  state_machine: StateMachine!
15534
- add_state(name: String!, is_final: Boolean): StateMachineMutation!
15535
- add_transition(name: String!, from: String!, to: String!): StateMachineMutation!
15858
+ add_state(name: String!, is_final: Boolean, label: String, description: String): StateMachineMutation!
15859
+ add_transition(name: String!, from: String!, to: String!, label: String, description: String, action_json: String, assignee_json: String, requirements_json: String, permission_json: String, risk: String, expected_outcome_json: String): StateMachineMutation!
15536
15860
  activate_transition(name: String!): StateMachineMutation!
15537
15861
  }
15538
15862
 
@@ -15549,6 +15873,7 @@ var stateMachineMetamodelPackage = defineMetamodelPackage({
15549
15873
  type StateMachineSnapshotMutation {
15550
15874
  snapshot: StateMachineSnapshot!
15551
15875
  activate_transition(name: String!): StateMachineSnapshotMutation!
15876
+ observe_state(state: String!, force: Boolean, source: String): StateMachineSnapshotMutation!
15552
15877
  }
15553
15878
 
15554
15879
  type StateMachine {
@@ -15568,6 +15893,8 @@ var stateMachineMetamodelPackage = defineMetamodelPackage({
15568
15893
 
15569
15894
  type StateMachineState {
15570
15895
  name: String!
15896
+ label: String
15897
+ description: String
15571
15898
  is_final: Boolean!
15572
15899
  }
15573
15900
 
@@ -15575,6 +15902,14 @@ var stateMachineMetamodelPackage = defineMetamodelPackage({
15575
15902
  name: String!
15576
15903
  from: StateMachineState!
15577
15904
  to: StateMachineState!
15905
+ label: String
15906
+ description: String
15907
+ action_json: String
15908
+ assignee_json: String
15909
+ requirements_json: String
15910
+ permission_json: String
15911
+ risk: String
15912
+ expected_outcome_json: String
15578
15913
  }
15579
15914
 
15580
15915
  type StateMachinePath {
@@ -15627,23 +15962,47 @@ var stateMachineMetamodelPackage = defineMetamodelPackage({
15627
15962
  StateMachineMutation: {
15628
15963
  name: (value) => value.name,
15629
15964
  state_machine: async (value) => await run(value.target.state_machine(value.name)),
15630
- add_state: async (value, { name, is_final }) => {
15965
+ add_state: async (value, { name, is_final, label, description }) => {
15631
15966
  await run(
15632
15967
  value.target.add_state_machine_state(
15633
15968
  value.name,
15634
15969
  name,
15635
- is_final ?? false
15970
+ is_final ?? false,
15971
+ label,
15972
+ description
15636
15973
  )
15637
15974
  );
15638
15975
  return value;
15639
15976
  },
15640
- add_transition: async (value, { name, from, to }) => {
15977
+ add_transition: async (value, {
15978
+ name,
15979
+ from,
15980
+ to,
15981
+ label,
15982
+ description,
15983
+ action_json,
15984
+ assignee_json,
15985
+ requirements_json,
15986
+ permission_json,
15987
+ risk,
15988
+ expected_outcome_json
15989
+ }) => {
15641
15990
  await run(
15642
15991
  value.target.add_state_machine_transition(
15643
15992
  value.name,
15644
15993
  name,
15645
15994
  from,
15646
- to
15995
+ to,
15996
+ {
15997
+ label,
15998
+ description,
15999
+ actionJson: action_json,
16000
+ assigneeJson: assignee_json,
16001
+ requirementsJson: requirements_json,
16002
+ permissionJson: permission_json,
16003
+ risk,
16004
+ expectedOutcomeJson: expected_outcome_json
16005
+ }
15647
16006
  )
15648
16007
  );
15649
16008
  return value;
@@ -15662,16 +16021,37 @@ var stateMachineMetamodelPackage = defineMetamodelPackage({
15662
16021
  value.target.activate_state_machine_transition(value.name, name)
15663
16022
  );
15664
16023
  return value;
16024
+ },
16025
+ observe_state: async (value, { state, force, source }) => {
16026
+ await run(
16027
+ value.target.observe_state_machine_state(
16028
+ value.name,
16029
+ state,
16030
+ force === true,
16031
+ source
16032
+ )
16033
+ );
16034
+ return value;
15665
16035
  }
15666
16036
  },
15667
16037
  StateMachineState: {
15668
16038
  name: (value) => value.name,
16039
+ label: (value) => value.label || null,
16040
+ description: (value) => value.description || null,
15669
16041
  is_final: (value) => value.is_final
15670
16042
  },
15671
16043
  StateMachineTransition: {
15672
16044
  name: (value) => value.name,
15673
16045
  from: (value) => value.from_state || { name: value.from, is_final: false },
15674
- to: (value) => value.to_state || { name: value.to, is_final: false }
16046
+ to: (value) => value.to_state || { name: value.to, is_final: false },
16047
+ label: (value) => value.label || null,
16048
+ description: (value) => value.description || null,
16049
+ action_json: (value) => value.action_json || null,
16050
+ assignee_json: (value) => value.assignee_json || null,
16051
+ requirements_json: (value) => value.requirements_json || null,
16052
+ permission_json: (value) => value.permission_json || null,
16053
+ risk: (value) => value.risk || null,
16054
+ expected_outcome_json: (value) => value.expected_outcome_json || null
15675
16055
  },
15676
16056
  StateMachinePath: {
15677
16057
  states: (value) => value.states,
@@ -15738,6 +16118,14 @@ var stateMachineMetamodelPackage = defineMetamodelPackage({
15738
16118
  name
15739
16119
  from { name }
15740
16120
  to { name }
16121
+ label
16122
+ description
16123
+ action_json
16124
+ assignee_json
16125
+ requirements_json
16126
+ permission_json
16127
+ risk
16128
+ expected_outcome_json
15741
16129
  }
15742
16130
  }`
15743
16131
  ]
@@ -19145,6 +19533,9 @@ function rpcTimeoutMsForMethod(method) {
19145
19533
  return DOMAIN_PACKAGE_RPC_TIMEOUT_MS;
19146
19534
  case "client.heartbeat":
19147
19535
  case "effects.publishCatalog":
19536
+ case "effects.resetCatalog":
19537
+ case "effects.addCatalog":
19538
+ case "effects.removeCatalog":
19148
19539
  case "effects.refresh":
19149
19540
  return EFFECT_CONTROL_RPC_TIMEOUT_MS;
19150
19541
  case "harness.run":
@@ -19890,6 +20281,9 @@ function resolvePromptAnswer(prompt3, answer) {
19890
20281
 
19891
20282
  // src/session.ts
19892
20283
  var PROMPT_TRANSCRIPT_APPEND_TIMEOUT_MS = 5e3;
20284
+ function toPascalCase3(value) {
20285
+ return value.split(/[_:\-\s]+/).filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
20286
+ }
19893
20287
  function withPromptTranscriptTimeout(promise) {
19894
20288
  let timeout = null;
19895
20289
  return Promise.race([
@@ -20452,9 +20846,7 @@ var Session = class {
20452
20846
  if (classes && Object.keys(classes).length > 0) {
20453
20847
  let docs2 = "# Domain Documentation\n\n";
20454
20848
  docs2 += "Import concrete classes from `@granular/domain/<Class>` and global backend actions from `@granular/actions/backend`:\n\n";
20455
- const classNames = Object.keys(classes).map(
20456
- (c) => c.charAt(0).toUpperCase() + c.slice(1)
20457
- );
20849
+ const classNames = Object.keys(classes).map(toPascalCase3);
20458
20850
  const globalNames = (globalTools || []).map((t) => t.name);
20459
20851
  const importLines = [
20460
20852
  ...classNames.map(
@@ -20468,7 +20860,7 @@ ${importLines.join("\n") || "// No generated domain imports available."}
20468
20860
 
20469
20861
  `;
20470
20862
  for (const [className, cls] of Object.entries(classes)) {
20471
- const TsName = className.charAt(0).toUpperCase() + className.slice(1);
20863
+ const TsName = toPascalCase3(className);
20472
20864
  docs2 += `## ${TsName}
20473
20865
 
20474
20866
  `;
@@ -21458,6 +21850,28 @@ function asString(value) {
21458
21850
  function trimString(value) {
21459
21851
  return typeof value === "string" ? value.trim() : "";
21460
21852
  }
21853
+ function compactJson(value, maxLength = 320) {
21854
+ if (value === void 0 || value === null) return void 0;
21855
+ try {
21856
+ const json = JSON.stringify(value);
21857
+ if (!json || json === "undefined") return void 0;
21858
+ return json.length > maxLength ? `${json.slice(0, maxLength)}...` : json;
21859
+ } catch {
21860
+ return String(value);
21861
+ }
21862
+ }
21863
+ function artifactRecordsById(liveDoc) {
21864
+ const artifacts = asRecord3(liveDoc?.artifacts);
21865
+ const byId = asRecord3(artifacts?.byId) || {};
21866
+ return Object.fromEntries(
21867
+ Object.entries(byId).map(([artifactId, value]) => {
21868
+ const record = asRecord3(value);
21869
+ return record ? [artifactId, record] : null;
21870
+ }).filter(
21871
+ (entry) => Boolean(entry)
21872
+ )
21873
+ );
21874
+ }
21461
21875
  function normalizeShowRefs(value) {
21462
21876
  const record = asRecord3(value);
21463
21877
  if (!record) return void 0;
@@ -21474,9 +21888,31 @@ function normalizeShowRefs(value) {
21474
21888
  entryPaths: normalizeRefs(record.entryPaths),
21475
21889
  listNames: normalizeRefs(record.listNames),
21476
21890
  variableNames: normalizeRefs(record.variableNames),
21477
- fileIds: normalizeRefs(record.fileIds)
21891
+ fileIds: normalizeRefs(record.fileIds),
21892
+ sessionArtifactIds: normalizeRefs(record.sessionArtifactIds),
21893
+ actionSuggestions: normalizeActionSuggestions(record.actionSuggestions)
21478
21894
  };
21479
- return show.entryPaths || show.listNames || show.variableNames || show.fileIds ? show : void 0;
21895
+ return show.entryPaths || show.listNames || show.variableNames || show.fileIds || show.sessionArtifactIds || show.actionSuggestions ? show : void 0;
21896
+ }
21897
+ function normalizeActionSuggestions(value) {
21898
+ if (!Array.isArray(value)) return void 0;
21899
+ const suggestions = [];
21900
+ for (const item of value) {
21901
+ const record = asRecord3(item);
21902
+ if (!record) continue;
21903
+ const label = trimString(record.label);
21904
+ if (!label) continue;
21905
+ const suggestionId = trimString(record.suggestionId) || trimString(record.id) || label;
21906
+ suggestions.push({
21907
+ suggestionId,
21908
+ label,
21909
+ ...typeof record.description === "string" ? { description: record.description } : {},
21910
+ ...asRecord3(record.artifact) ? { artifact: asRecord3(record.artifact) } : {},
21911
+ ...asRecord3(record.target) ? { target: asRecord3(record.target) } : {},
21912
+ ...asRecord3(record.metadata) ? { metadata: asRecord3(record.metadata) } : {}
21913
+ });
21914
+ }
21915
+ return suggestions.length ? suggestions : void 0;
21480
21916
  }
21481
21917
  function stringifyTranscriptValue(value, fallback2 = "") {
21482
21918
  if (typeof value === "string") {
@@ -21496,12 +21932,139 @@ function stringifyTranscriptValue(value, fallback2 = "") {
21496
21932
  return String(value);
21497
21933
  }
21498
21934
  }
21499
- function buildArtifactHistory(show) {
21935
+ function latestInputEditSummary(metadata) {
21936
+ const lastInputEdit = asRecord3(metadata.lastInputEdit);
21937
+ if (!lastInputEdit) return null;
21938
+ const source = asString(lastInputEdit.source) || "unknown";
21939
+ const actor = asString(lastInputEdit.actorSubjectId) || asString(lastInputEdit.actorPermissionProfileName) || asString(lastInputEdit.jobId) || null;
21940
+ const inputKeys = Array.isArray(lastInputEdit.changedInputKeys) ? lastInputEdit.changedInputKeys.filter(
21941
+ (key) => typeof key === "string" && key.trim().length > 0
21942
+ ).slice(0, 6) : [];
21943
+ const relationshipKeys = Array.isArray(lastInputEdit.changedRelationshipKeys) ? lastInputEdit.changedRelationshipKeys.filter(
21944
+ (key) => typeof key === "string" && key.trim().length > 0
21945
+ ).slice(0, 6) : [];
21946
+ const changed = [
21947
+ inputKeys.length ? `inputs=${inputKeys.join(",")}` : null,
21948
+ relationshipKeys.length ? `relationships=${relationshipKeys.join(",")}` : null
21949
+ ].filter(Boolean);
21950
+ return `lastEdit=${source}${actor ? ` by ${actor}` : ""}${changed.length ? ` (${changed.join("; ")})` : ""}`;
21951
+ }
21952
+ function artifactIssueSummary(record) {
21953
+ const validation = asRecord3(record.validation);
21954
+ if (!validation) return null;
21955
+ const issues = Array.isArray(validation.issues) ? validation.issues.map((issue) => asRecord3(issue)).filter((issue) => Boolean(issue)).slice(0, 3) : [];
21956
+ if (issues.length > 0) {
21957
+ return `issues=${issues.map((issue) => {
21958
+ const code = asString(issue.code) || asString(issue.kind) || "issue";
21959
+ const path7 = asString(issue.path);
21960
+ const message = trimString(issue.message);
21961
+ return `${code}${path7 ? ` at ${path7}` : ""}${message ? ` (${message})` : ""}`;
21962
+ }).join("; ")}`;
21963
+ }
21964
+ const error2 = trimString(validation.error) || trimString(validation.reason) || trimString(validation.message);
21965
+ return error2 ? `validation=${error2}` : null;
21966
+ }
21967
+ function artifactExecutionSummary(metadata) {
21968
+ const execution = asRecord3(metadata.execution);
21969
+ if (!execution) return null;
21970
+ const result = asRecord3(execution.result);
21971
+ const awaiting = asString(result?.awaiting) || asString(execution.awaiting);
21972
+ const pendingTransition = asString(result?.pendingTransition) || asString(execution.pendingTransition);
21973
+ const approval = asRecord3(result?.approval) || asRecord3(execution.approval);
21974
+ const approvalTarget = asString(approval?.permissionProfileName) || asString(approval?.permissionProfileId) || asString(approval?.assigneeSubjectId);
21975
+ const error2 = trimString(execution.error);
21976
+ const pieces = [
21977
+ awaiting ? `awaiting=${awaiting}` : null,
21978
+ pendingTransition ? `pendingTransition=${pendingTransition}` : null,
21979
+ approvalTarget ? `approvalTarget=${approvalTarget}` : null,
21980
+ error2 ? `executionError=${error2}` : null
21981
+ ].filter(Boolean);
21982
+ return pieces.length ? pieces.join("; ") : null;
21983
+ }
21984
+ function artifactStatePathSummary(metadata) {
21985
+ const statePlan = asRecord3(metadata.statePlan);
21986
+ if (!statePlan) return null;
21987
+ const machineName = asString(statePlan.machineName);
21988
+ const targetState = asString(statePlan.targetState);
21989
+ const objectPath = asString(statePlan.objectPath);
21990
+ const approvedTransitions = Array.isArray(statePlan.approvedTransitions) ? statePlan.approvedTransitions.length : 0;
21991
+ const approvalDecisions = Array.isArray(statePlan.approvalDecisions) ? statePlan.approvalDecisions.length : 0;
21992
+ const pieces = [
21993
+ machineName || targetState ? `statePath=${machineName || "state_machine"}${targetState ? ` -> ${targetState}` : ""}` : null,
21994
+ objectPath ? `objectPath=${objectPath}` : null,
21995
+ approvedTransitions ? `approvedTransitions=${approvedTransitions}` : null,
21996
+ approvalDecisions ? `approvalDecisions=${approvalDecisions}` : null
21997
+ ].filter(Boolean);
21998
+ return pieces.length ? pieces.join("; ") : null;
21999
+ }
22000
+ function artifactSummaryLine(artifactId, record) {
22001
+ if (!record) return `- ${artifactId}: unavailable in session artifact store`;
22002
+ const label = trimString(record.label) || artifactId;
22003
+ const kind = asString(record.kind) || "artifact";
22004
+ const status = asString(record.status) || "unknown";
22005
+ const createdByJobId = asString(record.createdByJobId);
22006
+ const target = asRecord3(record.target);
22007
+ const metadata = asRecord3(record.metadata) || {};
22008
+ const subArtifactIds = Array.isArray(record.subArtifactIds) ? record.subArtifactIds.filter(
22009
+ (id) => typeof id === "string" && id.trim().length > 0
22010
+ ).slice(0, 8) : [];
22011
+ const relationships = compactJson(record.relationships, 220);
22012
+ const pieces = [
22013
+ `kind=${kind}`,
22014
+ `status=${status}`,
22015
+ createdByJobId ? `createdByJob=${createdByJobId}` : null,
22016
+ target ? `target=${asString(target.className) || "record"}:${asString(target.id) || "unknown"}${asString(target.label) ? ` (${asString(target.label)})` : ""}` : null,
22017
+ artifactStatePathSummary(metadata),
22018
+ artifactExecutionSummary(metadata),
22019
+ artifactIssueSummary(record),
22020
+ latestInputEditSummary(metadata),
22021
+ subArtifactIds.length ? `subArtifacts=${subArtifactIds.join(",")}` : null,
22022
+ relationships ? `relationships=${relationships}` : null
22023
+ ].filter(Boolean);
22024
+ return `- ${artifactId}: ${label}${pieces.length ? `; ${pieces.join("; ")}` : ""}`;
22025
+ }
22026
+ function buildArtifactHistory(show, artifactsById) {
21500
22027
  if (!show) return void 0;
21501
- return `[Agent message]
22028
+ const artifactIds = show.sessionArtifactIds || [];
22029
+ const actionSuggestions = show.actionSuggestions || [];
22030
+ if (artifactIds.length === 0 && actionSuggestions.length === 0) {
22031
+ return `[Agent message]
21502
22032
  ${stringifyTranscriptValue({ show }, "")}`;
22033
+ }
22034
+ const lines = artifactIds.slice(0, 8).map(
22035
+ (artifactId) => artifactSummaryLine(artifactId, artifactsById?.[artifactId])
22036
+ );
22037
+ if (artifactIds.length > 8) {
22038
+ lines.push(`- ${artifactIds.length - 8} more artifacts omitted`);
22039
+ }
22040
+ if (actionSuggestions.length > 0) {
22041
+ if (artifactIds.length > 0) lines.push("[Agent suggested actions]");
22042
+ for (const suggestion of actionSuggestions.slice(0, 8)) {
22043
+ lines.push(
22044
+ `- ${suggestion.label}${suggestion.description ? `; ${suggestion.description}` : ""}`
22045
+ );
22046
+ }
22047
+ if (actionSuggestions.length > 8) {
22048
+ lines.push(`- ${actionSuggestions.length - 8} more suggestions omitted`);
22049
+ }
22050
+ }
22051
+ const otherRefs = {
22052
+ entryPaths: show.entryPaths,
22053
+ listNames: show.listNames,
22054
+ variableNames: show.variableNames,
22055
+ fileIds: show.fileIds
22056
+ };
22057
+ const hasOtherRefs = Object.values(otherRefs).some(
22058
+ (value) => Array.isArray(value) && value.length > 0
22059
+ );
22060
+ const title = artifactIds.length > 0 ? "[Agent displayed session artifacts]" : "[Agent suggested actions]";
22061
+ return [
22062
+ title,
22063
+ ...lines,
22064
+ hasOtherRefs ? `Other shown refs: ${stringifyTranscriptValue(otherRefs, "")}` : null
22065
+ ].filter(Boolean).join("\n");
21503
22066
  }
21504
- function normalizeConversationMessage(raw) {
22067
+ function normalizeConversationMessage(raw, artifactsById) {
21505
22068
  const record = asRecord3(raw);
21506
22069
  if (!record) return null;
21507
22070
  const role = record.role === "user" ? "user" : record.role === "assistant" ? "assistant" : null;
@@ -21513,6 +22076,12 @@ function normalizeConversationMessage(raw) {
21513
22076
  const id = asString(record.id) || crypto.randomUUID();
21514
22077
  const timestamp = asNumber(record.timestamp) || asNumber(record.ts) || 0;
21515
22078
  if (!content && !show) return null;
22079
+ const artifactHistory = buildArtifactHistory(show, artifactsById);
22080
+ const historyContent = role === "assistant" ? content && artifactHistory ? `[Assistant reply]
22081
+ ${content}
22082
+
22083
+ ${artifactHistory}` : content ? `[Assistant reply]
22084
+ ${content}` : artifactHistory : void 0;
21516
22085
  return {
21517
22086
  id,
21518
22087
  role,
@@ -21521,8 +22090,7 @@ function normalizeConversationMessage(raw) {
21521
22090
  jobId: asString(record.jobId),
21522
22091
  promptId: asString(record.promptId),
21523
22092
  show,
21524
- historyContent: role === "assistant" ? content ? `[Assistant reply]
21525
- ${content}` : buildArtifactHistory(show) : void 0,
22093
+ historyContent,
21526
22094
  source: "conversation"
21527
22095
  };
21528
22096
  }
@@ -21565,7 +22133,7 @@ ${assistantContent}`,
21565
22133
  return entries;
21566
22134
  });
21567
22135
  }
21568
- function normalizeAgentMessageEntries(jobId, rawMessages) {
22136
+ function normalizeAgentMessageEntries(jobId, rawMessages, artifactsById) {
21569
22137
  return asArray(rawMessages).map((value) => asRecord3(value)).filter((value) => Boolean(value)).sort(
21570
22138
  (left, right) => (asNumber(left.timestamp) || asNumber(left.ts) || 0) - (asNumber(right.timestamp) || asNumber(right.ts) || 0)
21571
22139
  ).flatMap((message) => {
@@ -21596,14 +22164,14 @@ ${reply}`,
21596
22164
  timestamp,
21597
22165
  jobId,
21598
22166
  show,
21599
- historyContent: buildArtifactHistory(show),
22167
+ historyContent: buildArtifactHistory(show, artifactsById),
21600
22168
  source: "job_agent_message"
21601
22169
  });
21602
22170
  }
21603
22171
  return entries;
21604
22172
  });
21605
22173
  }
21606
- function buildJobFallbackEntries(jobId, job2, sessionHeap) {
22174
+ function buildJobFallbackEntries(jobId, job2, sessionHeap, artifactsById) {
21607
22175
  const timestamp = asNumber(job2.finishedAt) || asNumber(job2.startedAt) || asNumber(job2.submittedAt) || 0;
21608
22176
  const resultPreview = stringifyTranscriptValue(
21609
22177
  job2.result,
@@ -21641,7 +22209,7 @@ ${responseText}`,
21641
22209
  timestamp,
21642
22210
  jobId,
21643
22211
  show,
21644
- historyContent: buildArtifactHistory(show),
22212
+ historyContent: buildArtifactHistory(show, artifactsById),
21645
22213
  source: "job_result"
21646
22214
  });
21647
22215
  }
@@ -21695,10 +22263,11 @@ function buildJobCodeEntry(jobId, job2) {
21695
22263
  function buildSessionTranscript(input) {
21696
22264
  const liveDoc = input.liveDoc || null;
21697
22265
  const sessionHeap = input.sessionHeap || EMPTY_HEAP;
22266
+ const artifactsById = artifactRecordsById(liveDoc);
21698
22267
  const transcript = [];
21699
22268
  const conversationMessages = asArray(
21700
22269
  asRecord3(liveDoc?.conversation)?.messages
21701
- ).map((message) => normalizeConversationMessage(message)).filter((message) => Boolean(message));
22270
+ ).map((message) => normalizeConversationMessage(message, artifactsById)).filter((message) => Boolean(message));
21702
22271
  const conversationPromptIds = new Set(
21703
22272
  conversationMessages.map((message) => message.promptId).filter((promptId) => Boolean(promptId))
21704
22273
  );
@@ -21725,7 +22294,8 @@ function buildSessionTranscript(input) {
21725
22294
  if (!assistantConversationJobIds.has(jobId)) {
21726
22295
  const agentEntries = normalizeAgentMessageEntries(
21727
22296
  jobId,
21728
- job2.agentMessages
22297
+ job2.agentMessages,
22298
+ artifactsById
21729
22299
  );
21730
22300
  if (agentEntries.length > 0) {
21731
22301
  transcript.push(...agentEntries);
@@ -21734,7 +22304,8 @@ function buildSessionTranscript(input) {
21734
22304
  ...buildJobFallbackEntries(
21735
22305
  jobId,
21736
22306
  job2,
21737
- sessionHeap
22307
+ sessionHeap,
22308
+ artifactsById
21738
22309
  )
21739
22310
  );
21740
22311
  }
@@ -21982,15 +22553,50 @@ function toRecordSearchResult(className, node) {
21982
22553
  return [];
21983
22554
  }
21984
22555
  ) : [];
22556
+ const graphPathId = extractRecordIdFromGraphPath(path7, className);
22557
+ const realIdField = fields.find(
22558
+ (field) => normalizeGraphPathSegment(field.name) === "real_id" && typeof field.value === "string" && field.value.trim()
22559
+ );
22560
+ const id = typeof realIdField?.value === "string" ? realIdField.value.trim() : graphPathId;
22561
+ const rawLabel = typeof node.label === "string" && node.label.trim() ? node.label : "";
22562
+ if (fields.length === 0 && rawLabel && isPlaceholderRecordLabel(rawLabel, graphPathId, path7)) {
22563
+ return null;
22564
+ }
22565
+ const fallbackLabel = displayLabelFromFields(fields);
22566
+ const label = rawLabel && !isPlaceholderRecordLabel(rawLabel, id, path7) ? rawLabel : fallbackLabel || rawLabel || id;
21985
22567
  return {
21986
22568
  path: path7,
21987
22569
  className,
21988
- id: extractRecordIdFromGraphPath(path7, className),
21989
- label: typeof node.label === "string" && node.label.trim() ? node.label : extractRecordIdFromGraphPath(path7, className),
22570
+ id,
22571
+ label,
21990
22572
  description: typeof node.description === "string" && node.description.trim() ? node.description : null,
21991
22573
  fields
21992
22574
  };
21993
22575
  }
22576
+ function isPlaceholderRecordLabel(label, id, path7) {
22577
+ const normalizedLabel = normalizeGraphPathSegment(label);
22578
+ return normalizedLabel === normalizeGraphPathSegment(id) || normalizedLabel === normalizeGraphPathSegment(path7);
22579
+ }
22580
+ function displayLabelFromFields(fields) {
22581
+ const preferredFieldNames = [
22582
+ "name",
22583
+ "title",
22584
+ "label",
22585
+ "display_name",
22586
+ "file_name",
22587
+ "number",
22588
+ "code"
22589
+ ];
22590
+ for (const preferred of preferredFieldNames) {
22591
+ const match = fields.find(
22592
+ (field) => normalizeGraphPathSegment(field.name) === preferred && typeof field.value === "string" && field.value.trim()
22593
+ );
22594
+ if (typeof match?.value === "string") {
22595
+ return match.value.trim();
22596
+ }
22597
+ }
22598
+ return null;
22599
+ }
21994
22600
  function normalizeRecordSearchText(value) {
21995
22601
  return value.trim().toLowerCase().replace(/[^a-z0-9]+/g, " ").replace(/\s+/g, " ").trim();
21996
22602
  }
@@ -22239,6 +22845,26 @@ var STANDARD_MODULES_OPERATIONS = [
22239
22845
  var BUILTIN_MODULES = {
22240
22846
  standard_modules: STANDARD_MODULES_OPERATIONS
22241
22847
  };
22848
+ function stateNameFromMethodName(methodName) {
22849
+ const raw = methodName.startsWith("to") ? methodName.slice(2) : methodName;
22850
+ return raw.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^A-Za-z0-9]+/g, "_").replace(/_+/g, "_").replace(/^_+|_+$/g, "").toLowerCase();
22851
+ }
22852
+ function appendQueryOptions(searchParams, query) {
22853
+ for (const [key, value] of Object.entries(query || {})) {
22854
+ if (value === null || typeof value === "undefined" || value === "") {
22855
+ continue;
22856
+ }
22857
+ if (value instanceof Date) {
22858
+ searchParams.set(key, value.toISOString());
22859
+ continue;
22860
+ }
22861
+ if (Array.isArray(value)) {
22862
+ if (value.length > 0) searchParams.set(key, value.join(","));
22863
+ continue;
22864
+ }
22865
+ searchParams.set(key, String(value));
22866
+ }
22867
+ }
22242
22868
  var DEFAULT_DIRECT_RECORD_OBJECTS_REQUEST_BATCH_SIZE = 100;
22243
22869
  var MAX_RECORD_OBJECTS_CONCURRENCY = 16;
22244
22870
  var DEFAULT_DIRECT_RECORD_OBJECTS_RETRY_COUNT = 3;
@@ -22269,8 +22895,20 @@ function bodyInitFromSessionFileUpload(body) {
22269
22895
  return body;
22270
22896
  }
22271
22897
  var EFFECT_CATALOG_SYNC_TIMEOUT_MS = 12e4;
22898
+ var EFFECT_CATALOG_SYNC_BATCH_SIZE = 20;
22272
22899
  var EFFECT_CATALOG_SYNC_RETRY_COUNT = 3;
22273
22900
  var EFFECT_CATALOG_SYNC_RETRY_DELAY_MS = 1e3;
22901
+ function chunkItems(items, batchSize) {
22902
+ const chunks = [];
22903
+ for (let offset = 0; offset < items.length; offset += batchSize) {
22904
+ chunks.push(items.slice(offset, offset + batchSize));
22905
+ }
22906
+ return chunks;
22907
+ }
22908
+ function isUnsupportedEffectCatalogMutation(error2) {
22909
+ const message = error2 instanceof Error ? error2.message : String(error2);
22910
+ return message.includes("Unknown RPC method: effects.resetCatalog") || message.includes("Unknown RPC method: effects.addCatalog") || message.includes("Method not found: effects.resetCatalog") || message.includes("Method not found: effects.addCatalog");
22911
+ }
22274
22912
  function planRecordObjectsChunks(records, batchSize) {
22275
22913
  const total = records.length;
22276
22914
  const size = Math.max(1, Math.min(batchSize, total));
@@ -22282,6 +22920,23 @@ function planRecordObjectsChunks(records, batchSize) {
22282
22920
  }
22283
22921
  return plans;
22284
22922
  }
22923
+ function preserveRecordObjectRealId(record) {
22924
+ const realId = record.id.trim();
22925
+ if (!realId) {
22926
+ return record;
22927
+ }
22928
+ const fields = record.fields || {};
22929
+ if (typeof fields.real_id === "string" && fields.real_id.trim()) {
22930
+ return record;
22931
+ }
22932
+ return {
22933
+ ...record,
22934
+ fields: {
22935
+ ...fields,
22936
+ real_id: realId
22937
+ }
22938
+ };
22939
+ }
22285
22940
  function computeEffectKey2(effect) {
22286
22941
  const attachedClass = effect.className?.trim();
22287
22942
  if (!attachedClass) {
@@ -22519,11 +23174,105 @@ var Environment = class _Environment {
22519
23174
  getAwaitingCount: async () => this.getAwaitingRecordCount()
22520
23175
  };
22521
23176
  }
23177
+ /**
23178
+ * Mirror product-owned workflow state into Granular without making Granular
23179
+ * own the customer application's state machine.
23180
+ */
23181
+ async recordState(input) {
23182
+ const { machine, state, ...target } = input;
23183
+ if (!machine.trim()) {
23184
+ throw new Error("State update requires a machine name");
23185
+ }
23186
+ if (!state.trim()) {
23187
+ throw new Error("State update requires a state");
23188
+ }
23189
+ return this.recordObject({
23190
+ className: target.className,
23191
+ id: target.id,
23192
+ ...target.label ? { label: target.label } : {},
23193
+ ...target.fields ? { fields: target.fields } : {},
23194
+ ...target.relationships ? { relationships: target.relationships } : {},
23195
+ states: {
23196
+ [machine.trim()]: {
23197
+ state: state.trim(),
23198
+ ...target.source ? { source: target.source } : {},
23199
+ ...target.cause ? { cause: target.cause } : {},
23200
+ ...target.actorId ? { actorId: target.actorId } : {},
23201
+ ...target.observedAt !== void 0 ? { observedAt: target.observedAt } : {},
23202
+ ...target.force !== void 0 ? { force: target.force } : {},
23203
+ ...target.metadata ? { metadata: target.metadata } : {}
23204
+ }
23205
+ }
23206
+ });
23207
+ }
23208
+ /**
23209
+ * Mirror product-owned workflow state into Granular without making Granular
23210
+ * own the customer application's state machine.
23211
+ *
23212
+ * Example:
23213
+ * `await env.recordState({ className: "spend_request", id, machine: "lifecycle", state: "policy_review", source: "customer_backend" })`
23214
+ */
23215
+ state(target) {
23216
+ const observe = async (machineName, stateName, input = {}) => {
23217
+ const observedState = input.observedState || input.state || stateName;
23218
+ if (!observedState) {
23219
+ throw new Error("State observation requires a target state");
23220
+ }
23221
+ return this.recordState({
23222
+ ...target,
23223
+ machine: machineName,
23224
+ state: observedState,
23225
+ ...input.source ? { source: input.source } : {},
23226
+ ...input.cause ? { cause: input.cause } : {},
23227
+ ...input.actorId ? { actorId: input.actorId } : {},
23228
+ ...input.observedAt !== void 0 ? { observedAt: input.observedAt } : {},
23229
+ ...input.force !== void 0 ? { force: input.force } : {},
23230
+ ...input.metadata ? { metadata: input.metadata } : {}
23231
+ });
23232
+ };
23233
+ return new Proxy(
23234
+ {},
23235
+ {
23236
+ get: (_target, machineProperty) => {
23237
+ if (typeof machineProperty !== "string") return void 0;
23238
+ return new Proxy(
23239
+ {},
23240
+ {
23241
+ get: (_machineTarget, stateProperty) => {
23242
+ if (stateProperty === "to") {
23243
+ return (stateName, input) => observe(machineProperty, stateName, input || {});
23244
+ }
23245
+ if (typeof stateProperty !== "string") return void 0;
23246
+ return (input) => observe(
23247
+ machineProperty,
23248
+ stateNameFromMethodName(stateProperty),
23249
+ input || {}
23250
+ );
23251
+ }
23252
+ }
23253
+ );
23254
+ }
23255
+ }
23256
+ );
23257
+ }
22522
23258
  get feedback() {
22523
23259
  return {
22524
23260
  list: async () => this.listFeedback()
22525
23261
  };
22526
23262
  }
23263
+ get manualActions() {
23264
+ return {
23265
+ record: (input) => this.recordManualAction(input),
23266
+ list: (options = {}) => this.listManualActions(options),
23267
+ suggest: (options = {}) => this.suggestManualActions(options)
23268
+ };
23269
+ }
23270
+ get artifactApprovals() {
23271
+ return {
23272
+ list: (options = {}) => this.listArtifactApprovals(options),
23273
+ decide: (approvalTaskId, input) => this.decideArtifactApproval(approvalTaskId, input)
23274
+ };
23275
+ }
22527
23276
  /**
22528
23277
  * Sessionless environments do not own a live transport, so disconnecting the
22529
23278
  * environment handle itself is a no-op. This keeps the public surface
@@ -22602,6 +23351,50 @@ var Environment = class _Environment {
22602
23351
  const response = await this.controlPlaneRequest(`/control/environments/${this.environmentId}/feedback`);
22603
23352
  return Array.isArray(response.items) ? response.items : [];
22604
23353
  }
23354
+ async recordManualAction(input) {
23355
+ const body = {
23356
+ ...input,
23357
+ ...input.idempotencyKey ? { idempotencyKey: input.idempotencyKey } : {}
23358
+ };
23359
+ return this.controlPlaneRequest(
23360
+ `/control/environments/${this.environmentId}/manual-actions`,
23361
+ {
23362
+ method: "POST",
23363
+ body: JSON.stringify(body)
23364
+ }
23365
+ );
23366
+ }
23367
+ async listManualActions(options = {}) {
23368
+ const query = new URLSearchParams();
23369
+ appendQueryOptions(query, options);
23370
+ const suffix = query.toString() ? `?${query.toString()}` : "";
23371
+ return this.controlPlaneRequest(`/control/environments/${this.environmentId}/manual-actions${suffix}`);
23372
+ }
23373
+ async suggestManualActions(options = {}) {
23374
+ const query = new URLSearchParams();
23375
+ appendQueryOptions(query, options);
23376
+ const suffix = query.toString() ? `?${query.toString()}` : "";
23377
+ return this.controlPlaneRequest(
23378
+ `/control/environments/${this.environmentId}/manual-actions/suggestions${suffix}`
23379
+ );
23380
+ }
23381
+ async listArtifactApprovals(options = {}) {
23382
+ const query = new URLSearchParams();
23383
+ appendQueryOptions(query, options);
23384
+ const suffix = query.toString() ? `?${query.toString()}` : "";
23385
+ return this.controlPlaneRequest(
23386
+ `/control/environments/${this.environmentId}/artifact-approvals${suffix}`
23387
+ );
23388
+ }
23389
+ async decideArtifactApproval(approvalTaskId, input) {
23390
+ return this.controlPlaneRequest(
23391
+ `/control/environments/${this.environmentId}/artifact-approvals/${encodeURIComponent(approvalTaskId)}/decide`,
23392
+ {
23393
+ method: "POST",
23394
+ body: JSON.stringify(input)
23395
+ }
23396
+ );
23397
+ }
22605
23398
  getRuntimeBaseUrl() {
22606
23399
  return deriveRuntimeBaseUrl(this._apiEndpoint);
22607
23400
  }
@@ -23426,10 +24219,11 @@ var Environment = class _Environment {
23426
24219
  if (!Array.isArray(records) || records.length === 0) {
23427
24220
  return [];
23428
24221
  }
24222
+ const recordsToWrite = records.map(preserveRecordObjectRealId);
23429
24223
  const batchSize = Math.max(
23430
24224
  1,
23431
24225
  Math.min(
23432
- records.length,
24226
+ recordsToWrite.length,
23433
24227
  options?.batchSize ?? DEFAULT_DIRECT_RECORD_OBJECTS_REQUEST_BATCH_SIZE
23434
24228
  )
23435
24229
  );
@@ -23437,8 +24231,8 @@ var Environment = class _Environment {
23437
24231
  MAX_RECORD_OBJECTS_CONCURRENCY,
23438
24232
  Math.max(1, options?.concurrency ?? 1)
23439
24233
  );
23440
- const plans = planRecordObjectsChunks(records, batchSize);
23441
- const total = records.length;
24234
+ const plans = planRecordObjectsChunks(recordsToWrite, batchSize);
24235
+ const total = recordsToWrite.length;
23442
24236
  const results = new Array(total);
23443
24237
  const onChunk = options?.onChunkComplete;
23444
24238
  for (let waveStart = 0; waveStart < plans.length; waveStart += concurrency) {
@@ -23509,12 +24303,13 @@ var Environment = class _Environment {
23509
24303
  * synchronous upserts and fine-grained chunk progress via **`onChunkComplete`**.
23510
24304
  */
23511
24305
  async enqueueRecordImport(records, options = {}) {
24306
+ const recordsToImport = records.map(preserveRecordObjectRealId);
23512
24307
  return this.controlPlaneRequest(
23513
24308
  `/control/environments/${this.environmentId}/record-imports`,
23514
24309
  {
23515
24310
  method: "POST",
23516
24311
  body: JSON.stringify({
23517
- records,
24312
+ records: recordsToImport,
23518
24313
  batchSize: options.batchSize,
23519
24314
  setupRunId: options.setupRunId,
23520
24315
  writeMode: options.writeMode
@@ -23622,11 +24417,7 @@ var EnvironmentSession = class extends Session {
23622
24417
  }
23623
24418
  buildSessionDataUrl(path7, query) {
23624
24419
  const searchParams = new URLSearchParams();
23625
- for (const [key, value] of Object.entries(query || {})) {
23626
- if (value !== null && typeof value !== "undefined" && value !== "") {
23627
- searchParams.set(key, String(value));
23628
- }
23629
- }
24420
+ appendQueryOptions(searchParams, query);
23630
24421
  const queryString = searchParams.toString();
23631
24422
  return `${this.environment.runtimeBaseUrl}${this.sessionDataRoutePrefix}/${encodeURIComponent(this.sessionId)}${path7}${queryString ? `?${queryString}` : ""}`;
23632
24423
  }
@@ -23709,9 +24500,108 @@ var EnvironmentSession = class extends Session {
23709
24500
  ),
23710
24501
  get: (jobId) => this.sessionDataRequest(
23711
24502
  `/jobs/${encodeURIComponent(jobId)}`
24503
+ ),
24504
+ latest: async (options = {}) => {
24505
+ const page = await this.sessionDataRequest("/jobs", {
24506
+ status: options.status || "all",
24507
+ latest: true,
24508
+ limit: 1
24509
+ });
24510
+ return page.items[0] || null;
24511
+ }
24512
+ };
24513
+ }
24514
+ get artifacts() {
24515
+ return {
24516
+ list: (options = {}) => {
24517
+ const queryOptions = { ...options };
24518
+ if (options.target) {
24519
+ queryOptions.targetClassName = options.target.className;
24520
+ queryOptions.targetId = options.target.id;
24521
+ delete queryOptions.target;
24522
+ }
24523
+ return this.sessionDataRequest("/artifacts", queryOptions);
24524
+ },
24525
+ listForLatestJob: (options = {}) => this.artifacts.list({
24526
+ ...options,
24527
+ latestJob: true
24528
+ }),
24529
+ get: (artifactId) => this.sessionDataRequest(
24530
+ `/artifacts/${encodeURIComponent(artifactId)}`
24531
+ ),
24532
+ create: (artifact) => this.sessionDataRequest(
24533
+ "/artifacts",
24534
+ void 0,
24535
+ {
24536
+ method: "POST",
24537
+ body: artifact
24538
+ }
24539
+ ),
24540
+ updateInputs: (artifactId, patch) => this.sessionDataRequest(
24541
+ `/artifacts/${encodeURIComponent(artifactId)}`,
24542
+ void 0,
24543
+ {
24544
+ method: "PATCH",
24545
+ body: patch
24546
+ }
24547
+ ),
24548
+ validate: (artifactId) => this.sessionDataRequest(
24549
+ `/artifacts/${encodeURIComponent(artifactId)}/validate`,
24550
+ void 0,
24551
+ { method: "POST" }
24552
+ ),
24553
+ execute: (artifactId, options) => this.sessionDataRequest(
24554
+ `/artifacts/${encodeURIComponent(artifactId)}/execute`,
24555
+ void 0,
24556
+ { method: "POST", body: options }
24557
+ ),
24558
+ approve: (artifactId, options) => this.sessionDataRequest(
24559
+ `/artifacts/${encodeURIComponent(artifactId)}/approve`,
24560
+ void 0,
24561
+ { method: "POST", body: options }
24562
+ ),
24563
+ cancel: (artifactId) => this.sessionDataRequest(
24564
+ `/artifacts/${encodeURIComponent(artifactId)}/cancel`,
24565
+ void 0,
24566
+ { method: "POST" }
23712
24567
  )
23713
24568
  };
23714
24569
  }
24570
+ get manualActions() {
24571
+ const useDelegatedBrowserRoute = this.sessionDataRoutePrefix === "/sdk/browser-sessions";
24572
+ return {
24573
+ record: (input) => useDelegatedBrowserRoute ? this.sessionDataRequest(
24574
+ "/manual-actions",
24575
+ void 0,
24576
+ {
24577
+ method: "POST",
24578
+ body: { ...input, sessionId: this.sessionId }
24579
+ }
24580
+ ) : this.environment.manualActions.record({
24581
+ ...input,
24582
+ sessionId: this.sessionId
24583
+ }),
24584
+ list: (options = {}) => useDelegatedBrowserRoute ? this.sessionDataRequest("/manual-actions", { ...options, sessionId: this.sessionId }) : this.environment.manualActions.list({
24585
+ ...options,
24586
+ sessionId: this.sessionId
24587
+ }),
24588
+ suggest: (options = {}) => useDelegatedBrowserRoute ? this.sessionDataRequest(
24589
+ "/manual-actions/suggestions",
24590
+ options
24591
+ ) : this.environment.manualActions.suggest(options)
24592
+ };
24593
+ }
24594
+ get artifactApprovals() {
24595
+ const useDelegatedBrowserRoute = this.sessionDataRoutePrefix === "/sdk/browser-sessions";
24596
+ return {
24597
+ list: (options = {}) => useDelegatedBrowserRoute ? this.sessionDataRequest("/artifact-approvals", options) : this.environment.artifactApprovals.list(options),
24598
+ decide: (approvalTaskId, input) => useDelegatedBrowserRoute ? this.sessionDataRequest(
24599
+ `/artifact-approvals/${encodeURIComponent(approvalTaskId)}/decide`,
24600
+ void 0,
24601
+ { method: "POST", body: input }
24602
+ ) : this.environment.artifactApprovals.decide(approvalTaskId, input)
24603
+ };
24604
+ }
23715
24605
  get files() {
23716
24606
  return {
23717
24607
  list: (options = {}) => this.sessionDataRequest(
@@ -23792,13 +24682,16 @@ var EnvironmentSession = class extends Session {
23792
24682
  get transcript() {
23793
24683
  return {
23794
24684
  list: async (options = {}) => {
23795
- const [messages, jobs, entries, lists] = await Promise.all([
24685
+ const [messages, jobs, entries, lists, artifacts] = await Promise.all([
23796
24686
  this.collectAllSessionItems(this.messages.list),
23797
24687
  this.collectAllSessionItems(
23798
24688
  (pageOptions) => this.jobs.list({ ...pageOptions, status: "all" })
23799
24689
  ),
23800
24690
  this.collectAllSessionItems(this.heap.entries.list),
23801
- this.collectAllSessionItems(this.heap.lists.list)
24691
+ this.collectAllSessionItems(this.heap.lists.list),
24692
+ this.collectAllSessionItems(
24693
+ (pageOptions) => this.artifacts.list({ ...pageOptions, status: "all" })
24694
+ )
23802
24695
  ]);
23803
24696
  const liveDoc = {
23804
24697
  conversation: { messages },
@@ -23812,6 +24705,21 @@ var EnvironmentSession = class extends Session {
23812
24705
  (entry) => Boolean(entry)
23813
24706
  )
23814
24707
  )
24708
+ },
24709
+ artifacts: {
24710
+ byId: Object.fromEntries(
24711
+ artifacts.map((artifact) => {
24712
+ return artifact?.artifactId ? [
24713
+ artifact.artifactId,
24714
+ artifact
24715
+ ] : null;
24716
+ }).filter(
24717
+ (entry) => Boolean(entry)
24718
+ )
24719
+ ),
24720
+ order: artifacts.map((artifact) => artifact?.artifactId).filter(
24721
+ (artifactId) => Boolean(artifactId)
24722
+ )
23815
24723
  }
23816
24724
  };
23817
24725
  const heap = normalizeHeapSnapshot({
@@ -23888,6 +24796,12 @@ var EnvironmentSession = class extends Session {
23888
24796
  async recordObject(options) {
23889
24797
  return this.environment.recordObject(options);
23890
24798
  }
24799
+ async recordState(input) {
24800
+ return this.environment.recordState(input);
24801
+ }
24802
+ state(target) {
24803
+ return this.environment.state(target);
24804
+ }
23891
24805
  async recordObjects(records, options) {
23892
24806
  return this.environment.recordObjects(records, options);
23893
24807
  }
@@ -24715,15 +25629,43 @@ var Granular = class _Granular {
24715
25629
  const effects2 = Array.from(
24716
25630
  this.getSandboxEffectMap(host.sandboxId).values()
24717
25631
  ).map((effect) => this.serializeEffect(effect));
24718
- const result = await withTimeout(
24719
- host.wsClient.call("effects.publishCatalog", {
24720
- effects: effects2
24721
- }),
24722
- EFFECT_CATALOG_SYNC_TIMEOUT_MS,
24723
- `effects.publishCatalog for sandbox ${host.sandboxId}`
24724
- );
24725
- const acceptedCount = typeof result?.acceptedCount === "number" ? result.acceptedCount : 0;
24726
- const rejected = Array.isArray(result?.rejected) ? result.rejected : [];
25632
+ let acceptedCount = 0;
25633
+ const rejected = [];
25634
+ try {
25635
+ await withTimeout(
25636
+ host.wsClient.call("effects.resetCatalog", {}),
25637
+ EFFECT_CATALOG_SYNC_TIMEOUT_MS,
25638
+ `effects.resetCatalog for sandbox ${host.sandboxId}`
25639
+ );
25640
+ for (const batch of chunkItems(effects2, EFFECT_CATALOG_SYNC_BATCH_SIZE)) {
25641
+ const result = await withTimeout(
25642
+ host.wsClient.call("effects.addCatalog", {
25643
+ effects: batch
25644
+ }),
25645
+ EFFECT_CATALOG_SYNC_TIMEOUT_MS,
25646
+ `effects.addCatalog for sandbox ${host.sandboxId}`
25647
+ );
25648
+ acceptedCount += typeof result?.acceptedCount === "number" ? result.acceptedCount : 0;
25649
+ if (Array.isArray(result?.rejected)) {
25650
+ rejected.push(...result.rejected);
25651
+ }
25652
+ }
25653
+ } catch (error2) {
25654
+ if (!isUnsupportedEffectCatalogMutation(error2)) {
25655
+ throw error2;
25656
+ }
25657
+ const result = await withTimeout(
25658
+ host.wsClient.call("effects.publishCatalog", {
25659
+ effects: effects2
25660
+ }),
25661
+ EFFECT_CATALOG_SYNC_TIMEOUT_MS,
25662
+ `effects.publishCatalog for sandbox ${host.sandboxId}`
25663
+ );
25664
+ acceptedCount = typeof result?.acceptedCount === "number" ? result.acceptedCount : 0;
25665
+ if (Array.isArray(result?.rejected)) {
25666
+ rejected.push(...result.rejected);
25667
+ }
25668
+ }
24727
25669
  if (acceptedCount === 0 && rejected.length > 0) {
24728
25670
  const detail = rejected.map(
24729
25671
  (entry) => `${entry.name || "unknown"}: ${entry.reason || "rejected"}`