@granular-software/sdk 0.4.48 → 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
  `;
@@ -20689,6 +21081,9 @@ import { ${tools[0]?.name || "example"} } from "@granular/actions/backend";
20689
21081
  this.client.on("harness.model_stream", (data) => {
20690
21082
  this.emit("harness:model_stream", data);
20691
21083
  });
21084
+ this.client.on("harness.text_response.delta", (data) => {
21085
+ this.emit("harness:text_response_delta", data);
21086
+ });
20692
21087
  this.client.on("job.agent_message", (data) => {
20693
21088
  const normalized = normalizeJobAgentMessageEnvelope(data);
20694
21089
  if (!normalized) return;
@@ -21455,6 +21850,28 @@ function asString(value) {
21455
21850
  function trimString(value) {
21456
21851
  return typeof value === "string" ? value.trim() : "";
21457
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
+ }
21458
21875
  function normalizeShowRefs(value) {
21459
21876
  const record = asRecord3(value);
21460
21877
  if (!record) return void 0;
@@ -21471,9 +21888,31 @@ function normalizeShowRefs(value) {
21471
21888
  entryPaths: normalizeRefs(record.entryPaths),
21472
21889
  listNames: normalizeRefs(record.listNames),
21473
21890
  variableNames: normalizeRefs(record.variableNames),
21474
- fileIds: normalizeRefs(record.fileIds)
21891
+ fileIds: normalizeRefs(record.fileIds),
21892
+ sessionArtifactIds: normalizeRefs(record.sessionArtifactIds),
21893
+ actionSuggestions: normalizeActionSuggestions(record.actionSuggestions)
21475
21894
  };
21476
- 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;
21477
21916
  }
21478
21917
  function stringifyTranscriptValue(value, fallback2 = "") {
21479
21918
  if (typeof value === "string") {
@@ -21493,12 +21932,139 @@ function stringifyTranscriptValue(value, fallback2 = "") {
21493
21932
  return String(value);
21494
21933
  }
21495
21934
  }
21496
- 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) {
21497
22027
  if (!show) return void 0;
21498
- 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]
21499
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");
21500
22066
  }
21501
- function normalizeConversationMessage(raw) {
22067
+ function normalizeConversationMessage(raw, artifactsById) {
21502
22068
  const record = asRecord3(raw);
21503
22069
  if (!record) return null;
21504
22070
  const role = record.role === "user" ? "user" : record.role === "assistant" ? "assistant" : null;
@@ -21510,6 +22076,12 @@ function normalizeConversationMessage(raw) {
21510
22076
  const id = asString(record.id) || crypto.randomUUID();
21511
22077
  const timestamp = asNumber(record.timestamp) || asNumber(record.ts) || 0;
21512
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;
21513
22085
  return {
21514
22086
  id,
21515
22087
  role,
@@ -21518,8 +22090,7 @@ function normalizeConversationMessage(raw) {
21518
22090
  jobId: asString(record.jobId),
21519
22091
  promptId: asString(record.promptId),
21520
22092
  show,
21521
- historyContent: role === "assistant" ? content ? `[Assistant reply]
21522
- ${content}` : buildArtifactHistory(show) : void 0,
22093
+ historyContent,
21523
22094
  source: "conversation"
21524
22095
  };
21525
22096
  }
@@ -21562,7 +22133,7 @@ ${assistantContent}`,
21562
22133
  return entries;
21563
22134
  });
21564
22135
  }
21565
- function normalizeAgentMessageEntries(jobId, rawMessages) {
22136
+ function normalizeAgentMessageEntries(jobId, rawMessages, artifactsById) {
21566
22137
  return asArray(rawMessages).map((value) => asRecord3(value)).filter((value) => Boolean(value)).sort(
21567
22138
  (left, right) => (asNumber(left.timestamp) || asNumber(left.ts) || 0) - (asNumber(right.timestamp) || asNumber(right.ts) || 0)
21568
22139
  ).flatMap((message) => {
@@ -21593,14 +22164,14 @@ ${reply}`,
21593
22164
  timestamp,
21594
22165
  jobId,
21595
22166
  show,
21596
- historyContent: buildArtifactHistory(show),
22167
+ historyContent: buildArtifactHistory(show, artifactsById),
21597
22168
  source: "job_agent_message"
21598
22169
  });
21599
22170
  }
21600
22171
  return entries;
21601
22172
  });
21602
22173
  }
21603
- function buildJobFallbackEntries(jobId, job2, sessionHeap) {
22174
+ function buildJobFallbackEntries(jobId, job2, sessionHeap, artifactsById) {
21604
22175
  const timestamp = asNumber(job2.finishedAt) || asNumber(job2.startedAt) || asNumber(job2.submittedAt) || 0;
21605
22176
  const resultPreview = stringifyTranscriptValue(
21606
22177
  job2.result,
@@ -21638,7 +22209,7 @@ ${responseText}`,
21638
22209
  timestamp,
21639
22210
  jobId,
21640
22211
  show,
21641
- historyContent: buildArtifactHistory(show),
22212
+ historyContent: buildArtifactHistory(show, artifactsById),
21642
22213
  source: "job_result"
21643
22214
  });
21644
22215
  }
@@ -21692,10 +22263,11 @@ function buildJobCodeEntry(jobId, job2) {
21692
22263
  function buildSessionTranscript(input) {
21693
22264
  const liveDoc = input.liveDoc || null;
21694
22265
  const sessionHeap = input.sessionHeap || EMPTY_HEAP;
22266
+ const artifactsById = artifactRecordsById(liveDoc);
21695
22267
  const transcript = [];
21696
22268
  const conversationMessages = asArray(
21697
22269
  asRecord3(liveDoc?.conversation)?.messages
21698
- ).map((message) => normalizeConversationMessage(message)).filter((message) => Boolean(message));
22270
+ ).map((message) => normalizeConversationMessage(message, artifactsById)).filter((message) => Boolean(message));
21699
22271
  const conversationPromptIds = new Set(
21700
22272
  conversationMessages.map((message) => message.promptId).filter((promptId) => Boolean(promptId))
21701
22273
  );
@@ -21722,7 +22294,8 @@ function buildSessionTranscript(input) {
21722
22294
  if (!assistantConversationJobIds.has(jobId)) {
21723
22295
  const agentEntries = normalizeAgentMessageEntries(
21724
22296
  jobId,
21725
- job2.agentMessages
22297
+ job2.agentMessages,
22298
+ artifactsById
21726
22299
  );
21727
22300
  if (agentEntries.length > 0) {
21728
22301
  transcript.push(...agentEntries);
@@ -21731,7 +22304,8 @@ function buildSessionTranscript(input) {
21731
22304
  ...buildJobFallbackEntries(
21732
22305
  jobId,
21733
22306
  job2,
21734
- sessionHeap
22307
+ sessionHeap,
22308
+ artifactsById
21735
22309
  )
21736
22310
  );
21737
22311
  }
@@ -21979,15 +22553,50 @@ function toRecordSearchResult(className, node) {
21979
22553
  return [];
21980
22554
  }
21981
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;
21982
22567
  return {
21983
22568
  path: path7,
21984
22569
  className,
21985
- id: extractRecordIdFromGraphPath(path7, className),
21986
- label: typeof node.label === "string" && node.label.trim() ? node.label : extractRecordIdFromGraphPath(path7, className),
22570
+ id,
22571
+ label,
21987
22572
  description: typeof node.description === "string" && node.description.trim() ? node.description : null,
21988
22573
  fields
21989
22574
  };
21990
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
+ }
21991
22600
  function normalizeRecordSearchText(value) {
21992
22601
  return value.trim().toLowerCase().replace(/[^a-z0-9]+/g, " ").replace(/\s+/g, " ").trim();
21993
22602
  }
@@ -22236,6 +22845,26 @@ var STANDARD_MODULES_OPERATIONS = [
22236
22845
  var BUILTIN_MODULES = {
22237
22846
  standard_modules: STANDARD_MODULES_OPERATIONS
22238
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
+ }
22239
22868
  var DEFAULT_DIRECT_RECORD_OBJECTS_REQUEST_BATCH_SIZE = 100;
22240
22869
  var MAX_RECORD_OBJECTS_CONCURRENCY = 16;
22241
22870
  var DEFAULT_DIRECT_RECORD_OBJECTS_RETRY_COUNT = 3;
@@ -22266,8 +22895,20 @@ function bodyInitFromSessionFileUpload(body) {
22266
22895
  return body;
22267
22896
  }
22268
22897
  var EFFECT_CATALOG_SYNC_TIMEOUT_MS = 12e4;
22898
+ var EFFECT_CATALOG_SYNC_BATCH_SIZE = 20;
22269
22899
  var EFFECT_CATALOG_SYNC_RETRY_COUNT = 3;
22270
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
+ }
22271
22912
  function planRecordObjectsChunks(records, batchSize) {
22272
22913
  const total = records.length;
22273
22914
  const size = Math.max(1, Math.min(batchSize, total));
@@ -22279,6 +22920,23 @@ function planRecordObjectsChunks(records, batchSize) {
22279
22920
  }
22280
22921
  return plans;
22281
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
+ }
22282
22940
  function computeEffectKey2(effect) {
22283
22941
  const attachedClass = effect.className?.trim();
22284
22942
  if (!attachedClass) {
@@ -22516,11 +23174,105 @@ var Environment = class _Environment {
22516
23174
  getAwaitingCount: async () => this.getAwaitingRecordCount()
22517
23175
  };
22518
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
+ }
22519
23258
  get feedback() {
22520
23259
  return {
22521
23260
  list: async () => this.listFeedback()
22522
23261
  };
22523
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
+ }
22524
23276
  /**
22525
23277
  * Sessionless environments do not own a live transport, so disconnecting the
22526
23278
  * environment handle itself is a no-op. This keeps the public surface
@@ -22599,6 +23351,50 @@ var Environment = class _Environment {
22599
23351
  const response = await this.controlPlaneRequest(`/control/environments/${this.environmentId}/feedback`);
22600
23352
  return Array.isArray(response.items) ? response.items : [];
22601
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
+ }
22602
23398
  getRuntimeBaseUrl() {
22603
23399
  return deriveRuntimeBaseUrl(this._apiEndpoint);
22604
23400
  }
@@ -23423,10 +24219,11 @@ var Environment = class _Environment {
23423
24219
  if (!Array.isArray(records) || records.length === 0) {
23424
24220
  return [];
23425
24221
  }
24222
+ const recordsToWrite = records.map(preserveRecordObjectRealId);
23426
24223
  const batchSize = Math.max(
23427
24224
  1,
23428
24225
  Math.min(
23429
- records.length,
24226
+ recordsToWrite.length,
23430
24227
  options?.batchSize ?? DEFAULT_DIRECT_RECORD_OBJECTS_REQUEST_BATCH_SIZE
23431
24228
  )
23432
24229
  );
@@ -23434,8 +24231,8 @@ var Environment = class _Environment {
23434
24231
  MAX_RECORD_OBJECTS_CONCURRENCY,
23435
24232
  Math.max(1, options?.concurrency ?? 1)
23436
24233
  );
23437
- const plans = planRecordObjectsChunks(records, batchSize);
23438
- const total = records.length;
24234
+ const plans = planRecordObjectsChunks(recordsToWrite, batchSize);
24235
+ const total = recordsToWrite.length;
23439
24236
  const results = new Array(total);
23440
24237
  const onChunk = options?.onChunkComplete;
23441
24238
  for (let waveStart = 0; waveStart < plans.length; waveStart += concurrency) {
@@ -23506,12 +24303,13 @@ var Environment = class _Environment {
23506
24303
  * synchronous upserts and fine-grained chunk progress via **`onChunkComplete`**.
23507
24304
  */
23508
24305
  async enqueueRecordImport(records, options = {}) {
24306
+ const recordsToImport = records.map(preserveRecordObjectRealId);
23509
24307
  return this.controlPlaneRequest(
23510
24308
  `/control/environments/${this.environmentId}/record-imports`,
23511
24309
  {
23512
24310
  method: "POST",
23513
24311
  body: JSON.stringify({
23514
- records,
24312
+ records: recordsToImport,
23515
24313
  batchSize: options.batchSize,
23516
24314
  setupRunId: options.setupRunId,
23517
24315
  writeMode: options.writeMode
@@ -23619,11 +24417,7 @@ var EnvironmentSession = class extends Session {
23619
24417
  }
23620
24418
  buildSessionDataUrl(path7, query) {
23621
24419
  const searchParams = new URLSearchParams();
23622
- for (const [key, value] of Object.entries(query || {})) {
23623
- if (value !== null && typeof value !== "undefined" && value !== "") {
23624
- searchParams.set(key, String(value));
23625
- }
23626
- }
24420
+ appendQueryOptions(searchParams, query);
23627
24421
  const queryString = searchParams.toString();
23628
24422
  return `${this.environment.runtimeBaseUrl}${this.sessionDataRoutePrefix}/${encodeURIComponent(this.sessionId)}${path7}${queryString ? `?${queryString}` : ""}`;
23629
24423
  }
@@ -23706,9 +24500,108 @@ var EnvironmentSession = class extends Session {
23706
24500
  ),
23707
24501
  get: (jobId) => this.sessionDataRequest(
23708
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" }
23709
24567
  )
23710
24568
  };
23711
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
+ }
23712
24605
  get files() {
23713
24606
  return {
23714
24607
  list: (options = {}) => this.sessionDataRequest(
@@ -23789,13 +24682,16 @@ var EnvironmentSession = class extends Session {
23789
24682
  get transcript() {
23790
24683
  return {
23791
24684
  list: async (options = {}) => {
23792
- const [messages, jobs, entries, lists] = await Promise.all([
24685
+ const [messages, jobs, entries, lists, artifacts] = await Promise.all([
23793
24686
  this.collectAllSessionItems(this.messages.list),
23794
24687
  this.collectAllSessionItems(
23795
24688
  (pageOptions) => this.jobs.list({ ...pageOptions, status: "all" })
23796
24689
  ),
23797
24690
  this.collectAllSessionItems(this.heap.entries.list),
23798
- 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
+ )
23799
24695
  ]);
23800
24696
  const liveDoc = {
23801
24697
  conversation: { messages },
@@ -23809,6 +24705,21 @@ var EnvironmentSession = class extends Session {
23809
24705
  (entry) => Boolean(entry)
23810
24706
  )
23811
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
+ )
23812
24723
  }
23813
24724
  };
23814
24725
  const heap = normalizeHeapSnapshot({
@@ -23885,6 +24796,12 @@ var EnvironmentSession = class extends Session {
23885
24796
  async recordObject(options) {
23886
24797
  return this.environment.recordObject(options);
23887
24798
  }
24799
+ async recordState(input) {
24800
+ return this.environment.recordState(input);
24801
+ }
24802
+ state(target) {
24803
+ return this.environment.state(target);
24804
+ }
23888
24805
  async recordObjects(records, options) {
23889
24806
  return this.environment.recordObjects(records, options);
23890
24807
  }
@@ -24712,15 +25629,43 @@ var Granular = class _Granular {
24712
25629
  const effects2 = Array.from(
24713
25630
  this.getSandboxEffectMap(host.sandboxId).values()
24714
25631
  ).map((effect) => this.serializeEffect(effect));
24715
- const result = await withTimeout(
24716
- host.wsClient.call("effects.publishCatalog", {
24717
- effects: effects2
24718
- }),
24719
- EFFECT_CATALOG_SYNC_TIMEOUT_MS,
24720
- `effects.publishCatalog for sandbox ${host.sandboxId}`
24721
- );
24722
- const acceptedCount = typeof result?.acceptedCount === "number" ? result.acceptedCount : 0;
24723
- 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
+ }
24724
25669
  if (acceptedCount === 0 && rejected.length > 0) {
24725
25670
  const detail = rejected.map(
24726
25671
  (entry) => `${entry.name || "unknown"}: ${entry.reason || "rejected"}`