@granular-software/sdk 0.4.50 → 0.4.52
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/README.md +53 -0
- package/dist/agent-evals.d.mts +2 -2
- package/dist/agent-evals.d.ts +2 -2
- package/dist/agent-evals.js +685 -210
- package/dist/agent-evals.js.map +1 -1
- package/dist/agent-evals.mjs +685 -210
- package/dist/agent-evals.mjs.map +1 -1
- package/dist/agent-harness.js +4 -2
- package/dist/agent-harness.js.map +1 -1
- package/dist/agent-harness.mjs +4 -2
- package/dist/agent-harness.mjs.map +1 -1
- package/dist/cli/index.js +754 -253
- package/dist/{client-DaYFTHG8.d.mts → client-B2OyGOHE.d.mts} +44 -13
- package/dist/{client-BbI7ThzU.d.ts → client-BMfjRJTs.d.ts} +44 -13
- package/dist/index.d.mts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +685 -210
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +685 -210
- package/dist/index.mjs.map +1 -1
- package/dist/{spend-RpJikX9w.d.mts → spend-DpRRCrAr.d.mts} +161 -5
- package/dist/{spend-RpJikX9w.d.ts → spend-DpRRCrAr.d.ts} +161 -5
- package/dist/spend.d.mts +1 -1
- package/dist/spend.d.ts +1 -1
- package/dist/spend.js +6 -1
- package/dist/spend.js.map +1 -1
- package/dist/spend.mjs +6 -1
- package/dist/spend.mjs.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -60,11 +60,11 @@ var __export = (target, all) => {
|
|
|
60
60
|
for (var name in all)
|
|
61
61
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
62
62
|
};
|
|
63
|
-
var __copyProps = (to,
|
|
64
|
-
if (
|
|
65
|
-
for (let key of __getOwnPropNames(
|
|
63
|
+
var __copyProps = (to, from2, except, desc) => {
|
|
64
|
+
if (from2 && typeof from2 === "object" || typeof from2 === "function") {
|
|
65
|
+
for (let key of __getOwnPropNames(from2))
|
|
66
66
|
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
67
|
-
__defProp(to, key, { get: () =>
|
|
67
|
+
__defProp(to, key, { get: () => from2[key], enumerable: !(desc = __getOwnPropDesc(from2, key)) || desc.enumerable });
|
|
68
68
|
}
|
|
69
69
|
return to;
|
|
70
70
|
};
|
|
@@ -7898,14 +7898,14 @@ var ApiClient = class {
|
|
|
7898
7898
|
async getVersion(versionId) {
|
|
7899
7899
|
return this.request(`/control/versions/${versionId}`);
|
|
7900
7900
|
}
|
|
7901
|
-
async triggerBuild(sandboxId, manifestId) {
|
|
7901
|
+
async triggerBuild(sandboxId, manifestId, releaseKey) {
|
|
7902
7902
|
return this.request(`/control/sandboxes/${sandboxId}/builds`, {
|
|
7903
7903
|
method: "POST",
|
|
7904
|
-
body: JSON.stringify({ manifestId })
|
|
7904
|
+
body: JSON.stringify({ manifestId, releaseKey })
|
|
7905
7905
|
});
|
|
7906
7906
|
}
|
|
7907
|
-
async createVersion(sandboxId, manifestId) {
|
|
7908
|
-
return this.triggerBuild(sandboxId, manifestId);
|
|
7907
|
+
async createVersion(sandboxId, manifestId, releaseKey) {
|
|
7908
|
+
return this.triggerBuild(sandboxId, manifestId, releaseKey);
|
|
7909
7909
|
}
|
|
7910
7910
|
async listTags(sandboxId) {
|
|
7911
7911
|
const result = await this.request(
|
|
@@ -8889,7 +8889,7 @@ createChalk({ level: stderrColor ? stderrColor.level : 0 });
|
|
|
8889
8889
|
var source_default = chalk;
|
|
8890
8890
|
|
|
8891
8891
|
// ../../node_modules/mimic-function/index.js
|
|
8892
|
-
var copyProperty = (to,
|
|
8892
|
+
var copyProperty = (to, from2, property, ignoreNonConfigurable) => {
|
|
8893
8893
|
if (property === "length" || property === "prototype") {
|
|
8894
8894
|
return;
|
|
8895
8895
|
}
|
|
@@ -8897,7 +8897,7 @@ var copyProperty = (to, from, property, ignoreNonConfigurable) => {
|
|
|
8897
8897
|
return;
|
|
8898
8898
|
}
|
|
8899
8899
|
const toDescriptor = Object.getOwnPropertyDescriptor(to, property);
|
|
8900
|
-
const fromDescriptor = Object.getOwnPropertyDescriptor(
|
|
8900
|
+
const fromDescriptor = Object.getOwnPropertyDescriptor(from2, property);
|
|
8901
8901
|
if (!canCopyProperty(toDescriptor, fromDescriptor) && ignoreNonConfigurable) {
|
|
8902
8902
|
return;
|
|
8903
8903
|
}
|
|
@@ -8906,8 +8906,8 @@ var copyProperty = (to, from, property, ignoreNonConfigurable) => {
|
|
|
8906
8906
|
var canCopyProperty = function(toDescriptor, fromDescriptor) {
|
|
8907
8907
|
return toDescriptor === void 0 || toDescriptor.configurable || toDescriptor.writable === fromDescriptor.writable && toDescriptor.enumerable === fromDescriptor.enumerable && toDescriptor.configurable === fromDescriptor.configurable && (toDescriptor.writable || toDescriptor.value === fromDescriptor.value);
|
|
8908
8908
|
};
|
|
8909
|
-
var changePrototype = (to,
|
|
8910
|
-
const fromPrototype = Object.getPrototypeOf(
|
|
8909
|
+
var changePrototype = (to, from2) => {
|
|
8910
|
+
const fromPrototype = Object.getPrototypeOf(from2);
|
|
8911
8911
|
if (fromPrototype === Object.getPrototypeOf(to)) {
|
|
8912
8912
|
return;
|
|
8913
8913
|
}
|
|
@@ -8917,20 +8917,20 @@ var wrappedToString = (withName, fromBody) => `/* Wrapped ${withName}*/
|
|
|
8917
8917
|
${fromBody}`;
|
|
8918
8918
|
var toStringDescriptor = Object.getOwnPropertyDescriptor(Function.prototype, "toString");
|
|
8919
8919
|
var toStringName = Object.getOwnPropertyDescriptor(Function.prototype.toString, "name");
|
|
8920
|
-
var changeToString = (to,
|
|
8920
|
+
var changeToString = (to, from2, name) => {
|
|
8921
8921
|
const withName = name === "" ? "" : `with ${name.trim()}() `;
|
|
8922
|
-
const newToString = wrappedToString.bind(null, withName,
|
|
8922
|
+
const newToString = wrappedToString.bind(null, withName, from2.toString());
|
|
8923
8923
|
Object.defineProperty(newToString, "name", toStringName);
|
|
8924
8924
|
const { writable, enumerable, configurable } = toStringDescriptor;
|
|
8925
8925
|
Object.defineProperty(to, "toString", { value: newToString, writable, enumerable, configurable });
|
|
8926
8926
|
};
|
|
8927
|
-
function mimicFunction(to,
|
|
8927
|
+
function mimicFunction(to, from2, { ignoreNonConfigurable = false } = {}) {
|
|
8928
8928
|
const { name } = to;
|
|
8929
|
-
for (const property of Reflect.ownKeys(
|
|
8930
|
-
copyProperty(to,
|
|
8929
|
+
for (const property of Reflect.ownKeys(from2)) {
|
|
8930
|
+
copyProperty(to, from2, property, ignoreNonConfigurable);
|
|
8931
8931
|
}
|
|
8932
|
-
changePrototype(to,
|
|
8933
|
-
changeToString(to,
|
|
8932
|
+
changePrototype(to, from2);
|
|
8933
|
+
changeToString(to, from2, name);
|
|
8934
8934
|
return to;
|
|
8935
8935
|
}
|
|
8936
8936
|
|
|
@@ -15624,11 +15624,20 @@ function buildStateMachineModelMutations(modelPath, machines) {
|
|
|
15624
15624
|
return mutations;
|
|
15625
15625
|
}
|
|
15626
15626
|
function buildMachineTypes(classSummary, machine) {
|
|
15627
|
+
const stateGlossary = machine.states.map((state) => {
|
|
15628
|
+
const label = state.label && state.label !== state.name ? state.label : null;
|
|
15629
|
+
const meaning = [label, state.description].filter(Boolean).join(" \u2014 ");
|
|
15630
|
+
const finalMarker = state.isFinal ? " Final state." : "";
|
|
15631
|
+
return `${state.name}${meaning ? `: ${meaning}` : "."}${finalMarker}`;
|
|
15632
|
+
});
|
|
15627
15633
|
return [
|
|
15628
15634
|
{
|
|
15629
15635
|
kind: "union",
|
|
15630
15636
|
name: stateTypeName(classSummary.name, machine.name),
|
|
15631
|
-
docs: [
|
|
15637
|
+
docs: [
|
|
15638
|
+
`Allowed states for ${classSummary.name}.${machine.name}.`,
|
|
15639
|
+
...stateGlossary
|
|
15640
|
+
],
|
|
15632
15641
|
members: machine.states.map((state) => state.name)
|
|
15633
15642
|
},
|
|
15634
15643
|
{
|
|
@@ -15976,7 +15985,7 @@ var stateMachineMetamodelPackage = defineMetamodelPackage({
|
|
|
15976
15985
|
},
|
|
15977
15986
|
add_transition: async (value, {
|
|
15978
15987
|
name,
|
|
15979
|
-
from,
|
|
15988
|
+
from: from2,
|
|
15980
15989
|
to,
|
|
15981
15990
|
label,
|
|
15982
15991
|
description,
|
|
@@ -15991,7 +16000,7 @@ var stateMachineMetamodelPackage = defineMetamodelPackage({
|
|
|
15991
16000
|
value.target.add_state_machine_transition(
|
|
15992
16001
|
value.name,
|
|
15993
16002
|
name,
|
|
15994
|
-
|
|
16003
|
+
from2,
|
|
15995
16004
|
to,
|
|
15996
16005
|
{
|
|
15997
16006
|
label,
|
|
@@ -16814,7 +16823,7 @@ ${effectMetamodelTable}
|
|
|
16814
16823
|
| \`enqueueRecordImport\`, \`listRecordImports\`, \`getRecordImport\`, \`getRecordImportSummary\`, \u2026 | **Async** bulk import (worker queue + aggregate progress). Prefer when loads are huge, returning an \`importId\` is enough up front, and background processing is acceptable. |
|
|
16815
16824
|
| \`graphql(query, variables?)\` | **GraphQL** \u2014 see dedicated subsection below. |
|
|
16816
16825
|
| \`defineRelationship\`, \`getRelationships\`, \`attach\`, \`detach\`, \`listRelated\` | Imperative relationship operations (same ideas as manifest \`defineRelationship\`). |
|
|
16817
|
-
| \`sessions.list()\`, \`sessions.create()\`, \`sessions.connect()\`, \`sessions.reopen()\`, \`sessions.close()\` |
|
|
16826
|
+
| \`sessions.list({ status?, sessionScope?, limit?, offset? })\`, \`sessions.create({ sessionScope? })\`, \`sessions.connect()\`, \`sessions.reopen()\`, \`sessions.close()\` | Scoped, bounded session history and lifecycle for this environment. |
|
|
16818
16827
|
|
|
16819
16828
|
### \`Session\` (live runtime connection)
|
|
16820
16829
|
|
|
@@ -16862,7 +16871,7 @@ Use \`environment.graphql(query, variables?)\` when you need **query/mutation ac
|
|
|
16862
16871
|
| \`granular simulate\` | Open simulator in browser. |
|
|
16863
16872
|
| \`granular simulate --print-url\` | Print a deep-linkable simulator URL without opening the browser. |
|
|
16864
16873
|
| \`granular connect test --json\` | Verify auth and environment connectivity with a real session. |
|
|
16865
|
-
| \`granular session create/list/heap/doc --json\` | Create, enumerate, and inspect real session state. |
|
|
16874
|
+
| \`granular session create/list/heap/doc --json\` | Create, enumerate, and inspect real session state. \`session list\` defaults to 25 rows; use \`--session-scope\`, \`--subject-id\`, \`--limit\`, and \`--offset\` for deterministic paging. |
|
|
16866
16875
|
| \`granular graphql --query '...' --json\` | Run a GraphQL query or mutation against the live graph. |
|
|
16867
16876
|
| \`granular effects list/diff --json\` | Inspect declared versus live ready effects. |
|
|
16868
16877
|
| \`granular job run --file ./job.ts --json\` | Execute a real runtime job from the terminal or CI. |
|
|
@@ -17542,8 +17551,8 @@ Use this for command execution, environment setup, and shipping flows.
|
|
|
17542
17551
|
| \`granular graphql --query '...' --json\` | Query the live graph through the environment GraphQL API |
|
|
17543
17552
|
| \`granular effects list --json\` | Inspect declared and live effects for an environment |
|
|
17544
17553
|
| \`granular effects diff --json\` | Compare declared effects to live ready handlers |
|
|
17545
|
-
| \`granular session create --json\` | Create a fresh session for an environment |
|
|
17546
|
-
| \`granular session list --json\` | List
|
|
17554
|
+
| \`granular session create --session-scope <scope> --json\` | Create a fresh, application-scoped session for an environment |
|
|
17555
|
+
| \`granular session list --session-scope <scope> --limit 25 --offset 0 --json\` | List one bounded page of indexed sessions |
|
|
17547
17556
|
| \`granular session heap --json\` | Inspect session heap |
|
|
17548
17557
|
| \`granular session doc --json\` | Inspect the Automerge-backed session document |
|
|
17549
17558
|
| \`granular job run --file ./job.ts\` | Execute a real job against the ontology runtime |
|
|
@@ -17626,8 +17635,8 @@ Use this for runtime debugging after the ontology builds but behavior does not m
|
|
|
17626
17635
|
|
|
17627
17636
|
| Goal | Preferred path |
|
|
17628
17637
|
| --- | --- |
|
|
17629
|
-
| Create or rotate a session | \`granular session create --json\` |
|
|
17630
|
-
| List known sessions | \`granular session list --json\` |
|
|
17638
|
+
| Create or rotate a session | \`granular session create --session-scope <scope> --json\` |
|
|
17639
|
+
| List known sessions | \`granular session list --session-scope <scope> --limit 25 --offset 0 --json\` |
|
|
17631
17640
|
| Inspect heap | \`granular session heap --json\` |
|
|
17632
17641
|
| Inspect full document | \`granular session doc --json\` |
|
|
17633
17642
|
| Verify connectivity | \`granular connect test\` |
|
|
@@ -18938,7 +18947,7 @@ async function deployCommand(options = {}) {
|
|
|
18938
18947
|
]);
|
|
18939
18948
|
const devTag = tags.find((tag2) => tag2.name === "dev");
|
|
18940
18949
|
const prodTag = tags.find((tag2) => tag2.name === "prod");
|
|
18941
|
-
const existingVersion = versions.find(
|
|
18950
|
+
const existingVersion = options.releaseKey ? null : versions.find(
|
|
18942
18951
|
(version2) => version2.manifestDigest === uploadedManifest.digest
|
|
18943
18952
|
) || null;
|
|
18944
18953
|
const existingVersionId = existingVersion?.buildId || null;
|
|
@@ -18956,19 +18965,27 @@ async function deployCommand(options = {}) {
|
|
|
18956
18965
|
} else {
|
|
18957
18966
|
const version2 = await api.createVersion(
|
|
18958
18967
|
config.sandboxId,
|
|
18959
|
-
uploadedManifest.manifestId
|
|
18960
|
-
|
|
18961
|
-
const startTime = Date.now();
|
|
18962
|
-
building.text = ` Running build for version... ${brand.muted(version2.buildId)}`;
|
|
18963
|
-
completed = await api.waitForVersionBuild(version2.buildId, (status) => {
|
|
18964
|
-
const elapsed = Math.round((Date.now() - startTime) / 1e3);
|
|
18965
|
-
building.text = ` Running build for version... ${brand.muted(`${status} (${elapsed}s)`)}`;
|
|
18966
|
-
});
|
|
18967
|
-
totalTime = Math.round((Date.now() - startTime) / 1e3);
|
|
18968
|
-
deployedToDev = true;
|
|
18969
|
-
building.succeed(
|
|
18970
|
-
` Dev now points to ${brand.secondary(completed.buildId)} (${totalTime}s)`
|
|
18968
|
+
uploadedManifest.manifestId,
|
|
18969
|
+
options.releaseKey
|
|
18971
18970
|
);
|
|
18971
|
+
if (version2.createdNewVersion === false && version2.status === "completed") {
|
|
18972
|
+
completed = version2;
|
|
18973
|
+
building.succeed(
|
|
18974
|
+
` Reused ${brand.secondary(version2.buildId)}; the release key is unchanged.`
|
|
18975
|
+
);
|
|
18976
|
+
} else {
|
|
18977
|
+
const startTime = Date.now();
|
|
18978
|
+
building.text = ` Running build for version... ${brand.muted(version2.buildId)}`;
|
|
18979
|
+
completed = await api.waitForVersionBuild(version2.buildId, (status) => {
|
|
18980
|
+
const elapsed = Math.round((Date.now() - startTime) / 1e3);
|
|
18981
|
+
building.text = ` Running build for version... ${brand.muted(`${status} (${elapsed}s)`)}`;
|
|
18982
|
+
});
|
|
18983
|
+
totalTime = Math.round((Date.now() - startTime) / 1e3);
|
|
18984
|
+
deployedToDev = true;
|
|
18985
|
+
building.succeed(
|
|
18986
|
+
` Dev now points to ${brand.secondary(completed.buildId)} (${totalTime}s)`
|
|
18987
|
+
);
|
|
18988
|
+
}
|
|
18972
18989
|
}
|
|
18973
18990
|
if (!completed) {
|
|
18974
18991
|
throw new Error("Could not resolve the current ontology version.");
|
|
@@ -18999,6 +19016,7 @@ async function deployCommand(options = {}) {
|
|
|
18999
19016
|
Release: options.prod ? deployedToDev ? "dev and prod now point to this version" : "prod promoted to the version already on dev" : "dev updated to this version",
|
|
19000
19017
|
"Agent doc": "GRANULAR_SANDBOX.md"
|
|
19001
19018
|
});
|
|
19019
|
+
console.log(`GRANULAR_RELEASE_CHANGED=${deployedToDev ? "true" : "false"}`);
|
|
19002
19020
|
console.log();
|
|
19003
19021
|
if (options.prod) {
|
|
19004
19022
|
info(
|
|
@@ -19560,16 +19578,37 @@ var WSClient = class {
|
|
|
19560
19578
|
tokenRefreshTimer = null;
|
|
19561
19579
|
isExplicitlyDisconnected = false;
|
|
19562
19580
|
reconnectAttempts = 0;
|
|
19581
|
+
connectPromise = null;
|
|
19582
|
+
connectionEpoch = 0;
|
|
19583
|
+
cancelConnectAttempt = null;
|
|
19563
19584
|
options;
|
|
19564
19585
|
constructor(options) {
|
|
19565
19586
|
this.options = options;
|
|
19566
19587
|
this.url = options.url;
|
|
19567
19588
|
this.sessionId = options.sessionId;
|
|
19568
19589
|
this.token = options.token;
|
|
19590
|
+
if (options.initialDocumentSnapshot) {
|
|
19591
|
+
this.seedDocumentSnapshot(options.initialDocumentSnapshot);
|
|
19592
|
+
}
|
|
19569
19593
|
}
|
|
19570
19594
|
get currentSessionId() {
|
|
19571
19595
|
return this.sessionId;
|
|
19572
19596
|
}
|
|
19597
|
+
seedDocumentSnapshot(document) {
|
|
19598
|
+
if (!document || typeof document !== "object" || Array.isArray(document)) {
|
|
19599
|
+
return;
|
|
19600
|
+
}
|
|
19601
|
+
try {
|
|
19602
|
+
this.doc = document instanceof Uint8Array ? Automerge__namespace.load(document) : Automerge__namespace.from(document);
|
|
19603
|
+
this.syncState = Automerge__namespace.initSyncState();
|
|
19604
|
+
this.emit("sync", this.doc);
|
|
19605
|
+
} catch (error2) {
|
|
19606
|
+
console.warn("[Granular] Failed to seed cached session document", error2);
|
|
19607
|
+
}
|
|
19608
|
+
}
|
|
19609
|
+
saveDocumentSnapshot() {
|
|
19610
|
+
return Automerge__namespace.save(this.doc);
|
|
19611
|
+
}
|
|
19573
19612
|
clearTokenRefreshTimer() {
|
|
19574
19613
|
if (this.tokenRefreshTimer) {
|
|
19575
19614
|
clearTimeout(this.tokenRefreshTimer);
|
|
@@ -19679,8 +19718,23 @@ var WSClient = class {
|
|
|
19679
19718
|
* Connect to the WebSocket server
|
|
19680
19719
|
* @returns {Promise<void>} Resolves when connection is open
|
|
19681
19720
|
*/
|
|
19682
|
-
async connect() {
|
|
19721
|
+
async connect(options = {}) {
|
|
19722
|
+
if (this.ws?.readyState === READY_STATE_OPEN) return;
|
|
19723
|
+
if (this.connectPromise) return this.connectPromise;
|
|
19724
|
+
const connectPromise = this.connectAttempt(options.signal);
|
|
19725
|
+
this.connectPromise = connectPromise;
|
|
19726
|
+
try {
|
|
19727
|
+
await connectPromise;
|
|
19728
|
+
} finally {
|
|
19729
|
+
if (this.connectPromise === connectPromise) {
|
|
19730
|
+
this.connectPromise = null;
|
|
19731
|
+
}
|
|
19732
|
+
}
|
|
19733
|
+
}
|
|
19734
|
+
async connectAttempt(signal) {
|
|
19735
|
+
if (signal?.aborted) throw new Error("WebSocket connect aborted");
|
|
19683
19736
|
const token = await this.resolveTokenForConnect();
|
|
19737
|
+
if (signal?.aborted) throw new Error("WebSocket connect aborted");
|
|
19684
19738
|
this.isExplicitlyDisconnected = false;
|
|
19685
19739
|
this.scheduleTokenRefresh();
|
|
19686
19740
|
if (this.reconnectTimer) {
|
|
@@ -19692,7 +19746,7 @@ var WSClient = class {
|
|
|
19692
19746
|
try {
|
|
19693
19747
|
const wsModule = await import('ws');
|
|
19694
19748
|
WebSocketClass = wsModule.default || wsModule;
|
|
19695
|
-
} catch
|
|
19749
|
+
} catch {
|
|
19696
19750
|
}
|
|
19697
19751
|
}
|
|
19698
19752
|
if (!WebSocketClass) {
|
|
@@ -19700,83 +19754,97 @@ var WSClient = class {
|
|
|
19700
19754
|
'No WebSocket implementation found. If using Node.js, please install "ws" and pass the constructor to the SDK options: { WebSocketCtor: WebSocket }.'
|
|
19701
19755
|
);
|
|
19702
19756
|
}
|
|
19757
|
+
const epoch = ++this.connectionEpoch;
|
|
19758
|
+
const wsUrl = new URL(this.url);
|
|
19759
|
+
wsUrl.searchParams.set("sessionId", this.sessionId);
|
|
19760
|
+
wsUrl.searchParams.set("token", token);
|
|
19761
|
+
const socket = new WebSocketClass(wsUrl.toString());
|
|
19762
|
+
this.ws = socket;
|
|
19703
19763
|
return new Promise((resolve2, reject) => {
|
|
19704
|
-
|
|
19705
|
-
|
|
19706
|
-
|
|
19707
|
-
|
|
19708
|
-
|
|
19709
|
-
if (
|
|
19710
|
-
|
|
19711
|
-
|
|
19712
|
-
|
|
19713
|
-
|
|
19714
|
-
|
|
19715
|
-
this.reconnectTimer = null;
|
|
19716
|
-
}
|
|
19717
|
-
this.reconnectAttempts = 0;
|
|
19718
|
-
this.emit("open", {});
|
|
19719
|
-
resolve2();
|
|
19720
|
-
});
|
|
19721
|
-
socket.on("message", (data) => {
|
|
19722
|
-
try {
|
|
19723
|
-
const message = JSON.parse(data.toString());
|
|
19724
|
-
this.handleMessage(message);
|
|
19725
|
-
} catch (error2) {
|
|
19726
|
-
console.error("[Granular] Failed to parse message:", error2);
|
|
19727
|
-
}
|
|
19728
|
-
});
|
|
19729
|
-
socket.on("error", (error2) => {
|
|
19730
|
-
this.emit("error", error2);
|
|
19731
|
-
if (socket.readyState !== READY_STATE_OPEN) {
|
|
19732
|
-
reject(error2);
|
|
19733
|
-
}
|
|
19734
|
-
});
|
|
19735
|
-
socket.on("close", (code, reason) => {
|
|
19736
|
-
this.handleDisconnect({
|
|
19737
|
-
code,
|
|
19738
|
-
reason: this.normalizeReason(reason),
|
|
19739
|
-
// ws does not provide wasClean on Node-style close callback
|
|
19740
|
-
wasClean: code === 1e3
|
|
19741
|
-
});
|
|
19742
|
-
});
|
|
19764
|
+
let settled = false;
|
|
19765
|
+
const isCurrent = () => this.connectionEpoch === epoch && this.ws === socket;
|
|
19766
|
+
const finish = (error2) => {
|
|
19767
|
+
if (settled) return;
|
|
19768
|
+
settled = true;
|
|
19769
|
+
if (this.cancelConnectAttempt === handleAbort) {
|
|
19770
|
+
this.cancelConnectAttempt = null;
|
|
19771
|
+
}
|
|
19772
|
+
signal?.removeEventListener("abort", handleAbort);
|
|
19773
|
+
if (error2) {
|
|
19774
|
+
reject(error2 instanceof Error ? error2 : new Error(String(error2)));
|
|
19743
19775
|
} else {
|
|
19744
|
-
|
|
19745
|
-
if (this.reconnectTimer) {
|
|
19746
|
-
clearTimeout(this.reconnectTimer);
|
|
19747
|
-
this.reconnectTimer = null;
|
|
19748
|
-
}
|
|
19749
|
-
this.reconnectAttempts = 0;
|
|
19750
|
-
this.emit("open", {});
|
|
19751
|
-
resolve2();
|
|
19752
|
-
};
|
|
19753
|
-
this.ws.onmessage = (event) => {
|
|
19754
|
-
try {
|
|
19755
|
-
const data = event.data;
|
|
19756
|
-
const message = JSON.parse(data.toString());
|
|
19757
|
-
this.handleMessage(message);
|
|
19758
|
-
} catch (error2) {
|
|
19759
|
-
console.error("[Granular] Failed to parse message:", error2);
|
|
19760
|
-
}
|
|
19761
|
-
};
|
|
19762
|
-
this.ws.onerror = (event) => {
|
|
19763
|
-
const error2 = new Error("WebSocket error");
|
|
19764
|
-
error2.event = event;
|
|
19765
|
-
this.emit("error", error2);
|
|
19766
|
-
if (this.ws?.readyState !== READY_STATE_OPEN) {
|
|
19767
|
-
reject(error2);
|
|
19768
|
-
}
|
|
19769
|
-
};
|
|
19770
|
-
this.ws.onclose = (event) => {
|
|
19771
|
-
this.handleDisconnect({
|
|
19772
|
-
code: event.code,
|
|
19773
|
-
reason: event.reason,
|
|
19774
|
-
wasClean: event.wasClean
|
|
19775
|
-
});
|
|
19776
|
-
};
|
|
19776
|
+
resolve2();
|
|
19777
19777
|
}
|
|
19778
|
-
}
|
|
19779
|
-
|
|
19778
|
+
};
|
|
19779
|
+
const closeStaleSocket = () => {
|
|
19780
|
+
try {
|
|
19781
|
+
socket.close(1e3, "Stale connection attempt");
|
|
19782
|
+
} catch {
|
|
19783
|
+
}
|
|
19784
|
+
};
|
|
19785
|
+
const handleAbort = () => {
|
|
19786
|
+
if (isCurrent()) {
|
|
19787
|
+
this.connectionEpoch += 1;
|
|
19788
|
+
this.ws = null;
|
|
19789
|
+
}
|
|
19790
|
+
closeStaleSocket();
|
|
19791
|
+
finish(new Error("WebSocket connect aborted"));
|
|
19792
|
+
};
|
|
19793
|
+
this.cancelConnectAttempt = handleAbort;
|
|
19794
|
+
const handleOpen = () => {
|
|
19795
|
+
if (!isCurrent()) {
|
|
19796
|
+
closeStaleSocket();
|
|
19797
|
+
return;
|
|
19798
|
+
}
|
|
19799
|
+
this.reconnectAttempts = 0;
|
|
19800
|
+
this.emit("open", {});
|
|
19801
|
+
finish();
|
|
19802
|
+
};
|
|
19803
|
+
const handleMessage = (data) => {
|
|
19804
|
+
if (!isCurrent()) return;
|
|
19805
|
+
try {
|
|
19806
|
+
const text = typeof data === "string" ? data : data && typeof data === "object" && "toString" in data ? String(data.toString()) : "";
|
|
19807
|
+
this.handleMessage(JSON.parse(text));
|
|
19808
|
+
} catch (error2) {
|
|
19809
|
+
console.error("[Granular] Failed to parse message:", error2);
|
|
19810
|
+
}
|
|
19811
|
+
};
|
|
19812
|
+
const handleError = (error2) => {
|
|
19813
|
+
if (!isCurrent()) return;
|
|
19814
|
+
const typedError = error2 instanceof Error ? error2 : new Error("WebSocket error");
|
|
19815
|
+
this.emit("error", typedError);
|
|
19816
|
+
if (socket.readyState !== READY_STATE_OPEN) finish(typedError);
|
|
19817
|
+
};
|
|
19818
|
+
const handleClose = (close) => {
|
|
19819
|
+
if (!isCurrent()) return;
|
|
19820
|
+
if (!settled) {
|
|
19821
|
+
finish(
|
|
19822
|
+
new Error(
|
|
19823
|
+
`WebSocket closed before ready${close.code ? ` (code=${close.code})` : ""}`
|
|
19824
|
+
)
|
|
19825
|
+
);
|
|
19826
|
+
}
|
|
19827
|
+
this.handleDisconnect({
|
|
19828
|
+
code: close.code,
|
|
19829
|
+
reason: this.normalizeReason(close.reason),
|
|
19830
|
+
wasClean: close.wasClean
|
|
19831
|
+
});
|
|
19832
|
+
};
|
|
19833
|
+
signal?.addEventListener("abort", handleAbort, { once: true });
|
|
19834
|
+
const nodeSocket = socket;
|
|
19835
|
+
if (typeof nodeSocket.on === "function") {
|
|
19836
|
+
nodeSocket.on("open", handleOpen);
|
|
19837
|
+
nodeSocket.on("message", handleMessage);
|
|
19838
|
+
nodeSocket.on("error", handleError);
|
|
19839
|
+
nodeSocket.on(
|
|
19840
|
+
"close",
|
|
19841
|
+
(code, reason) => handleClose({ code, reason, wasClean: code === 1e3 })
|
|
19842
|
+
);
|
|
19843
|
+
} else {
|
|
19844
|
+
socket.onopen = handleOpen;
|
|
19845
|
+
socket.onmessage = (event) => handleMessage(event.data);
|
|
19846
|
+
socket.onerror = handleError;
|
|
19847
|
+
socket.onclose = (event) => handleClose(event);
|
|
19780
19848
|
}
|
|
19781
19849
|
});
|
|
19782
19850
|
}
|
|
@@ -19794,9 +19862,58 @@ var WSClient = class {
|
|
|
19794
19862
|
return void 0;
|
|
19795
19863
|
}
|
|
19796
19864
|
rejectPending(error2) {
|
|
19797
|
-
this.messageQueue.forEach((pending) =>
|
|
19865
|
+
this.messageQueue.forEach((pending) => {
|
|
19866
|
+
clearTimeout(pending.timeout);
|
|
19867
|
+
pending.reject(error2);
|
|
19868
|
+
});
|
|
19798
19869
|
this.messageQueue = [];
|
|
19799
19870
|
}
|
|
19871
|
+
emitReconnectErrorMessage(error2) {
|
|
19872
|
+
const reconnectInfo = {
|
|
19873
|
+
error: error2,
|
|
19874
|
+
sessionId: this.sessionId,
|
|
19875
|
+
timestamp: Date.now()
|
|
19876
|
+
};
|
|
19877
|
+
this.emit("reconnect_error", reconnectInfo);
|
|
19878
|
+
if (this.options.onReconnectError) {
|
|
19879
|
+
try {
|
|
19880
|
+
this.options.onReconnectError(reconnectInfo);
|
|
19881
|
+
} catch (callbackError) {
|
|
19882
|
+
console.error(
|
|
19883
|
+
"[Granular] onReconnectError callback failed:",
|
|
19884
|
+
callbackError
|
|
19885
|
+
);
|
|
19886
|
+
}
|
|
19887
|
+
}
|
|
19888
|
+
}
|
|
19889
|
+
scheduleReconnectAttempt() {
|
|
19890
|
+
if (this.isExplicitlyDisconnected || this.reconnectTimer) return null;
|
|
19891
|
+
const baseReconnectDelayMs = typeof this.options.reconnectDelayMs === "number" && Number.isFinite(this.options.reconnectDelayMs) && this.options.reconnectDelayMs > 0 ? this.options.reconnectDelayMs : DEFAULT_RECONNECT_DELAY_MS;
|
|
19892
|
+
const maxReconnectAttempts = typeof this.options.maxReconnectAttempts === "number" && Number.isFinite(this.options.maxReconnectAttempts) && this.options.maxReconnectAttempts >= 0 ? Math.floor(this.options.maxReconnectAttempts) : DEFAULT_MAX_RECONNECT_ATTEMPTS;
|
|
19893
|
+
if (this.reconnectAttempts >= maxReconnectAttempts) {
|
|
19894
|
+
this.emitReconnectErrorMessage(
|
|
19895
|
+
`WebSocket reconnect attempts exhausted after ${maxReconnectAttempts} attempt(s).`
|
|
19896
|
+
);
|
|
19897
|
+
return null;
|
|
19898
|
+
}
|
|
19899
|
+
this.reconnectAttempts += 1;
|
|
19900
|
+
const reconnectDelayMs = Math.min(
|
|
19901
|
+
3e4,
|
|
19902
|
+
baseReconnectDelayMs * 2 ** Math.max(0, this.reconnectAttempts - 1)
|
|
19903
|
+
);
|
|
19904
|
+
this.reconnectTimer = setTimeout(() => {
|
|
19905
|
+
this.reconnectTimer = null;
|
|
19906
|
+
console.log("[Granular] Attempting reconnect...");
|
|
19907
|
+
this.connect().catch((error2) => {
|
|
19908
|
+
console.error("[Granular] Reconnect failed:", error2);
|
|
19909
|
+
this.emitReconnectErrorMessage(
|
|
19910
|
+
error2 instanceof Error ? error2.message : String(error2)
|
|
19911
|
+
);
|
|
19912
|
+
this.scheduleReconnectAttempt();
|
|
19913
|
+
});
|
|
19914
|
+
}, reconnectDelayMs);
|
|
19915
|
+
return reconnectDelayMs;
|
|
19916
|
+
}
|
|
19800
19917
|
buildDisconnectError(info2) {
|
|
19801
19918
|
const details = [
|
|
19802
19919
|
info2.code !== void 0 ? `code=${info2.code}` : void 0,
|
|
@@ -19806,8 +19923,6 @@ var WSClient = class {
|
|
|
19806
19923
|
return new Error(`WebSocket disconnected${suffix}`);
|
|
19807
19924
|
}
|
|
19808
19925
|
handleDisconnect(close = {}) {
|
|
19809
|
-
const baseReconnectDelayMs = typeof this.options.reconnectDelayMs === "number" && Number.isFinite(this.options.reconnectDelayMs) && this.options.reconnectDelayMs > 0 ? this.options.reconnectDelayMs : DEFAULT_RECONNECT_DELAY_MS;
|
|
19810
|
-
const maxReconnectAttempts = typeof this.options.maxReconnectAttempts === "number" && Number.isFinite(this.options.maxReconnectAttempts) && this.options.maxReconnectAttempts >= 0 ? Math.floor(this.options.maxReconnectAttempts) : DEFAULT_MAX_RECONNECT_ATTEMPTS;
|
|
19811
19926
|
const unexpected = !this.isExplicitlyDisconnected;
|
|
19812
19927
|
const info2 = {
|
|
19813
19928
|
code: close.code,
|
|
@@ -19827,32 +19942,9 @@ var WSClient = class {
|
|
|
19827
19942
|
const disconnectError = this.buildDisconnectError(info2);
|
|
19828
19943
|
this.rejectPending(disconnectError);
|
|
19829
19944
|
this.emit("disconnect", info2);
|
|
19830
|
-
|
|
19831
|
-
|
|
19832
|
-
|
|
19833
|
-
sessionId: this.sessionId,
|
|
19834
|
-
timestamp: Date.now()
|
|
19835
|
-
};
|
|
19836
|
-
this.emit("reconnect_error", reconnectInfo);
|
|
19837
|
-
if (this.options.onReconnectError) {
|
|
19838
|
-
try {
|
|
19839
|
-
this.options.onReconnectError(reconnectInfo);
|
|
19840
|
-
} catch (callbackError) {
|
|
19841
|
-
console.error(
|
|
19842
|
-
"[Granular] onReconnectError callback failed:",
|
|
19843
|
-
callbackError
|
|
19844
|
-
);
|
|
19845
|
-
}
|
|
19846
|
-
}
|
|
19847
|
-
return;
|
|
19848
|
-
}
|
|
19849
|
-
this.reconnectAttempts += 1;
|
|
19850
|
-
const reconnectDelayMs = Math.min(
|
|
19851
|
-
3e4,
|
|
19852
|
-
baseReconnectDelayMs * 2 ** Math.max(0, this.reconnectAttempts - 1)
|
|
19853
|
-
);
|
|
19854
|
-
info2.reconnectScheduled = true;
|
|
19855
|
-
info2.reconnectDelayMs = reconnectDelayMs;
|
|
19945
|
+
const reconnectDelayMs = this.scheduleReconnectAttempt();
|
|
19946
|
+
info2.reconnectScheduled = reconnectDelayMs !== null;
|
|
19947
|
+
if (reconnectDelayMs !== null) info2.reconnectDelayMs = reconnectDelayMs;
|
|
19856
19948
|
if (this.options.onUnexpectedClose) {
|
|
19857
19949
|
try {
|
|
19858
19950
|
this.options.onUnexpectedClose(info2);
|
|
@@ -19863,28 +19955,6 @@ var WSClient = class {
|
|
|
19863
19955
|
);
|
|
19864
19956
|
}
|
|
19865
19957
|
}
|
|
19866
|
-
this.reconnectTimer = setTimeout(() => {
|
|
19867
|
-
console.log("[Granular] Attempting reconnect...");
|
|
19868
|
-
this.connect().catch((error2) => {
|
|
19869
|
-
console.error("[Granular] Reconnect failed:", error2);
|
|
19870
|
-
const reconnectInfo = {
|
|
19871
|
-
error: error2 instanceof Error ? error2.message : String(error2),
|
|
19872
|
-
sessionId: this.sessionId,
|
|
19873
|
-
timestamp: Date.now()
|
|
19874
|
-
};
|
|
19875
|
-
this.emit("reconnect_error", reconnectInfo);
|
|
19876
|
-
if (this.options.onReconnectError) {
|
|
19877
|
-
try {
|
|
19878
|
-
this.options.onReconnectError(reconnectInfo);
|
|
19879
|
-
} catch (callbackError) {
|
|
19880
|
-
console.error(
|
|
19881
|
-
"[Granular] onReconnectError callback failed:",
|
|
19882
|
-
callbackError
|
|
19883
|
-
);
|
|
19884
|
-
}
|
|
19885
|
-
}
|
|
19886
|
-
});
|
|
19887
|
-
}, reconnectDelayMs);
|
|
19888
19958
|
}
|
|
19889
19959
|
}
|
|
19890
19960
|
handleMessage(message) {
|
|
@@ -19995,6 +20065,7 @@ var WSClient = class {
|
|
|
19995
20065
|
const response = message;
|
|
19996
20066
|
const pending = this.messageQueue.find((q) => q.id === response.id);
|
|
19997
20067
|
if (pending) {
|
|
20068
|
+
clearTimeout(pending.timeout);
|
|
19998
20069
|
if (response.type === "rpc_error") {
|
|
19999
20070
|
pending.reject(
|
|
20000
20071
|
new Error(
|
|
@@ -20040,16 +20111,22 @@ var WSClient = class {
|
|
|
20040
20111
|
id
|
|
20041
20112
|
};
|
|
20042
20113
|
return new Promise((resolve2, reject) => {
|
|
20043
|
-
this.messageQueue.push({ resolve: resolve2, reject, id });
|
|
20044
|
-
this.ws.send(JSON.stringify(request));
|
|
20045
20114
|
const timeoutMs = rpcTimeoutMsForMethod(method);
|
|
20046
|
-
setTimeout(() => {
|
|
20115
|
+
const timeout = setTimeout(() => {
|
|
20047
20116
|
const pending = this.messageQueue.find((q) => q.id === id);
|
|
20048
20117
|
if (pending) {
|
|
20049
20118
|
this.messageQueue = this.messageQueue.filter((q) => q.id !== id);
|
|
20050
20119
|
reject(new Error(`RPC timeout: ${method}`));
|
|
20051
20120
|
}
|
|
20052
20121
|
}, timeoutMs);
|
|
20122
|
+
this.messageQueue.push({ resolve: resolve2, reject, id, timeout });
|
|
20123
|
+
try {
|
|
20124
|
+
this.ws.send(JSON.stringify(request));
|
|
20125
|
+
} catch (error2) {
|
|
20126
|
+
clearTimeout(timeout);
|
|
20127
|
+
this.messageQueue = this.messageQueue.filter((q) => q.id !== id);
|
|
20128
|
+
reject(error2 instanceof Error ? error2 : new Error(String(error2)));
|
|
20129
|
+
}
|
|
20053
20130
|
});
|
|
20054
20131
|
}
|
|
20055
20132
|
async handleIncomingRpc(request) {
|
|
@@ -20135,15 +20212,18 @@ var WSClient = class {
|
|
|
20135
20212
|
/**
|
|
20136
20213
|
* Disconnect the WebSocket and clear state
|
|
20137
20214
|
*/
|
|
20138
|
-
disconnect() {
|
|
20215
|
+
disconnect(options = {}) {
|
|
20139
20216
|
this.isExplicitlyDisconnected = true;
|
|
20217
|
+
this.cancelConnectAttempt?.();
|
|
20218
|
+
this.cancelConnectAttempt = null;
|
|
20219
|
+
this.connectionEpoch += 1;
|
|
20140
20220
|
if (this.reconnectTimer) {
|
|
20141
20221
|
clearTimeout(this.reconnectTimer);
|
|
20142
20222
|
this.reconnectTimer = null;
|
|
20143
20223
|
}
|
|
20144
20224
|
this.clearTokenRefreshTimer();
|
|
20145
20225
|
if (this.ws) {
|
|
20146
|
-
this.ws.close(1e3, "Client disconnect");
|
|
20226
|
+
this.ws.close(1e3, options.reason || "Client disconnect");
|
|
20147
20227
|
this.ws = null;
|
|
20148
20228
|
}
|
|
20149
20229
|
this.rejectPending(new Error("Client explicitly disconnected"));
|
|
@@ -20239,8 +20319,12 @@ function normalizePrompt(rawValue) {
|
|
|
20239
20319
|
const source = promptRecord || raw;
|
|
20240
20320
|
const id = typeof source.id === "string" ? source.id : typeof raw.id === "string" ? raw.id : typeof raw.promptId === "string" ? raw.promptId : "";
|
|
20241
20321
|
if (!id) return null;
|
|
20322
|
+
const jobId = typeof source.jobId === "string" && source.jobId.trim() ? source.jobId.trim() : typeof raw.jobId === "string" && raw.jobId.trim() ? raw.jobId.trim() : void 0;
|
|
20323
|
+
const turnId = typeof source.turnId === "string" && source.turnId.trim() ? source.turnId.trim() : typeof raw.turnId === "string" && raw.turnId.trim() ? raw.turnId.trim() : void 0;
|
|
20242
20324
|
return {
|
|
20243
20325
|
id,
|
|
20326
|
+
...jobId ? { jobId } : {},
|
|
20327
|
+
...turnId ? { turnId } : {},
|
|
20244
20328
|
type: normalizePromptType(source === raw ? raw : { ...raw, ...source }),
|
|
20245
20329
|
title: typeof source.title === "string" ? source.title : "Input required",
|
|
20246
20330
|
message: typeof source.message === "string" ? source.message : "",
|
|
@@ -20327,6 +20411,9 @@ var Session = class {
|
|
|
20327
20411
|
this.initialQuota = options.initialQuota || null;
|
|
20328
20412
|
this.setupEventHandlers();
|
|
20329
20413
|
this.setupToolInvokeHandler();
|
|
20414
|
+
this.currentDomainRevision = this.extractDomainRevisionFromDoc(
|
|
20415
|
+
this.client.doc
|
|
20416
|
+
);
|
|
20330
20417
|
}
|
|
20331
20418
|
extractDomainRevisionFromDoc(doc) {
|
|
20332
20419
|
const domain = doc?.domain;
|
|
@@ -21232,6 +21319,7 @@ function normalizeJobAgentMessageEnvelope(data) {
|
|
|
21232
21319
|
}
|
|
21233
21320
|
return {
|
|
21234
21321
|
jobId: d.jobId,
|
|
21322
|
+
...typeof d.turnId === "string" && d.turnId.trim() ? { turnId: d.turnId.trim() } : {},
|
|
21235
21323
|
message: {
|
|
21236
21324
|
messageId: d.messageId,
|
|
21237
21325
|
kind: d.kind === "artifacts" ? "artifacts" : "text",
|
|
@@ -21890,9 +21978,14 @@ function normalizeShowRefs(value) {
|
|
|
21890
21978
|
variableNames: normalizeRefs(record.variableNames),
|
|
21891
21979
|
fileIds: normalizeRefs(record.fileIds),
|
|
21892
21980
|
sessionArtifactIds: normalizeRefs(record.sessionArtifactIds),
|
|
21893
|
-
actionSuggestions: normalizeActionSuggestions(record.actionSuggestions)
|
|
21981
|
+
actionSuggestions: normalizeActionSuggestions(record.actionSuggestions),
|
|
21982
|
+
tables: Array.isArray(record.tables) ? record.tables.filter(
|
|
21983
|
+
(table2) => Boolean(
|
|
21984
|
+
table2 && typeof table2 === "object" && !Array.isArray(table2) && Array.isArray(table2.columns) && Array.isArray(table2.rows)
|
|
21985
|
+
)
|
|
21986
|
+
) : void 0
|
|
21894
21987
|
};
|
|
21895
|
-
return show.entryPaths || show.listNames || show.variableNames || show.fileIds || show.sessionArtifactIds || show.actionSuggestions ? show : void 0;
|
|
21988
|
+
return show.entryPaths || show.listNames || show.variableNames || show.fileIds || show.sessionArtifactIds || show.actionSuggestions || show.tables ? show : void 0;
|
|
21896
21989
|
}
|
|
21897
21990
|
function normalizeActionSuggestions(value) {
|
|
21898
21991
|
if (!Array.isArray(value)) return void 0;
|
|
@@ -21914,6 +22007,76 @@ function normalizeActionSuggestions(value) {
|
|
|
21914
22007
|
}
|
|
21915
22008
|
return suggestions.length ? suggestions : void 0;
|
|
21916
22009
|
}
|
|
22010
|
+
var TRANSCRIPT_MESSAGE_PART_LIMIT = 128;
|
|
22011
|
+
var TRANSCRIPT_MESSAGE_PART_TEXT_LIMIT = 2e5;
|
|
22012
|
+
var TRANSCRIPT_MESSAGE_PART_ACTION_LABEL_LIMIT = 1e3;
|
|
22013
|
+
var TRANSCRIPT_MESSAGE_ACTION_LIMIT = 64;
|
|
22014
|
+
function normalizeConversationMessageActions(value) {
|
|
22015
|
+
if (!Array.isArray(value) || value.length === 0) return void 0;
|
|
22016
|
+
const actions = [];
|
|
22017
|
+
for (const item of value.slice(0, TRANSCRIPT_MESSAGE_ACTION_LIMIT)) {
|
|
22018
|
+
const record = asRecord3(item);
|
|
22019
|
+
const kind = record?.kind;
|
|
22020
|
+
const label = trimString(record?.label ?? record?.title);
|
|
22021
|
+
const status = record?.status;
|
|
22022
|
+
if (kind !== "frontend" && kind !== "backend" && kind !== "system" || !label || label.length > TRANSCRIPT_MESSAGE_PART_ACTION_LABEL_LIMIT) {
|
|
22023
|
+
continue;
|
|
22024
|
+
}
|
|
22025
|
+
actions.push({
|
|
22026
|
+
kind,
|
|
22027
|
+
label,
|
|
22028
|
+
...status === "done" || status === "queued" || status === "failed" ? { status } : {}
|
|
22029
|
+
});
|
|
22030
|
+
}
|
|
22031
|
+
return actions.length ? actions : void 0;
|
|
22032
|
+
}
|
|
22033
|
+
function normalizeConversationMessageParts(value, canonicalContent, canonicalActions) {
|
|
22034
|
+
if (!Array.isArray(value) || value.length === 0 || value.length > TRANSCRIPT_MESSAGE_PART_LIMIT) {
|
|
22035
|
+
return void 0;
|
|
22036
|
+
}
|
|
22037
|
+
const parts = [];
|
|
22038
|
+
const canonicalActionsById = new Map(
|
|
22039
|
+
(canonicalActions || []).map((action) => [
|
|
22040
|
+
`${action.kind}:${action.label}`,
|
|
22041
|
+
action
|
|
22042
|
+
])
|
|
22043
|
+
);
|
|
22044
|
+
const seenActionIds = /* @__PURE__ */ new Set();
|
|
22045
|
+
let textLength = 0;
|
|
22046
|
+
for (const item of value) {
|
|
22047
|
+
const record = asRecord3(item);
|
|
22048
|
+
if (!record) return void 0;
|
|
22049
|
+
if (record.type === "text") {
|
|
22050
|
+
if (typeof record.text !== "string" || record.text.length === 0) {
|
|
22051
|
+
return void 0;
|
|
22052
|
+
}
|
|
22053
|
+
textLength += record.text.length;
|
|
22054
|
+
if (textLength > TRANSCRIPT_MESSAGE_PART_TEXT_LIMIT) return void 0;
|
|
22055
|
+
parts.push({ type: "text", text: record.text });
|
|
22056
|
+
continue;
|
|
22057
|
+
}
|
|
22058
|
+
if (record.type !== "action") return void 0;
|
|
22059
|
+
const action = asRecord3(record.action);
|
|
22060
|
+
const kind = action?.kind;
|
|
22061
|
+
const label = trimString(action?.label);
|
|
22062
|
+
if (kind !== "frontend" && kind !== "backend" && kind !== "system" || !label || label.length > TRANSCRIPT_MESSAGE_PART_ACTION_LABEL_LIMIT) {
|
|
22063
|
+
return void 0;
|
|
22064
|
+
}
|
|
22065
|
+
const actionId = `${kind}:${label}`;
|
|
22066
|
+
const canonicalAction = canonicalActionsById.get(actionId);
|
|
22067
|
+
if (!canonicalAction) return void 0;
|
|
22068
|
+
if (seenActionIds.has(actionId)) continue;
|
|
22069
|
+
seenActionIds.add(actionId);
|
|
22070
|
+
parts.push({
|
|
22071
|
+
type: "action",
|
|
22072
|
+
action: canonicalAction
|
|
22073
|
+
});
|
|
22074
|
+
}
|
|
22075
|
+
const orderedText = parts.filter(
|
|
22076
|
+
(part) => part.type === "text"
|
|
22077
|
+
).map((part) => part.text).join("");
|
|
22078
|
+
return orderedText === canonicalContent ? parts : void 0;
|
|
22079
|
+
}
|
|
21917
22080
|
function stringifyTranscriptValue(value, fallback2 = "") {
|
|
21918
22081
|
if (typeof value === "string") {
|
|
21919
22082
|
return value.trim() || fallback2;
|
|
@@ -22072,10 +22235,12 @@ function normalizeConversationMessage(raw, artifactsById) {
|
|
|
22072
22235
|
const content = trimString(
|
|
22073
22236
|
record.content ?? record.reply ?? record.message ?? record.text
|
|
22074
22237
|
);
|
|
22238
|
+
const actions = role === "assistant" ? normalizeConversationMessageActions(record.actions) : void 0;
|
|
22239
|
+
const parts = role === "assistant" ? normalizeConversationMessageParts(record.parts, content, actions) : void 0;
|
|
22075
22240
|
const show = normalizeShowRefs(record.show);
|
|
22076
22241
|
const id = asString(record.id) || crypto.randomUUID();
|
|
22077
22242
|
const timestamp = asNumber(record.timestamp) || asNumber(record.ts) || 0;
|
|
22078
|
-
if (!content && !show) return null;
|
|
22243
|
+
if (!content && !show && !actions?.length) return null;
|
|
22079
22244
|
const artifactHistory = buildArtifactHistory(show, artifactsById);
|
|
22080
22245
|
const historyContent = role === "assistant" ? content && artifactHistory ? `[Assistant reply]
|
|
22081
22246
|
${content}
|
|
@@ -22090,6 +22255,8 @@ ${content}` : artifactHistory : void 0;
|
|
|
22090
22255
|
jobId: asString(record.jobId),
|
|
22091
22256
|
promptId: asString(record.promptId),
|
|
22092
22257
|
show,
|
|
22258
|
+
actions,
|
|
22259
|
+
parts,
|
|
22093
22260
|
historyContent,
|
|
22094
22261
|
source: "conversation"
|
|
22095
22262
|
};
|
|
@@ -22738,7 +22905,12 @@ async function recordOpenAIUsageSpend(options) {
|
|
|
22738
22905
|
const metadata = {
|
|
22739
22906
|
...options.metadata || {},
|
|
22740
22907
|
...options.usage.rawUsage !== void 0 ? { openaiUsage: options.usage.rawUsage } : {},
|
|
22741
|
-
usageContext: context
|
|
22908
|
+
usageContext: context,
|
|
22909
|
+
pricingContextTier: options.usage.pricingContextTier,
|
|
22910
|
+
cacheWritePricePerMillionMicros: options.usage.cacheWritePricePerMillionMicros,
|
|
22911
|
+
cacheWriteTokens: options.usage.cacheWriteTokens,
|
|
22912
|
+
cacheWriteCostMicros: options.usage.cacheWriteCostMicros,
|
|
22913
|
+
longContextThresholdTokens: options.usage.longContextThresholdTokens
|
|
22742
22914
|
};
|
|
22743
22915
|
const response = await fetch(
|
|
22744
22916
|
`${toGranularHttpBase(options.apiUrl)}/control/spend/events`,
|
|
@@ -22809,6 +22981,18 @@ function buildEffectMetamodelMutations(toolPath, spec) {
|
|
|
22809
22981
|
}
|
|
22810
22982
|
|
|
22811
22983
|
// src/client.ts
|
|
22984
|
+
var DEFAULT_CONVERSATION_SESSION_LIST_LIMIT = 100;
|
|
22985
|
+
var MAX_CONVERSATION_SESSION_LIST_LIMIT = 500;
|
|
22986
|
+
var MAX_CONVERSATION_SESSION_LIST_OFFSET = 1e5;
|
|
22987
|
+
function boundedSessionListInteger(value, name, fallback2, minimum, maximum) {
|
|
22988
|
+
if (value === void 0) return fallback2;
|
|
22989
|
+
if (!Number.isInteger(value) || value < minimum || value > maximum) {
|
|
22990
|
+
throw new RangeError(
|
|
22991
|
+
`Session list ${name} must be an integer between ${minimum} and ${maximum}.`
|
|
22992
|
+
);
|
|
22993
|
+
}
|
|
22994
|
+
return value;
|
|
22995
|
+
}
|
|
22812
22996
|
var STANDARD_MODULES_OPERATIONS = [
|
|
22813
22997
|
{
|
|
22814
22998
|
create: "entity",
|
|
@@ -23026,7 +23210,8 @@ function normalizeEnvironmentSetupSummary(setup) {
|
|
|
23026
23210
|
environmentId: String(setup.environmentId || ""),
|
|
23027
23211
|
sandboxId: String(setup.sandboxId || ""),
|
|
23028
23212
|
subjectId: String(setup.subjectId || ""),
|
|
23029
|
-
triggerReason: setup.triggerReason === "fresh_after_version_update" ? "fresh_after_version_update" : "new_environment",
|
|
23213
|
+
triggerReason: setup.triggerReason === "fresh_after_version_update" ? "fresh_after_version_update" : setup.triggerReason === "explicit_reset" ? "explicit_reset" : "new_environment",
|
|
23214
|
+
operationKey: typeof setup.operationKey === "string" ? setup.operationKey : null,
|
|
23030
23215
|
lifecycleStatus: setup.lifecycleStatus === "completed" || setup.lifecycleStatus === "failed" ? setup.lifecycleStatus : "running",
|
|
23031
23216
|
stage: typeof setup.stage === "string" ? setup.stage : null,
|
|
23032
23217
|
totalObjectsToImport: Number(setup.totalObjectsToImport || 0),
|
|
@@ -23147,7 +23332,7 @@ var Environment = class _Environment {
|
|
|
23147
23332
|
}
|
|
23148
23333
|
get sessions() {
|
|
23149
23334
|
return {
|
|
23150
|
-
list: async (options) => this.listSessions(options
|
|
23335
|
+
list: async (options = {}) => this.listSessions(options),
|
|
23151
23336
|
create: async (options) => this.createSession(options),
|
|
23152
23337
|
connect: async (sessionId, options) => this.connectSession(sessionId, options),
|
|
23153
23338
|
reopen: async (sessionId, options) => this.reopenSession(sessionId, options),
|
|
@@ -23282,17 +23467,12 @@ var Environment = class _Environment {
|
|
|
23282
23467
|
*/
|
|
23283
23468
|
async disconnect() {
|
|
23284
23469
|
}
|
|
23285
|
-
async listSessions(
|
|
23286
|
-
|
|
23287
|
-
|
|
23288
|
-
|
|
23289
|
-
|
|
23290
|
-
|
|
23291
|
-
return [...active, ...closed].sort(
|
|
23292
|
-
(left, right) => Date.parse(right.lastSeenAt) - Date.parse(left.lastSeenAt)
|
|
23293
|
-
);
|
|
23294
|
-
}
|
|
23295
|
-
return status === "closed" ? this.granular.listClosedSessions({ environmentId: this.environmentId }) : this.granular.listOpenSessions({ environmentId: this.environmentId });
|
|
23470
|
+
async listSessions(optionsOrStatus = {}) {
|
|
23471
|
+
const options = typeof optionsOrStatus === "string" ? { status: optionsOrStatus } : optionsOrStatus;
|
|
23472
|
+
return this.granular.listSessions({
|
|
23473
|
+
...options,
|
|
23474
|
+
environmentId: this.environmentId
|
|
23475
|
+
});
|
|
23296
23476
|
}
|
|
23297
23477
|
async getUserEnvironmentState(options = {}) {
|
|
23298
23478
|
return this.granular.getUserEnvironmentState({
|
|
@@ -23310,6 +23490,7 @@ var Environment = class _Environment {
|
|
|
23310
23490
|
return this.granular.createSession({
|
|
23311
23491
|
environmentId: this.environmentId,
|
|
23312
23492
|
clientId: options?.clientId,
|
|
23493
|
+
sessionScope: options?.sessionScope,
|
|
23313
23494
|
initialHeap: options?.initialHeap
|
|
23314
23495
|
});
|
|
23315
23496
|
}
|
|
@@ -24312,6 +24493,7 @@ var Environment = class _Environment {
|
|
|
24312
24493
|
records: recordsToImport,
|
|
24313
24494
|
batchSize: options.batchSize,
|
|
24314
24495
|
setupRunId: options.setupRunId,
|
|
24496
|
+
operationKey: options.operationKey,
|
|
24315
24497
|
writeMode: options.writeMode
|
|
24316
24498
|
})
|
|
24317
24499
|
}
|
|
@@ -24872,7 +25054,7 @@ var EnvironmentSession = class extends Session {
|
|
|
24872
25054
|
* Close only the socket transport without sending `client.goodbye`.
|
|
24873
25055
|
*/
|
|
24874
25056
|
disconnectTransport() {
|
|
24875
|
-
this.client.disconnect();
|
|
25057
|
+
this.client.disconnect({ reason: "Transport detach" });
|
|
24876
25058
|
}
|
|
24877
25059
|
/**
|
|
24878
25060
|
* Backwards-compatible alias for `disconnect()`.
|
|
@@ -25116,6 +25298,107 @@ var Granular = class _Granular {
|
|
|
25116
25298
|
await this.maybeRunEnvironmentImporter(resolved, environment);
|
|
25117
25299
|
return environment;
|
|
25118
25300
|
}
|
|
25301
|
+
/**
|
|
25302
|
+
* Read the active environment selected by Granular for an already-recorded
|
|
25303
|
+
* external user. This is intentionally read-only: browser/login code must
|
|
25304
|
+
* not create subjects or environments as a side effect.
|
|
25305
|
+
*/
|
|
25306
|
+
async getActiveEnvironmentForUser(options) {
|
|
25307
|
+
const sandboxId = options.sandboxId.trim();
|
|
25308
|
+
const tagName = options.tag.trim();
|
|
25309
|
+
const userId = options.userId.trim();
|
|
25310
|
+
if (!sandboxId || !tagName || !userId) {
|
|
25311
|
+
throw new Error(
|
|
25312
|
+
"getActiveEnvironmentForUser() requires sandboxId, tag, and userId."
|
|
25313
|
+
);
|
|
25314
|
+
}
|
|
25315
|
+
const subjects = await this.request(
|
|
25316
|
+
`/control/subjects?identityId=${encodeURIComponent(userId)}`
|
|
25317
|
+
);
|
|
25318
|
+
const subject = (subjects.items || []).find(
|
|
25319
|
+
(item) => item.identityId === userId || item.userId === userId
|
|
25320
|
+
);
|
|
25321
|
+
if (!subject?.subjectId && !subject?.granularId) {
|
|
25322
|
+
return null;
|
|
25323
|
+
}
|
|
25324
|
+
const subjectId = subject.subjectId || subject.granularId;
|
|
25325
|
+
const tags = await this.request(
|
|
25326
|
+
`/control/sandboxes/${encodeURIComponent(sandboxId)}/tags`
|
|
25327
|
+
);
|
|
25328
|
+
const tag2 = (tags.items || []).find(
|
|
25329
|
+
(item) => item?.name === tagName
|
|
25330
|
+
);
|
|
25331
|
+
if (!tag2) return null;
|
|
25332
|
+
const query = new URLSearchParams({
|
|
25333
|
+
tagId: tag2.tagId,
|
|
25334
|
+
slot: options.slot?.trim() || "default"
|
|
25335
|
+
});
|
|
25336
|
+
try {
|
|
25337
|
+
const payload = await this.request(
|
|
25338
|
+
`/control/sandboxes/${encodeURIComponent(sandboxId)}/subjects/${encodeURIComponent(subjectId)}/active-environment?${query.toString()}`
|
|
25339
|
+
);
|
|
25340
|
+
return payload.environment ? this.bindEnvironmentHandle(
|
|
25341
|
+
normalizeEnvironmentData(payload.environment)
|
|
25342
|
+
) : null;
|
|
25343
|
+
} catch (error2) {
|
|
25344
|
+
const message = error2 instanceof Error ? error2.message : String(error2);
|
|
25345
|
+
if (message.includes("404") || message.includes("not found")) {
|
|
25346
|
+
return null;
|
|
25347
|
+
}
|
|
25348
|
+
throw error2;
|
|
25349
|
+
}
|
|
25350
|
+
}
|
|
25351
|
+
/**
|
|
25352
|
+
* Register one reviewed, pre-existing environment as the active workspace
|
|
25353
|
+
* for an external user. This is for a controlled migration only: it does
|
|
25354
|
+
* not create an environment and it does not run an importer.
|
|
25355
|
+
*/
|
|
25356
|
+
async adoptEnvironmentForUser(options) {
|
|
25357
|
+
const sandboxId = options.sandboxId.trim();
|
|
25358
|
+
const tagName = options.tag.trim();
|
|
25359
|
+
const userId = options.userId.trim();
|
|
25360
|
+
const environmentId = options.environmentId.trim();
|
|
25361
|
+
if (!sandboxId || !tagName || !userId || !environmentId) {
|
|
25362
|
+
throw new Error(
|
|
25363
|
+
"adoptEnvironmentForUser() requires sandboxId, tag, userId, and environmentId."
|
|
25364
|
+
);
|
|
25365
|
+
}
|
|
25366
|
+
const subjects = await this.request(
|
|
25367
|
+
`/control/subjects?identityId=${encodeURIComponent(userId)}`
|
|
25368
|
+
);
|
|
25369
|
+
const subject = (subjects.items || []).find(
|
|
25370
|
+
(item) => item.identityId === userId || item.userId === userId
|
|
25371
|
+
);
|
|
25372
|
+
if (!subject?.subjectId && !subject?.granularId) {
|
|
25373
|
+
throw new Error(`No Granular subject exists for user ${userId}.`);
|
|
25374
|
+
}
|
|
25375
|
+
const tags = await this.request(`/control/sandboxes/${encodeURIComponent(sandboxId)}/tags`);
|
|
25376
|
+
const tag2 = (tags.items || []).find(
|
|
25377
|
+
(item) => item?.name === tagName
|
|
25378
|
+
);
|
|
25379
|
+
if (!tag2) {
|
|
25380
|
+
throw new Error(`Tag ${tagName} was not found in sandbox ${sandboxId}.`);
|
|
25381
|
+
}
|
|
25382
|
+
const payload = await this.request(
|
|
25383
|
+
"/control/environment-activations/adopt",
|
|
25384
|
+
{
|
|
25385
|
+
method: "POST",
|
|
25386
|
+
body: JSON.stringify({
|
|
25387
|
+
environmentId,
|
|
25388
|
+
subjectId: subject.subjectId || subject.granularId,
|
|
25389
|
+
tagId: tag2.tagId,
|
|
25390
|
+
slot: options.slot?.trim() || "default",
|
|
25391
|
+
confirmExistingData: true
|
|
25392
|
+
})
|
|
25393
|
+
}
|
|
25394
|
+
);
|
|
25395
|
+
if (!payload.environment) {
|
|
25396
|
+
throw new Error("Granular did not return the adopted environment.");
|
|
25397
|
+
}
|
|
25398
|
+
return this.bindEnvironmentHandle(
|
|
25399
|
+
normalizeEnvironmentData(payload.environment)
|
|
25400
|
+
);
|
|
25401
|
+
}
|
|
25119
25402
|
/**
|
|
25120
25403
|
* Deprecated compatibility alias for `openEnvironment()`.
|
|
25121
25404
|
*
|
|
@@ -25147,7 +25430,9 @@ var Granular = class _Granular {
|
|
|
25147
25430
|
requestedOntology,
|
|
25148
25431
|
sandboxId: environmentData.sandboxId,
|
|
25149
25432
|
subjectId: environmentData.subjectId,
|
|
25150
|
-
|
|
25433
|
+
externalUserId: environmentData.subjectId,
|
|
25434
|
+
setupTriggerReason: options.reason || "new_environment",
|
|
25435
|
+
setupOperationKey: options.operationKey
|
|
25151
25436
|
},
|
|
25152
25437
|
environment
|
|
25153
25438
|
);
|
|
@@ -25159,20 +25444,17 @@ var Granular = class _Granular {
|
|
|
25159
25444
|
}
|
|
25160
25445
|
return tag2;
|
|
25161
25446
|
}
|
|
25162
|
-
buildManagedEnvironmentName(tag2, versionId) {
|
|
25163
|
-
|
|
25447
|
+
buildManagedEnvironmentName(tag2, versionId, resetKey) {
|
|
25448
|
+
if (!resetKey) {
|
|
25449
|
+
return `__sdk__${tag2}__${versionId}__tracked`;
|
|
25450
|
+
}
|
|
25451
|
+
const safeResetKey = resetKey.replace(/[^a-zA-Z0-9_-]/g, "_").slice(0, 80);
|
|
25452
|
+
return `__sdk__${tag2}__${versionId}__reset__${safeResetKey}`;
|
|
25164
25453
|
}
|
|
25165
25454
|
isManagedEnvironmentName(environment, tagName) {
|
|
25166
25455
|
const name = environment.environment || environment.envName || "";
|
|
25167
25456
|
return name.startsWith(`__sdk__${tagName}__`);
|
|
25168
25457
|
}
|
|
25169
|
-
isPinnedToVersion(environment, versionId) {
|
|
25170
|
-
return environment.buildPolicy.mode === "pinned" && (environment.versionId === versionId || environment.buildPolicy.versionId === versionId || environment.buildPolicy.buildId === versionId);
|
|
25171
|
-
}
|
|
25172
|
-
matchesTagTrackedEnvironment(environment, tagName, tagId) {
|
|
25173
|
-
const environmentTagName = environment.tag?.name || environment.buildPolicy.tagName || null;
|
|
25174
|
-
return environment.tagId === tagId || environmentTagName === tagName || environment.environment === tagName || environment.envName === tagName || environment.environment === this.buildManagedEnvironmentName(tagName, environment.versionId) || environment.envName === this.buildManagedEnvironmentName(tagName, environment.versionId);
|
|
25175
|
-
}
|
|
25176
25458
|
sortEnvironmentsByRecency(environments) {
|
|
25177
25459
|
return [...environments].sort(
|
|
25178
25460
|
(left, right) => right.updatedAt - left.updatedAt
|
|
@@ -25222,61 +25504,187 @@ var Granular = class _Granular {
|
|
|
25222
25504
|
`Tag "${tagName}" does not currently point to a build/version.`
|
|
25223
25505
|
);
|
|
25224
25506
|
}
|
|
25507
|
+
const slot = options.slot?.trim() || "default";
|
|
25508
|
+
const resetKey = options.resetKey?.trim() || void 0;
|
|
25509
|
+
const resolveActive = async (operationKey) => {
|
|
25510
|
+
const query = new URLSearchParams({ tagId: tag2.tagId, slot });
|
|
25511
|
+
if (operationKey) query.set("operationKey", operationKey);
|
|
25512
|
+
try {
|
|
25513
|
+
const payload = await this.request(
|
|
25514
|
+
`/control/sandboxes/${encodeURIComponent(sandbox.sandboxId)}/subjects/${encodeURIComponent(user.granularId)}/active-environment?${query.toString()}`
|
|
25515
|
+
);
|
|
25516
|
+
return payload.environment ? normalizeEnvironmentData(payload.environment) : null;
|
|
25517
|
+
} catch (error2) {
|
|
25518
|
+
const message = error2 instanceof Error ? error2.message : String(error2);
|
|
25519
|
+
if (message.includes("404") || message.includes("not found")) {
|
|
25520
|
+
return null;
|
|
25521
|
+
}
|
|
25522
|
+
throw error2;
|
|
25523
|
+
}
|
|
25524
|
+
};
|
|
25525
|
+
const activate = async (environment2) => {
|
|
25526
|
+
const payload = await this.request(
|
|
25527
|
+
"/control/environment-activations",
|
|
25528
|
+
{
|
|
25529
|
+
method: "POST",
|
|
25530
|
+
body: JSON.stringify({
|
|
25531
|
+
environmentId: environment2.environmentId,
|
|
25532
|
+
tagId: tag2.tagId,
|
|
25533
|
+
slot,
|
|
25534
|
+
operationKey: resetKey,
|
|
25535
|
+
operation: resetKey ? "explicit_reset" : void 0
|
|
25536
|
+
})
|
|
25537
|
+
}
|
|
25538
|
+
);
|
|
25539
|
+
return normalizeEnvironmentData(payload.environment);
|
|
25540
|
+
};
|
|
25541
|
+
if (resetKey) {
|
|
25542
|
+
const resetEnvironment = await resolveActive(resetKey);
|
|
25543
|
+
if (resetEnvironment) {
|
|
25544
|
+
return {
|
|
25545
|
+
environment: resetEnvironment,
|
|
25546
|
+
requestedOntology: ontology,
|
|
25547
|
+
sandboxId: sandbox.sandboxId,
|
|
25548
|
+
subjectId: user.granularId,
|
|
25549
|
+
externalUserId: user.userId,
|
|
25550
|
+
// Retrying an explicit reset must also resume its durable setup run.
|
|
25551
|
+
// Otherwise a Container crash after queue submission would leave a
|
|
25552
|
+
// valid environment permanently marked as "running".
|
|
25553
|
+
setupTriggerReason: "explicit_reset",
|
|
25554
|
+
setupOperationKey: resetKey
|
|
25555
|
+
};
|
|
25556
|
+
}
|
|
25557
|
+
} else {
|
|
25558
|
+
const active = await resolveActive();
|
|
25559
|
+
if (active && (active.versionId === targetVersionId || options.createFreshIfOutdated !== true)) {
|
|
25560
|
+
return {
|
|
25561
|
+
environment: active,
|
|
25562
|
+
requestedOntology: ontology,
|
|
25563
|
+
sandboxId: sandbox.sandboxId,
|
|
25564
|
+
subjectId: user.granularId,
|
|
25565
|
+
externalUserId: user.userId
|
|
25566
|
+
};
|
|
25567
|
+
}
|
|
25568
|
+
}
|
|
25225
25569
|
const allEnvironments = await this.environments.list(sandbox.sandboxId);
|
|
25226
25570
|
const userEnvironments = allEnvironments.filter(
|
|
25227
|
-
(
|
|
25571
|
+
(environment2) => environment2.subjectId === user.granularId
|
|
25228
25572
|
);
|
|
25229
25573
|
const currentMatches = this.sortEnvironmentsByRecency(
|
|
25230
25574
|
userEnvironments.filter(
|
|
25231
|
-
(
|
|
25575
|
+
(environment2) => environment2.tagId === tag2.tagId && environment2.versionId === targetVersionId
|
|
25232
25576
|
)
|
|
25233
25577
|
);
|
|
25234
|
-
if (currentMatches.length > 0) {
|
|
25578
|
+
if (!resetKey && currentMatches.length > 0) {
|
|
25579
|
+
const environment2 = await activate(currentMatches[0]);
|
|
25235
25580
|
return {
|
|
25236
|
-
environment:
|
|
25581
|
+
environment: environment2,
|
|
25237
25582
|
requestedOntology: ontology,
|
|
25238
25583
|
sandboxId: sandbox.sandboxId,
|
|
25239
|
-
subjectId: user.granularId
|
|
25584
|
+
subjectId: user.granularId,
|
|
25585
|
+
externalUserId: user.userId
|
|
25240
25586
|
};
|
|
25241
25587
|
}
|
|
25242
25588
|
const outdatedMatches = this.sortEnvironmentsByRecency(
|
|
25243
|
-
userEnvironments.filter(
|
|
25244
|
-
(environment) => this.matchesTagTrackedEnvironment(environment, tagName, tag2.tagId)
|
|
25245
|
-
)
|
|
25589
|
+
userEnvironments.filter((environment2) => environment2.tagId === tag2.tagId)
|
|
25246
25590
|
);
|
|
25247
25591
|
if (outdatedMatches.length > 0 && options.createFreshIfOutdated !== true) {
|
|
25592
|
+
const environment2 = await activate(outdatedMatches[0]);
|
|
25248
25593
|
return {
|
|
25249
|
-
environment:
|
|
25594
|
+
environment: environment2,
|
|
25250
25595
|
requestedOntology: ontology,
|
|
25251
25596
|
sandboxId: sandbox.sandboxId,
|
|
25252
|
-
subjectId: user.granularId
|
|
25597
|
+
subjectId: user.granularId,
|
|
25598
|
+
externalUserId: user.userId
|
|
25253
25599
|
};
|
|
25254
25600
|
}
|
|
25601
|
+
const created = await this.environments.create(sandbox.sandboxId, {
|
|
25602
|
+
subjectId: user.granularId,
|
|
25603
|
+
environment: this.buildManagedEnvironmentName(
|
|
25604
|
+
tagName,
|
|
25605
|
+
targetVersionId,
|
|
25606
|
+
resetKey
|
|
25607
|
+
),
|
|
25608
|
+
tagId: tag2.tagId,
|
|
25609
|
+
permissionProfileId: null
|
|
25610
|
+
});
|
|
25611
|
+
const environment = await activate(created);
|
|
25255
25612
|
return {
|
|
25256
|
-
environment
|
|
25257
|
-
subjectId: user.granularId,
|
|
25258
|
-
environment: this.buildManagedEnvironmentName(tagName, targetVersionId),
|
|
25259
|
-
tagId: tag2.tagId,
|
|
25260
|
-
versionId: targetVersionId,
|
|
25261
|
-
permissionProfileId: null
|
|
25262
|
-
}),
|
|
25613
|
+
environment,
|
|
25263
25614
|
requestedOntology: ontology,
|
|
25264
25615
|
sandboxId: sandbox.sandboxId,
|
|
25265
25616
|
subjectId: user.granularId,
|
|
25266
|
-
|
|
25617
|
+
externalUserId: user.userId,
|
|
25618
|
+
setupTriggerReason: resetKey ? "explicit_reset" : outdatedMatches.length > 0 ? "fresh_after_version_update" : "new_environment",
|
|
25619
|
+
setupOperationKey: resetKey
|
|
25267
25620
|
};
|
|
25268
25621
|
}
|
|
25269
25622
|
/**
|
|
25270
|
-
* List
|
|
25623
|
+
* List indexed sessions using ownership filters and bounded pagination.
|
|
25624
|
+
*/
|
|
25625
|
+
async listSessions(options) {
|
|
25626
|
+
const environmentId = options.environmentId?.trim();
|
|
25627
|
+
const sandboxId = options.sandboxId?.trim();
|
|
25628
|
+
const subjectId = options.subjectId?.trim();
|
|
25629
|
+
if (!environmentId && !sandboxId && !subjectId) {
|
|
25630
|
+
throw new Error(
|
|
25631
|
+
"listSessions() requires environmentId, sandboxId, or subjectId so history cannot be scanned accidentally."
|
|
25632
|
+
);
|
|
25633
|
+
}
|
|
25634
|
+
const status = options.status || "active";
|
|
25635
|
+
const allowedStatuses = /* @__PURE__ */ new Set([
|
|
25636
|
+
"active",
|
|
25637
|
+
"closed",
|
|
25638
|
+
"expired",
|
|
25639
|
+
"failed",
|
|
25640
|
+
"timeout",
|
|
25641
|
+
"all"
|
|
25642
|
+
]);
|
|
25643
|
+
if (!allowedStatuses.has(status)) {
|
|
25644
|
+
throw new Error(`Unsupported session status: ${String(status)}`);
|
|
25645
|
+
}
|
|
25646
|
+
const limit = boundedSessionListInteger(
|
|
25647
|
+
options.limit,
|
|
25648
|
+
"limit",
|
|
25649
|
+
DEFAULT_CONVERSATION_SESSION_LIST_LIMIT,
|
|
25650
|
+
1,
|
|
25651
|
+
MAX_CONVERSATION_SESSION_LIST_LIMIT
|
|
25652
|
+
);
|
|
25653
|
+
const offset = boundedSessionListInteger(
|
|
25654
|
+
options.offset,
|
|
25655
|
+
"offset",
|
|
25656
|
+
0,
|
|
25657
|
+
0,
|
|
25658
|
+
MAX_CONVERSATION_SESSION_LIST_OFFSET
|
|
25659
|
+
);
|
|
25660
|
+
const query = new URLSearchParams({
|
|
25661
|
+
limit: String(limit),
|
|
25662
|
+
offset: String(offset)
|
|
25663
|
+
});
|
|
25664
|
+
if (environmentId) query.set("environmentId", environmentId);
|
|
25665
|
+
if (sandboxId) query.set("sandboxId", sandboxId);
|
|
25666
|
+
if (subjectId) query.set("userId", subjectId);
|
|
25667
|
+
if (options.sessionScope?.trim()) {
|
|
25668
|
+
query.set("sessionScope", options.sessionScope.trim());
|
|
25669
|
+
}
|
|
25670
|
+
if (status !== "all") query.set("status", status);
|
|
25671
|
+
const res = await this.request(
|
|
25672
|
+
`/control/sessions?${query.toString()}`
|
|
25673
|
+
);
|
|
25674
|
+
const items = Array.isArray(res.items) ? res.items : [];
|
|
25675
|
+
return items.map((row) => this.normalizeConversationSession(row));
|
|
25676
|
+
}
|
|
25677
|
+
/**
|
|
25678
|
+
* List active (open) sessions for an environment.
|
|
25271
25679
|
*/
|
|
25272
25680
|
async listOpenSessions(filters) {
|
|
25273
|
-
return this.
|
|
25681
|
+
return this.listSessions({ ...filters, status: "active" });
|
|
25274
25682
|
}
|
|
25275
25683
|
/**
|
|
25276
25684
|
* List closed sessions for an environment (conversations that have disconnected).
|
|
25277
25685
|
*/
|
|
25278
25686
|
async listClosedSessions(filters) {
|
|
25279
|
-
return this.
|
|
25687
|
+
return this.listSessions({ ...filters, status: "closed" });
|
|
25280
25688
|
}
|
|
25281
25689
|
async getUserEnvironmentState(options) {
|
|
25282
25690
|
const query = new URLSearchParams({
|
|
@@ -25311,14 +25719,6 @@ var Granular = class _Granular {
|
|
|
25311
25719
|
});
|
|
25312
25720
|
return result.readAtBySessionId || {};
|
|
25313
25721
|
}
|
|
25314
|
-
async listSessionsForEnvironment(environmentId, status) {
|
|
25315
|
-
const query = new URLSearchParams({ environmentId, status });
|
|
25316
|
-
const res = await this.request(
|
|
25317
|
-
`/control/sessions?${query.toString()}`
|
|
25318
|
-
);
|
|
25319
|
-
const items = Array.isArray(res.items) ? res.items : [];
|
|
25320
|
-
return items.map((row) => this.normalizeConversationSession(row));
|
|
25321
|
-
}
|
|
25322
25722
|
normalizeConversationSession(row) {
|
|
25323
25723
|
const sessionId = String(row.sessionId ?? row.session_id ?? "");
|
|
25324
25724
|
const environmentId = String(row.environmentId ?? row.environment_id ?? "");
|
|
@@ -25377,6 +25777,7 @@ var Granular = class _Granular {
|
|
|
25377
25777
|
*/
|
|
25378
25778
|
async createSession(options) {
|
|
25379
25779
|
const clientId = options.clientId || `client_${Date.now()}`;
|
|
25780
|
+
const sessionScope = options.sessionScope?.trim() || void 0;
|
|
25380
25781
|
await this.activateEnvironment(options.environmentId);
|
|
25381
25782
|
const envData = await this.environments.get(options.environmentId);
|
|
25382
25783
|
const environment = this.bindEnvironmentHandle(envData);
|
|
@@ -25385,6 +25786,8 @@ var Granular = class _Granular {
|
|
|
25385
25786
|
body: JSON.stringify({
|
|
25386
25787
|
environmentId: options.environmentId,
|
|
25387
25788
|
clientId,
|
|
25789
|
+
sessionScope,
|
|
25790
|
+
capabilities: sessionScope ? { sessionScope } : void 0,
|
|
25388
25791
|
initialHeap: options.initialHeap
|
|
25389
25792
|
})
|
|
25390
25793
|
});
|
|
@@ -25492,11 +25895,24 @@ var Granular = class _Granular {
|
|
|
25492
25895
|
{
|
|
25493
25896
|
method: "POST",
|
|
25494
25897
|
body: JSON.stringify({
|
|
25495
|
-
triggerReason: resolved.setupTriggerReason
|
|
25898
|
+
triggerReason: resolved.setupTriggerReason,
|
|
25899
|
+
operationKey: resolved.setupOperationKey
|
|
25496
25900
|
})
|
|
25497
25901
|
}
|
|
25498
25902
|
);
|
|
25499
25903
|
const setupRunId = setupRun.setupRunId;
|
|
25904
|
+
let claim = null;
|
|
25905
|
+
for (let attempt = 0; attempt < 3; attempt += 1) {
|
|
25906
|
+
claim = await this.request(
|
|
25907
|
+
`/control/environment-setup-runs/${setupRunId}/importer-claim`,
|
|
25908
|
+
{ method: "POST", body: JSON.stringify({}) }
|
|
25909
|
+
);
|
|
25910
|
+
if (claim.action !== "busy") break;
|
|
25911
|
+
await sleep(Math.min(3e4, Math.max(250, claim.retryAfterMs || 1e3)));
|
|
25912
|
+
}
|
|
25913
|
+
if (!claim) {
|
|
25914
|
+
throw new Error(`Unable to claim environment setup run ${setupRunId}.`);
|
|
25915
|
+
}
|
|
25500
25916
|
const updateSetupRun = async (patch) => {
|
|
25501
25917
|
await this.request(
|
|
25502
25918
|
`/control/environment-setup-runs/${setupRunId}`,
|
|
@@ -25506,10 +25922,26 @@ var Granular = class _Granular {
|
|
|
25506
25922
|
}
|
|
25507
25923
|
);
|
|
25508
25924
|
};
|
|
25925
|
+
if (claim.action === "submitted") {
|
|
25926
|
+
const completedSetupRun = await this.request(
|
|
25927
|
+
`/control/environment-setup-runs/${setupRunId}`,
|
|
25928
|
+
{ method: "PATCH", body: JSON.stringify({ markHookCompleted: true }) }
|
|
25929
|
+
);
|
|
25930
|
+
const refreshedEnvironment = await this.environments.get(
|
|
25931
|
+
environment.environmentId
|
|
25932
|
+
);
|
|
25933
|
+
environment.syncEnvironmentData(refreshedEnvironment);
|
|
25934
|
+
return completedSetupRun;
|
|
25935
|
+
}
|
|
25936
|
+
if (claim.action === "busy" || claim.action === "terminal") {
|
|
25937
|
+
return claim.summary;
|
|
25938
|
+
}
|
|
25939
|
+
let importSequence = 0;
|
|
25509
25940
|
const importerContext = {
|
|
25510
25941
|
environmentId: environment.environmentId,
|
|
25511
25942
|
sandboxId: environment.sandboxId,
|
|
25512
25943
|
subjectId: environment.subjectId,
|
|
25944
|
+
externalUserId: resolved.externalUserId,
|
|
25513
25945
|
reason: resolved.setupTriggerReason,
|
|
25514
25946
|
incrementTotalObjectsToImportCount: async (n) => {
|
|
25515
25947
|
const safeIncrement = Math.max(0, Math.trunc(n));
|
|
@@ -25526,7 +25958,10 @@ var Granular = class _Granular {
|
|
|
25526
25958
|
importRecords: async (records, options) => environment.enqueueRecordImport(records, {
|
|
25527
25959
|
batchSize: options?.batchSize,
|
|
25528
25960
|
writeMode: options?.writeMode,
|
|
25529
|
-
setupRunId
|
|
25961
|
+
setupRunId,
|
|
25962
|
+
// Sequence is deterministic for a retry of one importer hook. It
|
|
25963
|
+
// prevents a Container restart from creating a second queue import.
|
|
25964
|
+
operationKey: `${setupRunId}:import:${importSequence++}`
|
|
25530
25965
|
})
|
|
25531
25966
|
};
|
|
25532
25967
|
try {
|
|
@@ -26706,15 +27141,22 @@ async function resolveEnvironmentData(granular, options) {
|
|
|
26706
27141
|
const ontologyId = await resolveOntologyId(granular, options.ontology);
|
|
26707
27142
|
const environmentName = options.environment ?? "dev";
|
|
26708
27143
|
const environments = await granular.environments.list(ontologyId);
|
|
26709
|
-
const
|
|
26710
|
-
(environment) => matchesEnvironmentName(environment, environmentName)
|
|
27144
|
+
const matchingEnvironments = environments.filter(
|
|
27145
|
+
(environment) => matchesEnvironmentName(environment, environmentName) && (!options.subjectId || environment.subjectId === options.subjectId)
|
|
26711
27146
|
);
|
|
27147
|
+
if (matchingEnvironments.length > 1) {
|
|
27148
|
+
throw new Error(
|
|
27149
|
+
`Environment slot \`${environmentName}\` matches ${matchingEnvironments.length} subject environments. Pass --environment-id or --subject-id so session history cannot resolve to an arbitrary user.`
|
|
27150
|
+
);
|
|
27151
|
+
}
|
|
27152
|
+
const existing = matchingEnvironments[0];
|
|
26712
27153
|
if (existing) {
|
|
26713
27154
|
return existing;
|
|
26714
27155
|
}
|
|
26715
27156
|
if (!options.createIfMissing) {
|
|
27157
|
+
const subjectSuffix = options.subjectId ? ` for subject \`${options.subjectId}\`` : "";
|
|
26716
27158
|
throw new Error(
|
|
26717
|
-
`No environment named \`${environmentName}
|
|
27159
|
+
`No environment named \`${environmentName}\`${subjectSuffix} found for ontology \`${ontologyId}\`. Run \`granular connect test\` or \`granular session create\` first, or pass \`--environment-id\`.`
|
|
26718
27160
|
);
|
|
26719
27161
|
}
|
|
26720
27162
|
const connection = await granular.connect({
|
|
@@ -26725,17 +27167,15 @@ async function resolveEnvironmentData(granular, options) {
|
|
|
26725
27167
|
});
|
|
26726
27168
|
return await granular.environments.get(connection.environmentId);
|
|
26727
27169
|
}
|
|
26728
|
-
async function listSessionsForEnvironment(granular, environmentId,
|
|
26729
|
-
|
|
26730
|
-
|
|
26731
|
-
|
|
26732
|
-
|
|
26733
|
-
|
|
26734
|
-
|
|
26735
|
-
|
|
26736
|
-
|
|
26737
|
-
}
|
|
26738
|
-
return status === "closed" ? granular.listClosedSessions({ environmentId }) : granular.listOpenSessions({ environmentId });
|
|
27170
|
+
async function listSessionsForEnvironment(granular, environmentId, options) {
|
|
27171
|
+
return granular.listSessions({
|
|
27172
|
+
environmentId,
|
|
27173
|
+
status: options.status,
|
|
27174
|
+
sessionScope: options.sessionScope,
|
|
27175
|
+
subjectId: options.subjectId,
|
|
27176
|
+
limit: options.limit,
|
|
27177
|
+
offset: options.offset
|
|
27178
|
+
});
|
|
26739
27179
|
}
|
|
26740
27180
|
async function connectRuntime(options) {
|
|
26741
27181
|
if (options.sessionId) {
|
|
@@ -26848,6 +27288,19 @@ async function connectTestCommand(options) {
|
|
|
26848
27288
|
}
|
|
26849
27289
|
|
|
26850
27290
|
// src/cli/commands/session.ts
|
|
27291
|
+
function parseSessionListInteger(value, name) {
|
|
27292
|
+
const fallback2 = name === "limit" ? 25 : 0;
|
|
27293
|
+
const minimum = name === "limit" ? 1 : 0;
|
|
27294
|
+
const maximum = name === "limit" ? 500 : 1e5;
|
|
27295
|
+
if (value === void 0 || value === "") return fallback2;
|
|
27296
|
+
const parsed = typeof value === "number" ? value : Number.parseInt(value.trim(), 10);
|
|
27297
|
+
if (!Number.isInteger(parsed) || String(parsed) !== String(value).trim() || parsed < minimum || parsed > maximum) {
|
|
27298
|
+
throw new Error(
|
|
27299
|
+
`--${name} must be an integer between ${minimum} and ${maximum}.`
|
|
27300
|
+
);
|
|
27301
|
+
}
|
|
27302
|
+
return parsed;
|
|
27303
|
+
}
|
|
26851
27304
|
function printValue(value, emitJson) {
|
|
26852
27305
|
const json = JSON.stringify(value, null, 2);
|
|
26853
27306
|
if (emitJson) {
|
|
@@ -26932,7 +27385,8 @@ async function sessionCreateCommand(options) {
|
|
|
26932
27385
|
createIfMissing: true
|
|
26933
27386
|
});
|
|
26934
27387
|
const environment = await granular.createSession({
|
|
26935
|
-
environmentId: envData.environmentId
|
|
27388
|
+
environmentId: envData.environmentId,
|
|
27389
|
+
sessionScope: options.sessionScope
|
|
26936
27390
|
});
|
|
26937
27391
|
try {
|
|
26938
27392
|
const payload = {
|
|
@@ -26941,6 +27395,7 @@ async function sessionCreateCommand(options) {
|
|
|
26941
27395
|
environmentId: environment.environmentId,
|
|
26942
27396
|
environment: environment.tag || envData.tag?.name || envData.buildPolicy.tagName || requestedEnvironment,
|
|
26943
27397
|
sessionId: environment.sessionId,
|
|
27398
|
+
sessionScope: options.sessionScope?.trim() || null,
|
|
26944
27399
|
subjectId: environment.subjectId,
|
|
26945
27400
|
versionId: environment.versionId
|
|
26946
27401
|
};
|
|
@@ -26955,6 +27410,7 @@ async function sessionCreateCommand(options) {
|
|
|
26955
27410
|
Environment: payload.environment,
|
|
26956
27411
|
"Environment ID": payload.environmentId,
|
|
26957
27412
|
"Session ID": payload.sessionId,
|
|
27413
|
+
"Session scope": payload.sessionScope || "unscoped",
|
|
26958
27414
|
"Subject ID": payload.subjectId,
|
|
26959
27415
|
"Version ID": payload.versionId
|
|
26960
27416
|
});
|
|
@@ -26970,6 +27426,21 @@ async function sessionCreateCommand(options) {
|
|
|
26970
27426
|
async function sessionListCommand(options) {
|
|
26971
27427
|
const emitJson = options.json === true;
|
|
26972
27428
|
const status = options.status ?? "active";
|
|
27429
|
+
const allowedStatuses = /* @__PURE__ */ new Set([
|
|
27430
|
+
"active",
|
|
27431
|
+
"closed",
|
|
27432
|
+
"expired",
|
|
27433
|
+
"failed",
|
|
27434
|
+
"timeout",
|
|
27435
|
+
"all"
|
|
27436
|
+
]);
|
|
27437
|
+
if (!allowedStatuses.has(status)) {
|
|
27438
|
+
throw new Error(
|
|
27439
|
+
"--status must be one of active, closed, expired, failed, timeout, or all."
|
|
27440
|
+
);
|
|
27441
|
+
}
|
|
27442
|
+
const limit = parseSessionListInteger(options.limit, "limit");
|
|
27443
|
+
const offset = parseSessionListInteger(options.offset, "offset");
|
|
26973
27444
|
const requestedEnvironment = options.environment ?? "dev";
|
|
26974
27445
|
if (!emitJson) {
|
|
26975
27446
|
printHeader();
|
|
@@ -26979,18 +27450,33 @@ async function sessionListCommand(options) {
|
|
|
26979
27450
|
ontology: options.ontology,
|
|
26980
27451
|
environment: requestedEnvironment,
|
|
26981
27452
|
environmentId: options.environmentId,
|
|
27453
|
+
subjectId: options.subjectId,
|
|
26982
27454
|
createIfMissing: false
|
|
26983
27455
|
});
|
|
26984
27456
|
const items = await listSessionsForEnvironment(
|
|
26985
27457
|
granular,
|
|
26986
27458
|
environmentData.environmentId,
|
|
26987
|
-
|
|
27459
|
+
{
|
|
27460
|
+
status,
|
|
27461
|
+
sessionScope: options.sessionScope?.trim() || void 0,
|
|
27462
|
+
subjectId: options.subjectId?.trim() || void 0,
|
|
27463
|
+
limit,
|
|
27464
|
+
offset
|
|
27465
|
+
}
|
|
26988
27466
|
);
|
|
26989
27467
|
const payload = {
|
|
26990
27468
|
ontologyId: environmentData.sandboxId,
|
|
26991
27469
|
environmentId: environmentData.environmentId,
|
|
26992
27470
|
environment: environmentData.tag?.name || environmentData.buildPolicy.tagName || requestedEnvironment,
|
|
26993
27471
|
status,
|
|
27472
|
+
sessionScope: options.sessionScope?.trim() || null,
|
|
27473
|
+
page: {
|
|
27474
|
+
limit,
|
|
27475
|
+
offset,
|
|
27476
|
+
returned: items.length,
|
|
27477
|
+
mayHaveMore: items.length === limit,
|
|
27478
|
+
nextOffset: items.length === limit ? offset + items.length : null
|
|
27479
|
+
},
|
|
26994
27480
|
items
|
|
26995
27481
|
};
|
|
26996
27482
|
if (emitJson) {
|
|
@@ -27013,6 +27499,9 @@ async function sessionListCommand(options) {
|
|
|
27013
27499
|
item.lastSeenAt
|
|
27014
27500
|
])
|
|
27015
27501
|
);
|
|
27502
|
+
info(
|
|
27503
|
+
`Showing ${items.length} session${items.length === 1 ? "" : "s"} from offset ${offset}.` + (items.length === limit ? ` Use --offset ${offset + items.length} for the next page.` : "")
|
|
27504
|
+
);
|
|
27016
27505
|
console.log();
|
|
27017
27506
|
}
|
|
27018
27507
|
|
|
@@ -27689,9 +28178,12 @@ program2.command("build").description(
|
|
|
27689
28178
|
});
|
|
27690
28179
|
program2.command("deploy").description(
|
|
27691
28180
|
"Push the current revision to dev; use --prod to move prod there too"
|
|
27692
|
-
).option("--prod", "Also point prod to the current version").
|
|
28181
|
+
).option("--prod", "Also point prod to the current version").option(
|
|
28182
|
+
"--release-key <key>",
|
|
28183
|
+
"Version data/importer changes with this immutable release key"
|
|
28184
|
+
).action(async (opts) => {
|
|
27693
28185
|
try {
|
|
27694
|
-
await deployCommand({ prod: opts.prod });
|
|
28186
|
+
await deployCommand({ prod: opts.prod, releaseKey: opts.releaseKey });
|
|
27695
28187
|
} catch (err) {
|
|
27696
28188
|
error(err.message);
|
|
27697
28189
|
process.exit(1);
|
|
@@ -27919,6 +28411,9 @@ session.command("create").description(
|
|
|
27919
28411
|
"--permissions <list>",
|
|
27920
28412
|
"Comma-separated permission profile to ensure when a named environment needs to be created",
|
|
27921
28413
|
"allow-all"
|
|
28414
|
+
).option(
|
|
28415
|
+
"--session-scope <scope>",
|
|
28416
|
+
"Application-owned history scope to persist on the new session"
|
|
27922
28417
|
).option("--json", "Print machine-readable JSON").action(
|
|
27923
28418
|
async (options) => {
|
|
27924
28419
|
try {
|
|
@@ -27929,7 +28424,7 @@ session.command("create").description(
|
|
|
27929
28424
|
}
|
|
27930
28425
|
}
|
|
27931
28426
|
);
|
|
27932
|
-
session.command("list").description("List indexed sessions for an environment").option(
|
|
28427
|
+
session.command("list").description("List one bounded page of indexed sessions for an environment").option(
|
|
27933
28428
|
"--ontology <ontologyId>",
|
|
27934
28429
|
"Override the ontology id from .granularrc"
|
|
27935
28430
|
).option(
|
|
@@ -27939,11 +28434,17 @@ session.command("list").description("List indexed sessions for an environment").
|
|
|
27939
28434
|
).option(
|
|
27940
28435
|
"--environment-id <environmentId>",
|
|
27941
28436
|
"List sessions for this exact environment id"
|
|
28437
|
+
).option(
|
|
28438
|
+
"--subject-id <subjectId>",
|
|
28439
|
+
"Resolve and constrain history to this internal Granular subject id"
|
|
28440
|
+
).option(
|
|
28441
|
+
"--session-scope <scope>",
|
|
28442
|
+
"Return only sessions owned by this application history scope"
|
|
27942
28443
|
).option(
|
|
27943
28444
|
"--status <status>",
|
|
27944
|
-
"Session status
|
|
28445
|
+
"Session status: active|closed|expired|failed|timeout|all",
|
|
27945
28446
|
"active"
|
|
27946
|
-
).option("--json", "Print machine-readable JSON").action(
|
|
28447
|
+
).option("--limit <count>", "Rows to return (1-500)", "25").option("--offset <count>", "Rows to skip (0-100000)", "0").option("--json", "Print machine-readable JSON").action(
|
|
27947
28448
|
async (options) => {
|
|
27948
28449
|
try {
|
|
27949
28450
|
await sessionListCommand(options);
|