@granular-software/sdk 0.4.32 → 0.4.34

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
@@ -15222,7 +15222,8 @@ ${effectMetamodelTable}
15222
15222
  | \`getDomain()\`, \`getDomainTypes()\`, \`getDomainDocs()\`, \`getDomainDocumentation()\` | Domain summary and generated TypeScript / docs. |
15223
15223
  | \`getEffects()\` / \`getTools()\`, \`session.on("effects:changed", ...)\` | Effect catalog and live updates. |
15224
15224
  | \`checkReadiness()\`, \`on('readiness', ...)\` | Runtime readiness. |
15225
- | \`getHeap()\` | Session state snapshot (advanced). |
15225
+ | \`document\`, \`getHeap()\` | Current live session state from the WebSocket. |
15226
+ | \`messages.list()\`, \`timeline.list()\`, \`jobs.list/get()\`, \`heap.entries.list/get()\`, \`heap.lists.list/get()\`, \`transcript.list()\` | Durable session history and saved artifacts. |
15226
15227
  | \`disconnect()\` | Close the live runtime session. |
15227
15228
  | \`rpc(method, params)\` | Low-level session RPC (advanced). |
15228
15229
  | \`disconnect()\` | End the session. |
@@ -19413,6 +19414,540 @@ var JobImplementation = class {
19413
19414
  }
19414
19415
  };
19415
19416
 
19417
+ // src/job-presentation.ts
19418
+ var RESPONSE_KEYS = [
19419
+ "reply",
19420
+ "response",
19421
+ "text",
19422
+ "message",
19423
+ "summary",
19424
+ "answer"
19425
+ ];
19426
+ var ENTRY_KEY_CANDIDATES = ["entryPath", "path"];
19427
+ var ENTRY_ARRAY_KEY_CANDIDATES = ["entryPaths", "paths"];
19428
+ var LIST_KEY_CANDIDATES = ["listName"];
19429
+ var LIST_ARRAY_KEY_CANDIDATES = ["listNames"];
19430
+ var VARIABLE_KEY_CANDIDATES = ["variableName"];
19431
+ var VARIABLE_ARRAY_KEY_CANDIDATES = ["variableNames"];
19432
+ var UI_CONTAINER_KEYS = ["show", "display", "present", "ui"];
19433
+ function asRecord2(value) {
19434
+ if (!value || typeof value !== "object" || Array.isArray(value)) return null;
19435
+ return value;
19436
+ }
19437
+ function normalizeText(value) {
19438
+ if (typeof value !== "string") return null;
19439
+ const trimmed = value.trim();
19440
+ if (!trimmed) return null;
19441
+ if (trimmed.startsWith("{") && trimmed.endsWith("}") || trimmed.startsWith("[") && trimmed.endsWith("]")) {
19442
+ return null;
19443
+ }
19444
+ return trimmed;
19445
+ }
19446
+ function humanTextFromStdout(stdout) {
19447
+ for (const line of [...stdout].reverse()) {
19448
+ const normalized = normalizeText(line);
19449
+ if (!normalized) continue;
19450
+ if (/^[A-Z_]+:/.test(normalized)) continue;
19451
+ return normalized;
19452
+ }
19453
+ return null;
19454
+ }
19455
+ function pushString(target, value) {
19456
+ if (typeof value === "string" && value.trim()) {
19457
+ target.add(value.trim());
19458
+ }
19459
+ }
19460
+ function pushStringArray(target, value) {
19461
+ if (!Array.isArray(value)) return;
19462
+ for (const item of value) {
19463
+ pushString(target, item);
19464
+ }
19465
+ }
19466
+ function collectReferencesFromRecord(record, refs) {
19467
+ for (const key of ENTRY_KEY_CANDIDATES)
19468
+ pushString(refs.entryPaths, record[key]);
19469
+ for (const key of ENTRY_ARRAY_KEY_CANDIDATES)
19470
+ pushStringArray(refs.entryPaths, record[key]);
19471
+ for (const key of LIST_KEY_CANDIDATES)
19472
+ pushString(refs.listNames, record[key]);
19473
+ for (const key of LIST_ARRAY_KEY_CANDIDATES)
19474
+ pushStringArray(refs.listNames, record[key]);
19475
+ for (const key of VARIABLE_KEY_CANDIDATES)
19476
+ pushString(refs.variableNames, record[key]);
19477
+ for (const key of VARIABLE_ARRAY_KEY_CANDIDATES)
19478
+ pushStringArray(refs.variableNames, record[key]);
19479
+ }
19480
+ function scanForHeapReferences(value, heap, refs, depth = 0, seen = /* @__PURE__ */ new Set()) {
19481
+ if (value === null || value === void 0 || depth > 4 || seen.has(value))
19482
+ return;
19483
+ if (typeof value === "string") {
19484
+ const trimmed = value.trim();
19485
+ if (heap.entriesByPath?.[trimmed]) refs.entryPaths.add(trimmed);
19486
+ if (heap.listsByName?.[trimmed]) refs.listNames.add(trimmed);
19487
+ if (heap.variablesByName?.[trimmed]) refs.variableNames.add(trimmed);
19488
+ return;
19489
+ }
19490
+ if (Array.isArray(value)) {
19491
+ seen.add(value);
19492
+ for (const item of value.slice(0, 24)) {
19493
+ scanForHeapReferences(item, heap, refs, depth + 1, seen);
19494
+ }
19495
+ return;
19496
+ }
19497
+ const record = asRecord2(value);
19498
+ if (!record) return;
19499
+ seen.add(value);
19500
+ collectReferencesFromRecord(record, refs);
19501
+ for (const key of UI_CONTAINER_KEYS) {
19502
+ const nested = asRecord2(record[key]);
19503
+ if (nested) collectReferencesFromRecord(nested, refs);
19504
+ }
19505
+ for (const nested of Object.values(record).slice(0, 24)) {
19506
+ scanForHeapReferences(nested, heap, refs, depth + 1, seen);
19507
+ }
19508
+ }
19509
+ function resolveVariablesToReferences(variableNames, heap, refs) {
19510
+ for (const variableName of variableNames) {
19511
+ const variable = heap.variablesByName?.[variableName];
19512
+ if (!variable) continue;
19513
+ if (variable.kind === "entry" && variable.entryPath) {
19514
+ refs.entryPaths.add(variable.entryPath);
19515
+ }
19516
+ if (variable.kind === "list" && variable.listName) {
19517
+ refs.listNames.add(variable.listName);
19518
+ }
19519
+ }
19520
+ }
19521
+ function sortEntries(entries) {
19522
+ return [...entries].sort((a, b) => (b.updatedAt || 0) - (a.updatedAt || 0));
19523
+ }
19524
+ function sortLists(lists) {
19525
+ return [...lists].sort((a, b) => (b.updatedAt || 0) - (a.updatedAt || 0));
19526
+ }
19527
+ function dedupeEntries(entries) {
19528
+ const seen = /* @__PURE__ */ new Set();
19529
+ const result = [];
19530
+ for (const entry of entries) {
19531
+ if (!entry?.path || seen.has(entry.path)) continue;
19532
+ seen.add(entry.path);
19533
+ result.push(entry);
19534
+ }
19535
+ return result;
19536
+ }
19537
+ function dedupeLists(lists) {
19538
+ const seen = /* @__PURE__ */ new Set();
19539
+ const result = [];
19540
+ for (const list of lists) {
19541
+ if (!list?.name || seen.has(list.name)) continue;
19542
+ seen.add(list.name);
19543
+ result.push(list);
19544
+ }
19545
+ return result;
19546
+ }
19547
+ function extractResponseText(result, stdout) {
19548
+ const directText = normalizeText(result);
19549
+ if (directText) return directText;
19550
+ const record = asRecord2(result);
19551
+ if (record) {
19552
+ for (const key of RESPONSE_KEYS) {
19553
+ const normalized = normalizeText(record[key]);
19554
+ if (normalized) return normalized;
19555
+ }
19556
+ for (const containerKey of UI_CONTAINER_KEYS) {
19557
+ const nested = asRecord2(record[containerKey]);
19558
+ if (!nested) continue;
19559
+ for (const key of RESPONSE_KEYS) {
19560
+ const normalized = normalizeText(nested[key]);
19561
+ if (normalized) return normalized;
19562
+ }
19563
+ }
19564
+ }
19565
+ return humanTextFromStdout(stdout);
19566
+ }
19567
+ function fallbackResponseText(entries, lists) {
19568
+ if (entries.length > 0) {
19569
+ return entries.length === 1 ? "I found one relevant record." : `I found ${entries.length} relevant records.`;
19570
+ }
19571
+ if (lists.length > 0) {
19572
+ const emptyOnly = lists.every((list) => (list.paths || []).length === 0);
19573
+ if (emptyOnly) {
19574
+ return lists.length === 1 ? "I saved one empty result set." : `I saved ${lists.length} empty result sets.`;
19575
+ }
19576
+ return lists.length === 1 ? "I saved one result set." : `I saved ${lists.length} result sets.`;
19577
+ }
19578
+ return null;
19579
+ }
19580
+ function getJobRelatedEntries(heap, jobId) {
19581
+ return sortEntries(
19582
+ Object.values(heap.entriesByPath || {}).filter(
19583
+ (entry) => entry.relatedJobIds?.includes(jobId)
19584
+ )
19585
+ );
19586
+ }
19587
+ function getJobRelatedLists(heap, jobId) {
19588
+ return sortLists(
19589
+ Object.values(heap.listsByName || {}).filter(
19590
+ (list) => list.relatedJobIds?.includes(jobId)
19591
+ )
19592
+ );
19593
+ }
19594
+ function entriesFromLists(lists, heap) {
19595
+ const entries = [];
19596
+ for (const list of lists) {
19597
+ for (const path6 of list.paths || []) {
19598
+ const entry = heap.entriesByPath?.[path6];
19599
+ if (entry) entries.push(entry);
19600
+ }
19601
+ }
19602
+ return entries;
19603
+ }
19604
+ function resolveJobPresentation({
19605
+ jobId,
19606
+ result,
19607
+ stdout = [],
19608
+ sessionHeap,
19609
+ allowExplicitArtifacts = true
19610
+ }) {
19611
+ const refs = {
19612
+ entryPaths: /* @__PURE__ */ new Set(),
19613
+ listNames: /* @__PURE__ */ new Set(),
19614
+ variableNames: /* @__PURE__ */ new Set()
19615
+ };
19616
+ if (allowExplicitArtifacts) {
19617
+ scanForHeapReferences(result, sessionHeap, refs);
19618
+ resolveVariablesToReferences(refs.variableNames, sessionHeap, refs);
19619
+ }
19620
+ const referencedLists = sortLists(
19621
+ [...refs.listNames].map((name) => sessionHeap.listsByName?.[name]).filter((list) => Boolean(list))
19622
+ );
19623
+ const referencedEntries = sortEntries(
19624
+ [...refs.entryPaths].map((path6) => sessionHeap.entriesByPath?.[path6]).filter((entry) => Boolean(entry))
19625
+ );
19626
+ const jobLists = getJobRelatedLists(sessionHeap, jobId);
19627
+ const jobEntries = getJobRelatedEntries(sessionHeap, jobId);
19628
+ const changedEntries = dedupeEntries([
19629
+ ...jobEntries,
19630
+ ...entriesFromLists(jobLists, sessionHeap)
19631
+ ]);
19632
+ const explicitLists = dedupeLists(referencedLists);
19633
+ const explicitEntries = dedupeEntries([
19634
+ ...referencedEntries,
19635
+ ...entriesFromLists(referencedLists, sessionHeap)
19636
+ ]);
19637
+ const hasExplicitArtifacts = allowExplicitArtifacts && (explicitEntries.length > 0 || explicitLists.length > 0);
19638
+ const lists = hasExplicitArtifacts ? explicitLists : jobLists;
19639
+ const entries = hasExplicitArtifacts ? explicitEntries : changedEntries;
19640
+ const responseText = extractResponseText(result, stdout) || fallbackResponseText(entries, lists);
19641
+ return {
19642
+ responseText,
19643
+ entries,
19644
+ lists,
19645
+ changedEntries,
19646
+ changedLists: jobLists,
19647
+ hasExplicitArtifacts
19648
+ };
19649
+ }
19650
+
19651
+ // src/session-transcript.ts
19652
+ var EMPTY_HEAP = {
19653
+ entriesByPath: {},
19654
+ listsByName: {},
19655
+ variablesByName: {}};
19656
+ function asRecord3(value) {
19657
+ if (!value || typeof value !== "object" || Array.isArray(value)) return null;
19658
+ return value;
19659
+ }
19660
+ function asArray(value) {
19661
+ return Array.isArray(value) ? value : [];
19662
+ }
19663
+ function asNumber(value) {
19664
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
19665
+ }
19666
+ function asString(value) {
19667
+ return typeof value === "string" ? value : void 0;
19668
+ }
19669
+ function trimString(value) {
19670
+ return typeof value === "string" ? value.trim() : "";
19671
+ }
19672
+ function normalizeShowRefs(value) {
19673
+ const record = asRecord3(value);
19674
+ if (!record) return void 0;
19675
+ const normalizeRefs = (input) => {
19676
+ if (!Array.isArray(input)) return void 0;
19677
+ const refs = Array.from(
19678
+ new Set(
19679
+ input.filter((item) => typeof item === "string").map((item) => item.trim()).filter(Boolean)
19680
+ )
19681
+ );
19682
+ return refs.length > 0 ? refs : void 0;
19683
+ };
19684
+ const show = {
19685
+ entryPaths: normalizeRefs(record.entryPaths),
19686
+ listNames: normalizeRefs(record.listNames),
19687
+ variableNames: normalizeRefs(record.variableNames)
19688
+ };
19689
+ return show.entryPaths || show.listNames || show.variableNames ? show : void 0;
19690
+ }
19691
+ function stringifyTranscriptValue(value, fallback2 = "") {
19692
+ if (typeof value === "string") {
19693
+ return value.trim() || fallback2;
19694
+ }
19695
+ if (typeof value === "boolean") {
19696
+ return value ? "Confirmed" : "Canceled";
19697
+ }
19698
+ if (value === void 0) {
19699
+ return fallback2;
19700
+ }
19701
+ try {
19702
+ const json = JSON.stringify(value, null, 2);
19703
+ if (!json || json === "undefined") return fallback2;
19704
+ return json.length > 2e3 ? `${json.slice(0, 2e3)}...` : json;
19705
+ } catch {
19706
+ return String(value);
19707
+ }
19708
+ }
19709
+ function buildArtifactHistory(show) {
19710
+ if (!show) return void 0;
19711
+ return `[Agent message]
19712
+ ${stringifyTranscriptValue({ show }, "")}`;
19713
+ }
19714
+ function normalizeConversationMessage(raw) {
19715
+ const record = asRecord3(raw);
19716
+ if (!record) return null;
19717
+ const role = record.role === "user" ? "user" : record.role === "assistant" ? "assistant" : null;
19718
+ if (!role) return null;
19719
+ const content = trimString(
19720
+ record.content ?? record.reply ?? record.message ?? record.text
19721
+ );
19722
+ const show = normalizeShowRefs(record.show);
19723
+ const id = asString(record.id) || crypto.randomUUID();
19724
+ const timestamp = asNumber(record.timestamp) || asNumber(record.ts) || 0;
19725
+ if (!content && !show) return null;
19726
+ return {
19727
+ id,
19728
+ role,
19729
+ content,
19730
+ timestamp,
19731
+ jobId: asString(record.jobId),
19732
+ promptId: asString(record.promptId),
19733
+ show,
19734
+ historyContent: role === "assistant" ? content ? `[Assistant reply]
19735
+ ${content}` : buildArtifactHistory(show) : void 0,
19736
+ source: "conversation"
19737
+ };
19738
+ }
19739
+ function normalizePromptEntries(jobId, rawPrompts, conversationPromptIds) {
19740
+ const promptsById = asRecord3(rawPrompts) || {};
19741
+ return Object.values(promptsById).map((value) => asRecord3(value)).filter((value) => Boolean(value)).sort(
19742
+ (left, right) => (asNumber(left.openedAt) || asNumber(left.answeredAt) || 0) - (asNumber(right.openedAt) || asNumber(right.answeredAt) || 0)
19743
+ ).flatMap((prompt3) => {
19744
+ const promptId = asString(prompt3.promptId);
19745
+ if (!promptId || conversationPromptIds.has(promptId)) return [];
19746
+ const title = trimString(prompt3.title);
19747
+ const message = trimString(prompt3.message);
19748
+ const assistantContent = message || title || "Input required";
19749
+ const openedAt = asNumber(prompt3.openedAt) || 0;
19750
+ const answeredAt = asNumber(prompt3.answeredAt) || openedAt;
19751
+ const entries = [
19752
+ {
19753
+ id: `prompt:${promptId}:assistant`,
19754
+ role: "assistant",
19755
+ content: assistantContent,
19756
+ timestamp: openedAt,
19757
+ jobId,
19758
+ promptId,
19759
+ historyContent: `[Assistant reply]
19760
+ ${assistantContent}`,
19761
+ source: "job_prompt"
19762
+ }
19763
+ ];
19764
+ if (Object.prototype.hasOwnProperty.call(prompt3, "answer")) {
19765
+ entries.push({
19766
+ id: `prompt:${promptId}:user`,
19767
+ role: "user",
19768
+ content: stringifyTranscriptValue(prompt3.answer, ""),
19769
+ timestamp: answeredAt,
19770
+ jobId,
19771
+ promptId,
19772
+ source: "job_prompt"
19773
+ });
19774
+ }
19775
+ return entries;
19776
+ });
19777
+ }
19778
+ function normalizeAgentMessageEntries(jobId, rawMessages) {
19779
+ return asArray(rawMessages).map((value) => asRecord3(value)).filter((value) => Boolean(value)).sort(
19780
+ (left, right) => (asNumber(left.timestamp) || asNumber(left.ts) || 0) - (asNumber(right.timestamp) || asNumber(right.ts) || 0)
19781
+ ).flatMap((message) => {
19782
+ const messageId = asString(message.messageId) || asString(message.id) || crypto.randomUUID();
19783
+ const timestamp = asNumber(message.timestamp) || asNumber(message.ts) || 0;
19784
+ const reply = trimString(
19785
+ message.reply ?? message.message ?? message.text ?? message.content
19786
+ );
19787
+ const show = normalizeShowRefs(message.show);
19788
+ const entries = [];
19789
+ if (reply) {
19790
+ entries.push({
19791
+ id: `agent:${messageId}:text`,
19792
+ role: "assistant",
19793
+ content: reply,
19794
+ timestamp,
19795
+ jobId,
19796
+ historyContent: `[Assistant reply]
19797
+ ${reply}`,
19798
+ source: "job_agent_message"
19799
+ });
19800
+ }
19801
+ if (show) {
19802
+ entries.push({
19803
+ id: `agent:${messageId}:artifacts`,
19804
+ role: "assistant",
19805
+ content: "",
19806
+ timestamp,
19807
+ jobId,
19808
+ show,
19809
+ historyContent: buildArtifactHistory(show),
19810
+ source: "job_agent_message"
19811
+ });
19812
+ }
19813
+ return entries;
19814
+ });
19815
+ }
19816
+ function buildJobFallbackEntries(jobId, job2, sessionHeap) {
19817
+ const timestamp = asNumber(job2.finishedAt) || asNumber(job2.startedAt) || asNumber(job2.submittedAt) || 0;
19818
+ const resultPreview = stringifyTranscriptValue(
19819
+ job2.result,
19820
+ "No job result recorded."
19821
+ );
19822
+ const presentation = resolveJobPresentation({
19823
+ jobId,
19824
+ result: job2.result,
19825
+ stdout: [],
19826
+ sessionHeap
19827
+ });
19828
+ const entries = [];
19829
+ const responseText = presentation.responseText || "";
19830
+ if (responseText) {
19831
+ entries.push({
19832
+ id: `job:${jobId}:result-text`,
19833
+ role: "assistant",
19834
+ content: responseText,
19835
+ timestamp,
19836
+ jobId,
19837
+ historyContent: `[Assistant reply]
19838
+ ${responseText}`,
19839
+ source: "job_result"
19840
+ });
19841
+ }
19842
+ const show = {
19843
+ entryPaths: presentation.entries.map((entry) => entry.path),
19844
+ listNames: presentation.lists.map((list) => list.name)
19845
+ };
19846
+ if (show.entryPaths && show.entryPaths.length > 0 || show.listNames && show.listNames.length > 0) {
19847
+ entries.push({
19848
+ id: `job:${jobId}:result-artifacts`,
19849
+ role: "assistant",
19850
+ content: "",
19851
+ timestamp,
19852
+ jobId,
19853
+ show,
19854
+ historyContent: buildArtifactHistory(show),
19855
+ source: "job_result"
19856
+ });
19857
+ }
19858
+ if (entries.length === 0 && trimString(job2.error)) {
19859
+ entries.push({
19860
+ id: `job:${jobId}:result-error`,
19861
+ role: "assistant",
19862
+ content: trimString(job2.error),
19863
+ timestamp,
19864
+ jobId,
19865
+ historyContent: `[Assistant reply]
19866
+ ${trimString(job2.error)}`,
19867
+ source: "job_result"
19868
+ });
19869
+ }
19870
+ if (entries.length === 0 && resultPreview && resultPreview !== "No job result recorded.") {
19871
+ entries.push({
19872
+ id: `job:${jobId}:result-preview`,
19873
+ role: "assistant",
19874
+ content: resultPreview,
19875
+ timestamp,
19876
+ jobId,
19877
+ historyContent: `[Assistant reply]
19878
+ ${resultPreview}`,
19879
+ source: "job_result"
19880
+ });
19881
+ }
19882
+ return entries;
19883
+ }
19884
+ function buildJobCodeEntry(jobId, job2) {
19885
+ const code = trimString(job2.source);
19886
+ if (!code) return null;
19887
+ const jobStatus = asString(job2.status);
19888
+ const error2 = jobStatus === "failed" || jobStatus === "canceled" || jobStatus === "timeout" ? trimString(job2.error) || `Job ${jobStatus}` : void 0;
19889
+ return {
19890
+ id: `job:${jobId}:code`,
19891
+ role: "assistant",
19892
+ content: "",
19893
+ timestamp: asNumber(job2.submittedAt) || asNumber(job2.startedAt) || asNumber(job2.finishedAt) || 0,
19894
+ jobId,
19895
+ code,
19896
+ jobStatus,
19897
+ jobResultPreview: stringifyTranscriptValue(job2.result, "No job result recorded."),
19898
+ error: error2,
19899
+ source: "job_code"
19900
+ };
19901
+ }
19902
+ function buildSessionTranscript(input) {
19903
+ const liveDoc = input.liveDoc || null;
19904
+ const sessionHeap = input.sessionHeap || EMPTY_HEAP;
19905
+ const transcript = [];
19906
+ const conversationMessages = asArray(asRecord3(liveDoc?.conversation)?.messages).map((message) => normalizeConversationMessage(message)).filter((message) => Boolean(message));
19907
+ const conversationPromptIds = new Set(
19908
+ conversationMessages.map((message) => message.promptId).filter((promptId) => Boolean(promptId))
19909
+ );
19910
+ const assistantConversationJobIds = new Set(
19911
+ conversationMessages.filter((message) => message.role === "assistant" && Boolean(message.jobId)).map((message) => message.jobId)
19912
+ );
19913
+ transcript.push(...conversationMessages);
19914
+ const jobsById = asRecord3(asRecord3(liveDoc?.jobs)?.byId) || {};
19915
+ const jobs = Object.values(jobsById).map((value) => asRecord3(value)).filter((value) => Boolean(value)).sort(
19916
+ (left, right) => (asNumber(left.submittedAt) || asNumber(left.startedAt) || asNumber(left.finishedAt) || 0) - (asNumber(right.submittedAt) || asNumber(right.startedAt) || asNumber(right.finishedAt) || 0)
19917
+ );
19918
+ for (const job2 of jobs) {
19919
+ const jobId = asString(job2.jobId);
19920
+ if (!jobId) continue;
19921
+ const codeEntry = buildJobCodeEntry(jobId, job2);
19922
+ if (codeEntry) {
19923
+ transcript.push(codeEntry);
19924
+ }
19925
+ transcript.push(
19926
+ ...normalizePromptEntries(jobId, job2.prompts, conversationPromptIds)
19927
+ );
19928
+ if (!assistantConversationJobIds.has(jobId)) {
19929
+ const agentEntries = normalizeAgentMessageEntries(jobId, job2.agentMessages);
19930
+ if (agentEntries.length > 0) {
19931
+ transcript.push(...agentEntries);
19932
+ } else {
19933
+ transcript.push(
19934
+ ...buildJobFallbackEntries(
19935
+ jobId,
19936
+ job2,
19937
+ sessionHeap
19938
+ )
19939
+ );
19940
+ }
19941
+ }
19942
+ }
19943
+ return transcript.sort((left, right) => {
19944
+ if (left.timestamp !== right.timestamp) {
19945
+ return left.timestamp - right.timestamp;
19946
+ }
19947
+ return left.id.localeCompare(right.id);
19948
+ });
19949
+ }
19950
+
19416
19951
  // src/effect-runtime.ts
19417
19952
  function computeEffectKey(effect) {
19418
19953
  const attachedClass = effect.className?.trim();
@@ -19421,6 +19956,50 @@ function computeEffectKey(effect) {
19421
19956
  }
19422
19957
  return effect.static ? `class:${attachedClass}:static:${effect.name}` : `class:${attachedClass}:instance:${effect.name}`;
19423
19958
  }
19959
+ function computeEffectVersionSelectorSpecificity(selector) {
19960
+ if (!selector || selector.mode === "all") {
19961
+ return 0;
19962
+ }
19963
+ if (selector.mode === "exact") {
19964
+ return 2;
19965
+ }
19966
+ return 1;
19967
+ }
19968
+ function matchesEffectVersionSelector(selector, buildVersionNumber) {
19969
+ if (!selector || selector.mode === "all") {
19970
+ return true;
19971
+ }
19972
+ if (typeof buildVersionNumber !== "number" || !Number.isFinite(buildVersionNumber)) {
19973
+ return false;
19974
+ }
19975
+ if (selector.mode === "exact") {
19976
+ return buildVersionNumber === selector.versionNumber;
19977
+ }
19978
+ if (selector.mode === "before") {
19979
+ return buildVersionNumber < selector.versionNumber;
19980
+ }
19981
+ return buildVersionNumber > selector.versionNumber;
19982
+ }
19983
+ function selectRegisteredEffect(effectMap, effectKey, buildVersionNumber) {
19984
+ let bestEffect;
19985
+ let bestSpecificity = Number.NEGATIVE_INFINITY;
19986
+ for (const effect of effectMap.values()) {
19987
+ if (computeEffectKey(effect) !== effectKey) {
19988
+ continue;
19989
+ }
19990
+ if (!matchesEffectVersionSelector(effect.versionSelector, buildVersionNumber)) {
19991
+ continue;
19992
+ }
19993
+ const specificity = computeEffectVersionSelectorSpecificity(
19994
+ effect.versionSelector
19995
+ );
19996
+ if (!bestEffect || specificity > bestSpecificity) {
19997
+ bestEffect = effect;
19998
+ bestSpecificity = specificity;
19999
+ }
20000
+ }
20001
+ return bestEffect;
20002
+ }
19424
20003
  function normalizeEffectBehaviors(value) {
19425
20004
  return normalizeEffectBehaviorSummary(
19426
20005
  value
@@ -19441,9 +20020,17 @@ function resolveReverseEffect(effectMap, currentEffect, request, behaviors) {
19441
20020
  return void 0;
19442
20021
  }
19443
20022
  if (reverseHandler.includes(":")) {
19444
- return effectMap.get(reverseHandler);
20023
+ return selectRegisteredEffect(
20024
+ effectMap,
20025
+ reverseHandler,
20026
+ request.context?.buildVersionNumber
20027
+ );
19445
20028
  }
19446
- const directMatch = effectMap.get(reverseHandler);
20029
+ const directMatch = selectRegisteredEffect(
20030
+ effectMap,
20031
+ reverseHandler,
20032
+ request.context?.buildVersionNumber
20033
+ );
19447
20034
  if (directMatch) {
19448
20035
  return directMatch;
19449
20036
  }
@@ -19458,7 +20045,11 @@ function resolveReverseEffect(effectMap, currentEffect, request, behaviors) {
19458
20045
  })
19459
20046
  ];
19460
20047
  for (const candidateKey of candidateKeys) {
19461
- const candidate = effectMap.get(candidateKey);
20048
+ const candidate = selectRegisteredEffect(
20049
+ effectMap,
20050
+ candidateKey,
20051
+ request.context?.buildVersionNumber
20052
+ );
19462
20053
  if (candidate) {
19463
20054
  return candidate;
19464
20055
  }
@@ -19494,7 +20085,11 @@ function resolveHandlerForMode(effectMap, effect, request) {
19494
20085
  return { effect, mode, handler: effect.handler };
19495
20086
  }
19496
20087
  async function invokeRegisteredEffect(effectMap, request) {
19497
- const effect = effectMap.get(request.effectKey);
20088
+ const effect = selectRegisteredEffect(
20089
+ effectMap,
20090
+ request.effectKey,
20091
+ request.context?.buildVersionNumber
20092
+ );
19498
20093
  if (!effect) {
19499
20094
  throw new Error(`Effect handler not found: ${request.effectKey}`);
19500
20095
  }
@@ -19615,6 +20210,17 @@ function computeEffectKey2(effect) {
19615
20210
  }
19616
20211
  return effect.static ? `class:${attachedClass}:static:${effect.name}` : `class:${attachedClass}:instance:${effect.name}`;
19617
20212
  }
20213
+ function computeEffectVersionSelectorKey(selector) {
20214
+ if (!selector || selector.mode === "all") {
20215
+ return "all";
20216
+ }
20217
+ return `${selector.mode}:${selector.versionNumber}`;
20218
+ }
20219
+ function computeEffectRegistrationKey(effect) {
20220
+ return `${computeEffectKey2(effect)}@${computeEffectVersionSelectorKey(
20221
+ effect.versionSelector
20222
+ )}`;
20223
+ }
19618
20224
  function buildEffectHostUrl(apiUrl, sandboxId, effectClientId, clientId) {
19619
20225
  const url = new URL(apiUrl);
19620
20226
  if (url.pathname.endsWith("/granular/ws/connect")) {
@@ -20109,7 +20715,9 @@ var Environment = class {
20109
20715
  { target: targetPath }
20110
20716
  );
20111
20717
  if (result.errors?.length) {
20112
- throw new Error(`attach failed: ${result.errors[0]?.message ?? "Unknown GraphQL error"}`);
20718
+ throw new Error(
20719
+ `attach failed: ${result.errors[0]?.message ?? "Unknown GraphQL error"}`
20720
+ );
20113
20721
  }
20114
20722
  }
20115
20723
  /**
@@ -20144,7 +20752,9 @@ var Environment = class {
20144
20752
  }`
20145
20753
  );
20146
20754
  if (result.errors?.length) {
20147
- throw new Error(`detach failed: ${result.errors[0]?.message ?? "Unknown GraphQL error"}`);
20755
+ throw new Error(
20756
+ `detach failed: ${result.errors[0]?.message ?? "Unknown GraphQL error"}`
20757
+ );
20148
20758
  }
20149
20759
  }
20150
20760
  /**
@@ -20266,7 +20876,9 @@ var Environment = class {
20266
20876
  async _runGraphql(query, label) {
20267
20877
  const result = await this.graphql(query);
20268
20878
  if (result.errors?.length) {
20269
- throw new Error(`${label}: ${result.errors[0]?.message ?? "Unknown GraphQL error"}`);
20879
+ throw new Error(
20880
+ `${label}: ${result.errors[0]?.message ?? "Unknown GraphQL error"}`
20881
+ );
20270
20882
  }
20271
20883
  return result.data;
20272
20884
  }
@@ -20801,6 +21413,9 @@ var EnvironmentSession = class extends Session {
20801
21413
  get envName() {
20802
21414
  return this.environment.envName;
20803
21415
  }
21416
+ get tag() {
21417
+ return this.environment.tag;
21418
+ }
20804
21419
  get versionId() {
20805
21420
  return this.environment.versionId;
20806
21421
  }
@@ -20820,12 +21435,171 @@ var EnvironmentSession = class extends Session {
20820
21435
  return this.environment.feedback;
20821
21436
  }
20822
21437
  /**
20823
- * Return a plain JS snapshot of the synced session heap.
21438
+ * Return a plain JS copy of the synced session heap.
20824
21439
  */
20825
21440
  getHeap() {
20826
21441
  const doc = this.document;
20827
21442
  return normalizeHeapSnapshot(doc?.heap);
20828
21443
  }
21444
+ async sessionDataRequest(path6, query) {
21445
+ const searchParams = new URLSearchParams();
21446
+ for (const [key, value] of Object.entries(query || {})) {
21447
+ if (value !== null && typeof value !== "undefined" && value !== "") {
21448
+ searchParams.set(key, String(value));
21449
+ }
21450
+ }
21451
+ const queryString = searchParams.toString();
21452
+ const response = await fetch(
21453
+ `${this.environment.runtimeBaseUrl}/orchestrator/ws/sessions/${encodeURIComponent(this.sessionId)}${path6}${queryString ? `?${queryString}` : ""}`,
21454
+ {
21455
+ method: "GET",
21456
+ headers: {
21457
+ Authorization: `Bearer ${this.environment.authToken}`,
21458
+ "Content-Type": "application/json"
21459
+ }
21460
+ }
21461
+ );
21462
+ if (!response.ok) {
21463
+ const errorText = await response.text();
21464
+ throw new Error(
21465
+ `Session data API Error (${response.status}): ${errorText}`
21466
+ );
21467
+ }
21468
+ return response.json();
21469
+ }
21470
+ async collectAllSessionItems(listPage) {
21471
+ const items = [];
21472
+ let cursor = null;
21473
+ do {
21474
+ const page = await listPage({ limit: 500, cursor });
21475
+ items.push(...page.items);
21476
+ cursor = page.nextCursor;
21477
+ } while (cursor);
21478
+ return items;
21479
+ }
21480
+ /**
21481
+ * Fetch the live session document from the runtime DO.
21482
+ *
21483
+ * For history and saved artifacts, prefer the collection APIs on
21484
+ * `messages`, `timeline`, `jobs`, and `heap`.
21485
+ */
21486
+ async getDocument() {
21487
+ return this.sessionDataRequest("/document");
21488
+ }
21489
+ get messages() {
21490
+ return {
21491
+ list: (options = {}) => this.sessionDataRequest(
21492
+ "/messages",
21493
+ options
21494
+ )
21495
+ };
21496
+ }
21497
+ get timeline() {
21498
+ return {
21499
+ list: (options = {}) => this.sessionDataRequest(
21500
+ "/timeline",
21501
+ options
21502
+ )
21503
+ };
21504
+ }
21505
+ get jobs() {
21506
+ return {
21507
+ list: (options = {}) => this.sessionDataRequest(
21508
+ "/jobs",
21509
+ options
21510
+ ),
21511
+ get: (jobId) => this.sessionDataRequest(
21512
+ `/jobs/${encodeURIComponent(jobId)}`
21513
+ )
21514
+ };
21515
+ }
21516
+ get heap() {
21517
+ return {
21518
+ entries: {
21519
+ list: (options = {}) => this.sessionDataRequest(
21520
+ "/heap/entries",
21521
+ options
21522
+ ),
21523
+ get: (path6) => this.sessionDataRequest(
21524
+ `/heap/entries/${encodeURIComponent(path6)}`
21525
+ )
21526
+ },
21527
+ lists: {
21528
+ list: (options = {}) => this.sessionDataRequest(
21529
+ "/heap/lists",
21530
+ options
21531
+ ),
21532
+ get: (name) => this.sessionDataRequest(
21533
+ `/heap/lists/${encodeURIComponent(name)}`
21534
+ )
21535
+ }
21536
+ };
21537
+ }
21538
+ get transcript() {
21539
+ return {
21540
+ list: async (options = {}) => {
21541
+ const [messages, jobs, entries, lists] = await Promise.all([
21542
+ this.collectAllSessionItems(this.messages.list),
21543
+ this.collectAllSessionItems(
21544
+ (pageOptions) => this.jobs.list({ ...pageOptions, status: "all" })
21545
+ ),
21546
+ this.collectAllSessionItems(this.heap.entries.list),
21547
+ this.collectAllSessionItems(this.heap.lists.list)
21548
+ ]);
21549
+ const liveDoc = {
21550
+ conversation: { messages },
21551
+ jobs: {
21552
+ byId: Object.fromEntries(
21553
+ jobs.map((job2) => {
21554
+ const record = job2 && typeof job2 === "object" ? job2 : null;
21555
+ const id = typeof record?.jobId === "string" ? record.jobId : typeof record?.id === "string" ? record.id : null;
21556
+ return id ? [id, record] : null;
21557
+ }).filter(
21558
+ (entry) => Boolean(entry)
21559
+ )
21560
+ )
21561
+ }
21562
+ };
21563
+ const heap = normalizeHeapSnapshot({
21564
+ entriesByPath: Object.fromEntries(
21565
+ entries.map((entry) => {
21566
+ return entry?.path ? [
21567
+ entry.path,
21568
+ entry
21569
+ ] : null;
21570
+ }).filter(
21571
+ (entry) => Boolean(entry)
21572
+ )
21573
+ ),
21574
+ listsByName: Object.fromEntries(
21575
+ lists.map((list) => {
21576
+ return list?.name ? [list.name, list] : null;
21577
+ }).filter(
21578
+ (entry) => Boolean(entry)
21579
+ )
21580
+ ),
21581
+ variablesByName: this.getHeap().variablesByName,
21582
+ updatedAt: Date.now()
21583
+ });
21584
+ const allItems = buildSessionTranscript({
21585
+ liveDoc,
21586
+ sessionHeap: heap
21587
+ });
21588
+ const limit = Math.max(
21589
+ 1,
21590
+ Math.min(500, Math.floor(options.limit ?? 100))
21591
+ );
21592
+ const offset = typeof options.cursor === "string" ? Number.parseInt(options.cursor, 10) || 0 : 0;
21593
+ const items = allItems.slice(offset, offset + limit);
21594
+ const nextOffset = offset + items.length;
21595
+ return {
21596
+ items,
21597
+ nextCursor: nextOffset < allItems.length ? String(nextOffset) : null,
21598
+ totalCount: allItems.length
21599
+ };
21600
+ }
21601
+ };
21602
+ }
20829
21603
  async graphql(query, variables) {
20830
21604
  return this.environment.graphql(query, variables);
20831
21605
  }
@@ -20968,7 +21742,7 @@ var Granular = class _Granular {
20968
21742
  onUnexpectedClose;
20969
21743
  onReconnectError;
20970
21744
  debugHttp = process.env.GRANULAR_DEBUG_HTTP === "1";
20971
- /** Sandbox-level effect registry: sandboxId → (effectKey → ToolWithHandler) */
21745
+ /** Sandbox-level effect registry: sandboxId → (effectKey@selector → ToolWithHandler) */
20972
21746
  sandboxEffects = /* @__PURE__ */ new Map();
20973
21747
  /** Live sandbox-scoped effect hosts keyed by sandboxId */
20974
21748
  sandboxEffectHosts = /* @__PURE__ */ new Map();
@@ -21387,7 +22161,8 @@ var Granular = class _Granular {
21387
22161
  provenance: effect.provenance || { source: "custom" },
21388
22162
  tags: effect.tags,
21389
22163
  className: effect.className,
21390
- static: effect.static
22164
+ static: effect.static,
22165
+ versionSelector: effect.versionSelector
21391
22166
  };
21392
22167
  }
21393
22168
  async publishSandboxEffectCatalog(host) {
@@ -21575,7 +22350,10 @@ var Granular = class _Granular {
21575
22350
  async registerEffect(sandboxNameOrId, effect) {
21576
22351
  const sandbox = await this.findOrCreateSandbox(sandboxNameOrId);
21577
22352
  const sandboxId = sandbox.sandboxId;
21578
- this.getSandboxEffectMap(sandboxId).set(computeEffectKey2(effect), effect);
22353
+ this.getSandboxEffectMap(sandboxId).set(
22354
+ computeEffectRegistrationKey(effect),
22355
+ effect
22356
+ );
21579
22357
  await this.syncSandboxEffectCatalog(sandboxId);
21580
22358
  }
21581
22359
  /**
@@ -21588,7 +22366,7 @@ var Granular = class _Granular {
21588
22366
  const sandboxId = sandbox.sandboxId;
21589
22367
  const map = this.getSandboxEffectMap(sandboxId);
21590
22368
  for (const effect of effects2) {
21591
- map.set(computeEffectKey2(effect), effect);
22369
+ map.set(computeEffectRegistrationKey(effect), effect);
21592
22370
  }
21593
22371
  await this.syncSandboxEffectCatalog(sandboxId);
21594
22372
  }
@@ -21606,7 +22384,7 @@ var Granular = class _Granular {
21606
22384
  return;
21607
22385
  }
21608
22386
  const nextEntries = Array.from(currentMap.entries()).filter(
21609
- ([effectKey, effect]) => effectKey !== name && effect.name !== name
22387
+ ([, effect]) => computeEffectKey2(effect) !== name && effect.name !== name
21610
22388
  );
21611
22389
  if (nextEntries.length === currentMap.size) {
21612
22390
  return;
@@ -22053,14 +22831,18 @@ async function resolveOntologyId(granular, ontology) {
22053
22831
  const { config } = createGranularClient();
22054
22832
  const requestedOntology = ontology ?? config.sandboxId;
22055
22833
  if (!requestedOntology) {
22056
- throw new Error("No ontology configured. Run `granular init` first or pass `--ontology`.");
22834
+ throw new Error(
22835
+ "No ontology configured. Run `granular init` first or pass `--ontology`."
22836
+ );
22057
22837
  }
22058
22838
  try {
22059
22839
  const sandbox = await granular.sandboxes.get(requestedOntology);
22060
22840
  return sandbox.sandboxId;
22061
22841
  } catch {
22062
22842
  const sandboxes = await granular.sandboxes.list();
22063
- const existing = sandboxes.items.find((item) => item.name === requestedOntology);
22843
+ const existing = sandboxes.items.find(
22844
+ (item) => item.name === requestedOntology
22845
+ );
22064
22846
  if (existing) {
22065
22847
  return existing.sandboxId;
22066
22848
  }
@@ -22068,7 +22850,8 @@ async function resolveOntologyId(granular, ontology) {
22068
22850
  throw new Error(`Ontology not found: ${requestedOntology}`);
22069
22851
  }
22070
22852
  function matchesEnvironmentName(environment, requested) {
22071
- return environment.environment === requested || environment.envName === requested;
22853
+ const managedPrefix = `__sdk__${requested}__`;
22854
+ return environment.environment === requested || environment.envName === requested || environment.environment?.startsWith(managedPrefix) || environment.envName?.startsWith(managedPrefix) || environment.tag?.name === requested || environment.buildPolicy?.tagName === requested || environment.tracking?.tagName === requested;
22072
22855
  }
22073
22856
  async function resolveEnvironmentData(granular, options) {
22074
22857
  if (options.environmentId) {
@@ -22077,7 +22860,9 @@ async function resolveEnvironmentData(granular, options) {
22077
22860
  const ontologyId = await resolveOntologyId(granular, options.ontology);
22078
22861
  const environmentName = options.environment ?? "dev";
22079
22862
  const environments = await granular.environments.list(ontologyId);
22080
- const existing = environments.find((environment) => matchesEnvironmentName(environment, environmentName));
22863
+ const existing = environments.find(
22864
+ (environment) => matchesEnvironmentName(environment, environmentName)
22865
+ );
22081
22866
  if (existing) {
22082
22867
  return existing;
22083
22868
  }
@@ -22109,7 +22894,9 @@ async function listSessionsForEnvironment(granular, environmentId, status) {
22109
22894
  async function connectRuntime(options) {
22110
22895
  if (options.sessionId) {
22111
22896
  const { granular: granular2 } = createGranularClient();
22112
- const environment2 = await granular2.connectSession({ sessionId: options.sessionId });
22897
+ const environment2 = await granular2.connectSession({
22898
+ sessionId: options.sessionId
22899
+ });
22113
22900
  return {
22114
22901
  granular: granular2,
22115
22902
  environment: environment2,
@@ -22120,7 +22907,9 @@ async function connectRuntime(options) {
22120
22907
  const { granular, config } = createGranularClient();
22121
22908
  const ontologyId = options.ontology ?? config.sandboxId;
22122
22909
  if (!ontologyId) {
22123
- throw new Error("No ontology configured. Run `granular init` first or pass `--ontology`.");
22910
+ throw new Error(
22911
+ "No ontology configured. Run `granular init` first or pass `--ontology`."
22912
+ );
22124
22913
  }
22125
22914
  const environmentHandle = await granular.connect({
22126
22915
  ontology: ontologyId,
@@ -22171,13 +22960,14 @@ function readJobCodeFromOptions(options) {
22171
22960
  // src/cli/commands/connect.ts
22172
22961
  async function connectTestCommand(options) {
22173
22962
  const emitJson = options.json === true;
22963
+ const requestedEnvironment = options.environment ?? "dev";
22174
22964
  if (!emitJson) {
22175
22965
  printHeader();
22176
22966
  }
22177
22967
  await withRuntimeConnection(
22178
22968
  {
22179
22969
  ontology: options.ontology,
22180
- environment: options.environment ?? "dev",
22970
+ environment: requestedEnvironment,
22181
22971
  userId: options.user,
22182
22972
  permissions: normalizePermissions(options.permissions)
22183
22973
  },
@@ -22187,7 +22977,7 @@ async function connectTestCommand(options) {
22187
22977
  ontologyId,
22188
22978
  sandboxId: environment.sandboxId,
22189
22979
  environmentId: environment.environmentId,
22190
- environment: environment.envName,
22980
+ environment: environment.tag || requestedEnvironment,
22191
22981
  sessionId: environment.sessionId,
22192
22982
  subjectId: environment.subjectId,
22193
22983
  versionId: environment.versionId
@@ -22200,7 +22990,7 @@ async function connectTestCommand(options) {
22200
22990
  console.log();
22201
22991
  keyValue({
22202
22992
  "Ontology ID": payload.ontologyId,
22203
- "Environment": payload.environment,
22993
+ Environment: payload.environment,
22204
22994
  "Environment ID": payload.environmentId,
22205
22995
  "Session ID": payload.sessionId,
22206
22996
  "Subject ID": payload.subjectId,
@@ -22267,7 +23057,9 @@ async function sessionDocCommand(options) {
22267
23057
  ontologyId,
22268
23058
  sessionId: environment.sessionId,
22269
23059
  environmentId: environment.environmentId,
22270
- document: documentToJson(environment.document)
23060
+ document: documentToJson(
23061
+ environment.document
23062
+ )
22271
23063
  };
22272
23064
  if (!emitJson) {
22273
23065
  step("Session document");
@@ -22279,6 +23071,7 @@ async function sessionDocCommand(options) {
22279
23071
  }
22280
23072
  async function sessionCreateCommand(options) {
22281
23073
  const emitJson = options.json === true;
23074
+ const requestedEnvironment = options.environment ?? "dev";
22282
23075
  if (!emitJson) {
22283
23076
  printHeader();
22284
23077
  }
@@ -22286,7 +23079,7 @@ async function sessionCreateCommand(options) {
22286
23079
  const permissions = normalizePermissions(options.permissions);
22287
23080
  const envData = await resolveEnvironmentData(granular, {
22288
23081
  ontology: options.ontology,
22289
- environment: options.environment ?? "dev",
23082
+ environment: requestedEnvironment,
22290
23083
  environmentId: options.environmentId,
22291
23084
  userId: options.user,
22292
23085
  permissions,
@@ -22300,7 +23093,7 @@ async function sessionCreateCommand(options) {
22300
23093
  ok: true,
22301
23094
  ontologyId: envData.sandboxId,
22302
23095
  environmentId: environment.environmentId,
22303
- environment: environment.envName,
23096
+ environment: environment.tag || envData.tag?.name || envData.buildPolicy.tagName || requestedEnvironment,
22304
23097
  sessionId: environment.sessionId,
22305
23098
  subjectId: environment.subjectId,
22306
23099
  versionId: environment.versionId
@@ -22313,7 +23106,7 @@ async function sessionCreateCommand(options) {
22313
23106
  console.log();
22314
23107
  keyValue({
22315
23108
  "Ontology ID": payload.ontologyId,
22316
- "Environment": payload.environment,
23109
+ Environment: payload.environment,
22317
23110
  "Environment ID": payload.environmentId,
22318
23111
  "Session ID": payload.sessionId,
22319
23112
  "Subject ID": payload.subjectId,
@@ -22331,21 +23124,26 @@ async function sessionCreateCommand(options) {
22331
23124
  async function sessionListCommand(options) {
22332
23125
  const emitJson = options.json === true;
22333
23126
  const status = options.status ?? "active";
23127
+ const requestedEnvironment = options.environment ?? "dev";
22334
23128
  if (!emitJson) {
22335
23129
  printHeader();
22336
23130
  }
22337
23131
  const { granular } = createGranularClient();
22338
23132
  const environmentData = await resolveEnvironmentData(granular, {
22339
23133
  ontology: options.ontology,
22340
- environment: options.environment ?? "dev",
23134
+ environment: requestedEnvironment,
22341
23135
  environmentId: options.environmentId,
22342
23136
  createIfMissing: false
22343
23137
  });
22344
- const items = await listSessionsForEnvironment(granular, environmentData.environmentId, status);
23138
+ const items = await listSessionsForEnvironment(
23139
+ granular,
23140
+ environmentData.environmentId,
23141
+ status
23142
+ );
22345
23143
  const payload = {
22346
23144
  ontologyId: environmentData.sandboxId,
22347
23145
  environmentId: environmentData.environmentId,
22348
- environment: environmentData.environment ?? environmentData.envName,
23146
+ environment: environmentData.tag?.name || environmentData.buildPolicy.tagName || requestedEnvironment,
22349
23147
  status,
22350
23148
  items
22351
23149
  };