@granular-software/sdk 0.4.51 → 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/dist/agent-evals.d.mts +2 -2
- package/dist/agent-evals.d.ts +2 -2
- package/dist/agent-evals.js +236 -31
- package/dist/agent-evals.js.map +1 -1
- package/dist/agent-evals.mjs +236 -31
- package/dist/agent-evals.mjs.map +1 -1
- package/dist/cli/index.js +267 -50
- package/dist/{client-djorlOpn.d.mts → client-B2OyGOHE.d.mts} +18 -3
- package/dist/{client-NSH-tpNU.d.ts → client-BMfjRJTs.d.ts} +18 -3
- package/dist/index.d.mts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +236 -31
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +236 -31
- package/dist/index.mjs.map +1 -1
- package/dist/{spend-BA-jZwZ0.d.mts → spend-DpRRCrAr.d.mts} +37 -2
- package/dist/{spend-BA-jZwZ0.d.ts → spend-DpRRCrAr.d.ts} +37 -2
- package/dist/spend.d.mts +1 -1
- package/dist/spend.d.ts +1 -1
- package/package.json +1 -1
package/dist/agent-evals.mjs
CHANGED
|
@@ -14192,7 +14192,8 @@ function normalizeEnvironmentSetupSummary(setup) {
|
|
|
14192
14192
|
environmentId: String(setup.environmentId || ""),
|
|
14193
14193
|
sandboxId: String(setup.sandboxId || ""),
|
|
14194
14194
|
subjectId: String(setup.subjectId || ""),
|
|
14195
|
-
triggerReason: setup.triggerReason === "fresh_after_version_update" ? "fresh_after_version_update" : "new_environment",
|
|
14195
|
+
triggerReason: setup.triggerReason === "fresh_after_version_update" ? "fresh_after_version_update" : setup.triggerReason === "explicit_reset" ? "explicit_reset" : "new_environment",
|
|
14196
|
+
operationKey: typeof setup.operationKey === "string" ? setup.operationKey : null,
|
|
14196
14197
|
lifecycleStatus: setup.lifecycleStatus === "completed" || setup.lifecycleStatus === "failed" ? setup.lifecycleStatus : "running",
|
|
14197
14198
|
stage: typeof setup.stage === "string" ? setup.stage : null,
|
|
14198
14199
|
totalObjectsToImport: Number(setup.totalObjectsToImport || 0),
|
|
@@ -15474,6 +15475,7 @@ var Environment = class _Environment {
|
|
|
15474
15475
|
records: recordsToImport,
|
|
15475
15476
|
batchSize: options.batchSize,
|
|
15476
15477
|
setupRunId: options.setupRunId,
|
|
15478
|
+
operationKey: options.operationKey,
|
|
15477
15479
|
writeMode: options.writeMode
|
|
15478
15480
|
})
|
|
15479
15481
|
}
|
|
@@ -16278,6 +16280,107 @@ var Granular = class _Granular {
|
|
|
16278
16280
|
await this.maybeRunEnvironmentImporter(resolved, environment);
|
|
16279
16281
|
return environment;
|
|
16280
16282
|
}
|
|
16283
|
+
/**
|
|
16284
|
+
* Read the active environment selected by Granular for an already-recorded
|
|
16285
|
+
* external user. This is intentionally read-only: browser/login code must
|
|
16286
|
+
* not create subjects or environments as a side effect.
|
|
16287
|
+
*/
|
|
16288
|
+
async getActiveEnvironmentForUser(options) {
|
|
16289
|
+
const sandboxId = options.sandboxId.trim();
|
|
16290
|
+
const tagName = options.tag.trim();
|
|
16291
|
+
const userId = options.userId.trim();
|
|
16292
|
+
if (!sandboxId || !tagName || !userId) {
|
|
16293
|
+
throw new Error(
|
|
16294
|
+
"getActiveEnvironmentForUser() requires sandboxId, tag, and userId."
|
|
16295
|
+
);
|
|
16296
|
+
}
|
|
16297
|
+
const subjects = await this.request(
|
|
16298
|
+
`/control/subjects?identityId=${encodeURIComponent(userId)}`
|
|
16299
|
+
);
|
|
16300
|
+
const subject = (subjects.items || []).find(
|
|
16301
|
+
(item) => item.identityId === userId || item.userId === userId
|
|
16302
|
+
);
|
|
16303
|
+
if (!subject?.subjectId && !subject?.granularId) {
|
|
16304
|
+
return null;
|
|
16305
|
+
}
|
|
16306
|
+
const subjectId = subject.subjectId || subject.granularId;
|
|
16307
|
+
const tags = await this.request(
|
|
16308
|
+
`/control/sandboxes/${encodeURIComponent(sandboxId)}/tags`
|
|
16309
|
+
);
|
|
16310
|
+
const tag = (tags.items || []).find(
|
|
16311
|
+
(item) => item?.name === tagName
|
|
16312
|
+
);
|
|
16313
|
+
if (!tag) return null;
|
|
16314
|
+
const query = new URLSearchParams({
|
|
16315
|
+
tagId: tag.tagId,
|
|
16316
|
+
slot: options.slot?.trim() || "default"
|
|
16317
|
+
});
|
|
16318
|
+
try {
|
|
16319
|
+
const payload = await this.request(
|
|
16320
|
+
`/control/sandboxes/${encodeURIComponent(sandboxId)}/subjects/${encodeURIComponent(subjectId)}/active-environment?${query.toString()}`
|
|
16321
|
+
);
|
|
16322
|
+
return payload.environment ? this.bindEnvironmentHandle(
|
|
16323
|
+
normalizeEnvironmentData(payload.environment)
|
|
16324
|
+
) : null;
|
|
16325
|
+
} catch (error) {
|
|
16326
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
16327
|
+
if (message.includes("404") || message.includes("not found")) {
|
|
16328
|
+
return null;
|
|
16329
|
+
}
|
|
16330
|
+
throw error;
|
|
16331
|
+
}
|
|
16332
|
+
}
|
|
16333
|
+
/**
|
|
16334
|
+
* Register one reviewed, pre-existing environment as the active workspace
|
|
16335
|
+
* for an external user. This is for a controlled migration only: it does
|
|
16336
|
+
* not create an environment and it does not run an importer.
|
|
16337
|
+
*/
|
|
16338
|
+
async adoptEnvironmentForUser(options) {
|
|
16339
|
+
const sandboxId = options.sandboxId.trim();
|
|
16340
|
+
const tagName = options.tag.trim();
|
|
16341
|
+
const userId = options.userId.trim();
|
|
16342
|
+
const environmentId = options.environmentId.trim();
|
|
16343
|
+
if (!sandboxId || !tagName || !userId || !environmentId) {
|
|
16344
|
+
throw new Error(
|
|
16345
|
+
"adoptEnvironmentForUser() requires sandboxId, tag, userId, and environmentId."
|
|
16346
|
+
);
|
|
16347
|
+
}
|
|
16348
|
+
const subjects = await this.request(
|
|
16349
|
+
`/control/subjects?identityId=${encodeURIComponent(userId)}`
|
|
16350
|
+
);
|
|
16351
|
+
const subject = (subjects.items || []).find(
|
|
16352
|
+
(item) => item.identityId === userId || item.userId === userId
|
|
16353
|
+
);
|
|
16354
|
+
if (!subject?.subjectId && !subject?.granularId) {
|
|
16355
|
+
throw new Error(`No Granular subject exists for user ${userId}.`);
|
|
16356
|
+
}
|
|
16357
|
+
const tags = await this.request(`/control/sandboxes/${encodeURIComponent(sandboxId)}/tags`);
|
|
16358
|
+
const tag = (tags.items || []).find(
|
|
16359
|
+
(item) => item?.name === tagName
|
|
16360
|
+
);
|
|
16361
|
+
if (!tag) {
|
|
16362
|
+
throw new Error(`Tag ${tagName} was not found in sandbox ${sandboxId}.`);
|
|
16363
|
+
}
|
|
16364
|
+
const payload = await this.request(
|
|
16365
|
+
"/control/environment-activations/adopt",
|
|
16366
|
+
{
|
|
16367
|
+
method: "POST",
|
|
16368
|
+
body: JSON.stringify({
|
|
16369
|
+
environmentId,
|
|
16370
|
+
subjectId: subject.subjectId || subject.granularId,
|
|
16371
|
+
tagId: tag.tagId,
|
|
16372
|
+
slot: options.slot?.trim() || "default",
|
|
16373
|
+
confirmExistingData: true
|
|
16374
|
+
})
|
|
16375
|
+
}
|
|
16376
|
+
);
|
|
16377
|
+
if (!payload.environment) {
|
|
16378
|
+
throw new Error("Granular did not return the adopted environment.");
|
|
16379
|
+
}
|
|
16380
|
+
return this.bindEnvironmentHandle(
|
|
16381
|
+
normalizeEnvironmentData(payload.environment)
|
|
16382
|
+
);
|
|
16383
|
+
}
|
|
16281
16384
|
/**
|
|
16282
16385
|
* Deprecated compatibility alias for `openEnvironment()`.
|
|
16283
16386
|
*
|
|
@@ -16309,7 +16412,9 @@ var Granular = class _Granular {
|
|
|
16309
16412
|
requestedOntology,
|
|
16310
16413
|
sandboxId: environmentData.sandboxId,
|
|
16311
16414
|
subjectId: environmentData.subjectId,
|
|
16312
|
-
|
|
16415
|
+
externalUserId: environmentData.subjectId,
|
|
16416
|
+
setupTriggerReason: options.reason || "new_environment",
|
|
16417
|
+
setupOperationKey: options.operationKey
|
|
16313
16418
|
},
|
|
16314
16419
|
environment
|
|
16315
16420
|
);
|
|
@@ -16321,20 +16426,17 @@ var Granular = class _Granular {
|
|
|
16321
16426
|
}
|
|
16322
16427
|
return tag;
|
|
16323
16428
|
}
|
|
16324
|
-
buildManagedEnvironmentName(tag, versionId) {
|
|
16325
|
-
|
|
16429
|
+
buildManagedEnvironmentName(tag, versionId, resetKey) {
|
|
16430
|
+
if (!resetKey) {
|
|
16431
|
+
return `__sdk__${tag}__${versionId}__tracked`;
|
|
16432
|
+
}
|
|
16433
|
+
const safeResetKey = resetKey.replace(/[^a-zA-Z0-9_-]/g, "_").slice(0, 80);
|
|
16434
|
+
return `__sdk__${tag}__${versionId}__reset__${safeResetKey}`;
|
|
16326
16435
|
}
|
|
16327
16436
|
isManagedEnvironmentName(environment, tagName) {
|
|
16328
16437
|
const name = environment.environment || environment.envName || "";
|
|
16329
16438
|
return name.startsWith(`__sdk__${tagName}__`);
|
|
16330
16439
|
}
|
|
16331
|
-
isPinnedToVersion(environment, versionId) {
|
|
16332
|
-
return environment.buildPolicy.mode === "pinned" && (environment.versionId === versionId || environment.buildPolicy.versionId === versionId || environment.buildPolicy.buildId === versionId);
|
|
16333
|
-
}
|
|
16334
|
-
matchesTagTrackedEnvironment(environment, tagName, tagId) {
|
|
16335
|
-
const environmentTagName = environment.tag?.name || environment.buildPolicy.tagName || null;
|
|
16336
|
-
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);
|
|
16337
|
-
}
|
|
16338
16440
|
sortEnvironmentsByRecency(environments) {
|
|
16339
16441
|
return [...environments].sort(
|
|
16340
16442
|
(left, right) => right.updatedAt - left.updatedAt
|
|
@@ -16384,48 +16486,119 @@ var Granular = class _Granular {
|
|
|
16384
16486
|
`Tag "${tagName}" does not currently point to a build/version.`
|
|
16385
16487
|
);
|
|
16386
16488
|
}
|
|
16489
|
+
const slot = options.slot?.trim() || "default";
|
|
16490
|
+
const resetKey = options.resetKey?.trim() || void 0;
|
|
16491
|
+
const resolveActive = async (operationKey) => {
|
|
16492
|
+
const query = new URLSearchParams({ tagId: tag.tagId, slot });
|
|
16493
|
+
if (operationKey) query.set("operationKey", operationKey);
|
|
16494
|
+
try {
|
|
16495
|
+
const payload = await this.request(
|
|
16496
|
+
`/control/sandboxes/${encodeURIComponent(sandbox.sandboxId)}/subjects/${encodeURIComponent(user.granularId)}/active-environment?${query.toString()}`
|
|
16497
|
+
);
|
|
16498
|
+
return payload.environment ? normalizeEnvironmentData(payload.environment) : null;
|
|
16499
|
+
} catch (error) {
|
|
16500
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
16501
|
+
if (message.includes("404") || message.includes("not found")) {
|
|
16502
|
+
return null;
|
|
16503
|
+
}
|
|
16504
|
+
throw error;
|
|
16505
|
+
}
|
|
16506
|
+
};
|
|
16507
|
+
const activate = async (environment2) => {
|
|
16508
|
+
const payload = await this.request(
|
|
16509
|
+
"/control/environment-activations",
|
|
16510
|
+
{
|
|
16511
|
+
method: "POST",
|
|
16512
|
+
body: JSON.stringify({
|
|
16513
|
+
environmentId: environment2.environmentId,
|
|
16514
|
+
tagId: tag.tagId,
|
|
16515
|
+
slot,
|
|
16516
|
+
operationKey: resetKey,
|
|
16517
|
+
operation: resetKey ? "explicit_reset" : void 0
|
|
16518
|
+
})
|
|
16519
|
+
}
|
|
16520
|
+
);
|
|
16521
|
+
return normalizeEnvironmentData(payload.environment);
|
|
16522
|
+
};
|
|
16523
|
+
if (resetKey) {
|
|
16524
|
+
const resetEnvironment = await resolveActive(resetKey);
|
|
16525
|
+
if (resetEnvironment) {
|
|
16526
|
+
return {
|
|
16527
|
+
environment: resetEnvironment,
|
|
16528
|
+
requestedOntology: ontology,
|
|
16529
|
+
sandboxId: sandbox.sandboxId,
|
|
16530
|
+
subjectId: user.granularId,
|
|
16531
|
+
externalUserId: user.userId,
|
|
16532
|
+
// Retrying an explicit reset must also resume its durable setup run.
|
|
16533
|
+
// Otherwise a Container crash after queue submission would leave a
|
|
16534
|
+
// valid environment permanently marked as "running".
|
|
16535
|
+
setupTriggerReason: "explicit_reset",
|
|
16536
|
+
setupOperationKey: resetKey
|
|
16537
|
+
};
|
|
16538
|
+
}
|
|
16539
|
+
} else {
|
|
16540
|
+
const active = await resolveActive();
|
|
16541
|
+
if (active && (active.versionId === targetVersionId || options.createFreshIfOutdated !== true)) {
|
|
16542
|
+
return {
|
|
16543
|
+
environment: active,
|
|
16544
|
+
requestedOntology: ontology,
|
|
16545
|
+
sandboxId: sandbox.sandboxId,
|
|
16546
|
+
subjectId: user.granularId,
|
|
16547
|
+
externalUserId: user.userId
|
|
16548
|
+
};
|
|
16549
|
+
}
|
|
16550
|
+
}
|
|
16387
16551
|
const allEnvironments = await this.environments.list(sandbox.sandboxId);
|
|
16388
16552
|
const userEnvironments = allEnvironments.filter(
|
|
16389
|
-
(
|
|
16553
|
+
(environment2) => environment2.subjectId === user.granularId
|
|
16390
16554
|
);
|
|
16391
16555
|
const currentMatches = this.sortEnvironmentsByRecency(
|
|
16392
16556
|
userEnvironments.filter(
|
|
16393
|
-
(
|
|
16557
|
+
(environment2) => environment2.tagId === tag.tagId && environment2.versionId === targetVersionId
|
|
16394
16558
|
)
|
|
16395
16559
|
);
|
|
16396
|
-
if (currentMatches.length > 0) {
|
|
16560
|
+
if (!resetKey && currentMatches.length > 0) {
|
|
16561
|
+
const environment2 = await activate(currentMatches[0]);
|
|
16397
16562
|
return {
|
|
16398
|
-
environment:
|
|
16563
|
+
environment: environment2,
|
|
16399
16564
|
requestedOntology: ontology,
|
|
16400
16565
|
sandboxId: sandbox.sandboxId,
|
|
16401
|
-
subjectId: user.granularId
|
|
16566
|
+
subjectId: user.granularId,
|
|
16567
|
+
externalUserId: user.userId
|
|
16402
16568
|
};
|
|
16403
16569
|
}
|
|
16404
16570
|
const outdatedMatches = this.sortEnvironmentsByRecency(
|
|
16405
|
-
userEnvironments.filter(
|
|
16406
|
-
(environment) => this.matchesTagTrackedEnvironment(environment, tagName, tag.tagId)
|
|
16407
|
-
)
|
|
16571
|
+
userEnvironments.filter((environment2) => environment2.tagId === tag.tagId)
|
|
16408
16572
|
);
|
|
16409
16573
|
if (outdatedMatches.length > 0 && options.createFreshIfOutdated !== true) {
|
|
16574
|
+
const environment2 = await activate(outdatedMatches[0]);
|
|
16410
16575
|
return {
|
|
16411
|
-
environment:
|
|
16576
|
+
environment: environment2,
|
|
16412
16577
|
requestedOntology: ontology,
|
|
16413
16578
|
sandboxId: sandbox.sandboxId,
|
|
16414
|
-
subjectId: user.granularId
|
|
16579
|
+
subjectId: user.granularId,
|
|
16580
|
+
externalUserId: user.userId
|
|
16415
16581
|
};
|
|
16416
16582
|
}
|
|
16583
|
+
const created = await this.environments.create(sandbox.sandboxId, {
|
|
16584
|
+
subjectId: user.granularId,
|
|
16585
|
+
environment: this.buildManagedEnvironmentName(
|
|
16586
|
+
tagName,
|
|
16587
|
+
targetVersionId,
|
|
16588
|
+
resetKey
|
|
16589
|
+
),
|
|
16590
|
+
tagId: tag.tagId,
|
|
16591
|
+
permissionProfileId: null
|
|
16592
|
+
});
|
|
16593
|
+
const environment = await activate(created);
|
|
16417
16594
|
return {
|
|
16418
|
-
environment
|
|
16419
|
-
subjectId: user.granularId,
|
|
16420
|
-
environment: this.buildManagedEnvironmentName(tagName, targetVersionId),
|
|
16421
|
-
tagId: tag.tagId,
|
|
16422
|
-
versionId: targetVersionId,
|
|
16423
|
-
permissionProfileId: null
|
|
16424
|
-
}),
|
|
16595
|
+
environment,
|
|
16425
16596
|
requestedOntology: ontology,
|
|
16426
16597
|
sandboxId: sandbox.sandboxId,
|
|
16427
16598
|
subjectId: user.granularId,
|
|
16428
|
-
|
|
16599
|
+
externalUserId: user.userId,
|
|
16600
|
+
setupTriggerReason: resetKey ? "explicit_reset" : outdatedMatches.length > 0 ? "fresh_after_version_update" : "new_environment",
|
|
16601
|
+
setupOperationKey: resetKey
|
|
16429
16602
|
};
|
|
16430
16603
|
}
|
|
16431
16604
|
/**
|
|
@@ -16704,11 +16877,24 @@ var Granular = class _Granular {
|
|
|
16704
16877
|
{
|
|
16705
16878
|
method: "POST",
|
|
16706
16879
|
body: JSON.stringify({
|
|
16707
|
-
triggerReason: resolved.setupTriggerReason
|
|
16880
|
+
triggerReason: resolved.setupTriggerReason,
|
|
16881
|
+
operationKey: resolved.setupOperationKey
|
|
16708
16882
|
})
|
|
16709
16883
|
}
|
|
16710
16884
|
);
|
|
16711
16885
|
const setupRunId = setupRun.setupRunId;
|
|
16886
|
+
let claim = null;
|
|
16887
|
+
for (let attempt = 0; attempt < 3; attempt += 1) {
|
|
16888
|
+
claim = await this.request(
|
|
16889
|
+
`/control/environment-setup-runs/${setupRunId}/importer-claim`,
|
|
16890
|
+
{ method: "POST", body: JSON.stringify({}) }
|
|
16891
|
+
);
|
|
16892
|
+
if (claim.action !== "busy") break;
|
|
16893
|
+
await sleep(Math.min(3e4, Math.max(250, claim.retryAfterMs || 1e3)));
|
|
16894
|
+
}
|
|
16895
|
+
if (!claim) {
|
|
16896
|
+
throw new Error(`Unable to claim environment setup run ${setupRunId}.`);
|
|
16897
|
+
}
|
|
16712
16898
|
const updateSetupRun = async (patch) => {
|
|
16713
16899
|
await this.request(
|
|
16714
16900
|
`/control/environment-setup-runs/${setupRunId}`,
|
|
@@ -16718,10 +16904,26 @@ var Granular = class _Granular {
|
|
|
16718
16904
|
}
|
|
16719
16905
|
);
|
|
16720
16906
|
};
|
|
16907
|
+
if (claim.action === "submitted") {
|
|
16908
|
+
const completedSetupRun = await this.request(
|
|
16909
|
+
`/control/environment-setup-runs/${setupRunId}`,
|
|
16910
|
+
{ method: "PATCH", body: JSON.stringify({ markHookCompleted: true }) }
|
|
16911
|
+
);
|
|
16912
|
+
const refreshedEnvironment = await this.environments.get(
|
|
16913
|
+
environment.environmentId
|
|
16914
|
+
);
|
|
16915
|
+
environment.syncEnvironmentData(refreshedEnvironment);
|
|
16916
|
+
return completedSetupRun;
|
|
16917
|
+
}
|
|
16918
|
+
if (claim.action === "busy" || claim.action === "terminal") {
|
|
16919
|
+
return claim.summary;
|
|
16920
|
+
}
|
|
16921
|
+
let importSequence = 0;
|
|
16721
16922
|
const importerContext = {
|
|
16722
16923
|
environmentId: environment.environmentId,
|
|
16723
16924
|
sandboxId: environment.sandboxId,
|
|
16724
16925
|
subjectId: environment.subjectId,
|
|
16926
|
+
externalUserId: resolved.externalUserId,
|
|
16725
16927
|
reason: resolved.setupTriggerReason,
|
|
16726
16928
|
incrementTotalObjectsToImportCount: async (n) => {
|
|
16727
16929
|
const safeIncrement = Math.max(0, Math.trunc(n));
|
|
@@ -16738,7 +16940,10 @@ var Granular = class _Granular {
|
|
|
16738
16940
|
importRecords: async (records, options) => environment.enqueueRecordImport(records, {
|
|
16739
16941
|
batchSize: options?.batchSize,
|
|
16740
16942
|
writeMode: options?.writeMode,
|
|
16741
|
-
setupRunId
|
|
16943
|
+
setupRunId,
|
|
16944
|
+
// Sequence is deterministic for a retry of one importer hook. It
|
|
16945
|
+
// prevents a Container restart from creating a second queue import.
|
|
16946
|
+
operationKey: `${setupRunId}:import:${importSequence++}`
|
|
16742
16947
|
})
|
|
16743
16948
|
};
|
|
16744
16949
|
try {
|