deepline 0.3.113 → 0.3.115
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/bundling-sources/sdk/src/client.ts +3 -1
- package/dist/bundling-sources/sdk/src/compat.ts +167 -11
- package/dist/bundling-sources/sdk/src/release.ts +1 -1
- package/dist/bundling-sources/sdk/src/skills-version.ts +27 -1
- package/dist/bundling-sources/shared_libs/monitors/inbound-queue.ts +6 -2
- package/dist/bundling-sources/shared_libs/observability/dlq.ts +942 -0
- package/dist/bundling-sources/shared_libs/observability/queue-health.ts +361 -6
- package/dist/bundling-sources/shared_libs/observability/scheduled-jobs.json +24 -24
- package/dist/bundling-sources/shared_libs/observability/scheduled-work-manual.ts +2 -0
- package/dist/bundling-sources/shared_libs/observability/scheduled-work.ts +29 -1
- package/dist/bundling-sources/shared_libs/play-runtime/admission-transport-policy.ts +91 -0
- package/dist/bundling-sources/shared_libs/play-runtime/context.ts +2 -0
- package/dist/bundling-sources/shared_libs/play-runtime/direct-admission-deadline.ts +34 -0
- package/dist/bundling-sources/shared_libs/play-runtime/fixture-behavior.ts +1 -0
- package/dist/bundling-sources/shared_libs/play-runtime/internal-bootstrap-token.ts +325 -0
- package/dist/bundling-sources/shared_libs/play-runtime/play-admission-outcome.ts +134 -0
- package/dist/bundling-sources/shared_libs/play-runtime/play-runs/admission/contracts.ts +13 -0
- package/dist/bundling-sources/shared_libs/play-runtime/play-runs/admission/index.ts +4 -1
- package/dist/bundling-sources/shared_libs/play-runtime/play-runs/admission/postgres-adapter.ts +13 -0
- package/dist/bundling-sources/shared_libs/play-runtime/play-webhook-admission-probe.ts +32 -0
- package/dist/bundling-sources/shared_libs/play-runtime/play-webhook-identity.ts +28 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backend.ts +7 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-cron-fire-task.ts +100 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-runtime-worker.ts +313 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-shared.ts +111 -3
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd.ts +16 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres-pool.ts +67 -8
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres.ts +1734 -147
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/run-ledger-outbox-recovery.ts +74 -13
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runtime-queue-health.ts +245 -81
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/submit-admission.ts +79 -15
- package/dist/bundling-sources/shared_libs/play-runtime/webhook-receipt-retry.ts +21 -21
- package/dist/bundling-sources/shared_libs/plays/bundling/index.ts +4 -1
- package/dist/bundling-sources/shared_libs/product-notifications/catalog.ts +64 -0
- package/dist/bundling-sources/shared_libs/product-notifications/default-policy.ts +1 -1
- package/dist/bundling-sources/shared_libs/product-notifications/events.ts +20 -1
- package/dist/bundling-sources/shared_libs/security/receipt-admission-token.ts +224 -0
- package/dist/cli/index.js +574 -114
- package/dist/cli/index.mjs +592 -133
- package/dist/index.d.mts +54 -1
- package/dist/index.d.ts +54 -1
- package/dist/index.js +8 -3
- package/dist/index.mjs +8 -3
- package/dist/install-integrity.json +8 -0
- package/dist/plays/bundle-play-file.mjs +1 -1
- package/dist/release.d.mts +1 -1
- package/dist/release.d.ts +1 -1
- package/dist/release.js +1 -1
- package/dist/release.mjs +1 -1
- package/package.json +1 -1
package/dist/cli/index.mjs
CHANGED
|
@@ -1271,7 +1271,7 @@ var SDK_RELEASE = {
|
|
|
1271
1271
|
// getters keep their established compatibility behavior.
|
|
1272
1272
|
// 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
|
|
1273
1273
|
// 0.3.90 is the first deliberately versioned SDK release for API v3.
|
|
1274
|
-
version: "0.3.
|
|
1274
|
+
version: "0.3.115",
|
|
1275
1275
|
updateSummary: "Play grep now returns concise results with the matched fields and terms. Automatic CLI updates are enabled by default; use `deepline settings autoupdate off` to opt out, `deepline settings autoupdate on` to re-enable updates, or `deepline settings autoupdate pin <version>` to hold an exact release.",
|
|
1276
1276
|
packageCapabilities: {
|
|
1277
1277
|
updatePreferences: 1
|
|
@@ -1487,8 +1487,22 @@ function readPluginSkillsVersion() {
|
|
|
1487
1487
|
return "";
|
|
1488
1488
|
}
|
|
1489
1489
|
}
|
|
1490
|
+
var KNOWN_SKILL_AGENTS = [
|
|
1491
|
+
"antigravity",
|
|
1492
|
+
"claude-code",
|
|
1493
|
+
"cline",
|
|
1494
|
+
"codex",
|
|
1495
|
+
"cursor",
|
|
1496
|
+
"gemini-cli",
|
|
1497
|
+
"windsurf"
|
|
1498
|
+
];
|
|
1499
|
+
function skillsAgentPathSegment(agent) {
|
|
1500
|
+
if (agent === "*") return "all";
|
|
1501
|
+
const slug = agent.replace(/[^a-z0-9]+/gi, "-").replace(/^-+|-+$/g, "");
|
|
1502
|
+
return slug || "agent";
|
|
1503
|
+
}
|
|
1490
1504
|
function sdkSkillsVersionPath(baseUrl, agents = []) {
|
|
1491
|
-
const suffix = agents.length > 0 ? `-${agents.join("-")}` : "";
|
|
1505
|
+
const suffix = agents.length > 0 ? `-${agents.map(skillsAgentPathSegment).join("-")}` : "";
|
|
1492
1506
|
return join2(sdkCliStateDirPath(baseUrl), `skills${suffix}-version`);
|
|
1493
1507
|
}
|
|
1494
1508
|
function legacySdkSkillsVersionPath(baseUrl) {
|
|
@@ -4820,7 +4834,7 @@ function resolveToolExecuteTimeoutMs(toolId, input2) {
|
|
|
4820
4834
|
if (usesExtendedBetterContactLauncherBudget(normalized)) {
|
|
4821
4835
|
return BETTERCONTACT_LAUNCHER_CLIENT_TIMEOUT_MS;
|
|
4822
4836
|
}
|
|
4823
|
-
return normalized === "deeplineagent" || normalized === "deeplineagent_deeplineagent" || normalized === "ai_inference" || normalized === "deeplineagent_ai_inference" || normalized === "aiinference" ? DEEPLINEAGENT_EXECUTE_TIMEOUT_MS : void 0;
|
|
4837
|
+
return normalized === "deeplineagent" || normalized === "deeplineagent_deeplineagent" || normalized === "ai_inference" || normalized === "deeplineagent_ai_inference" || normalized === "ai_evaluate" || normalized === "deeplineagent_ai_evaluate" || normalized === "aiinference" ? DEEPLINEAGENT_EXECUTE_TIMEOUT_MS : void 0;
|
|
4824
4838
|
}
|
|
4825
4839
|
var RUNS_FAILED_LOG_LIMIT = 20;
|
|
4826
4840
|
var RUN_LOGS_PAGE_LIMIT = 1e3;
|
|
@@ -8169,7 +8183,9 @@ import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as rea
|
|
|
8169
8183
|
import { homedir as homedir3 } from "os";
|
|
8170
8184
|
import { dirname as dirname3, join as join3 } from "path";
|
|
8171
8185
|
var CHECK_TIMEOUT_MS = 2e3;
|
|
8172
|
-
var
|
|
8186
|
+
var SDK_COMPATIBILITY_TRUST_MS = 10 * 60 * 1e3;
|
|
8187
|
+
var SDK_COMPATIBILITY_CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
8188
|
+
var SDK_COMPATIBILITY_FAST_DEADLINE_MS = 400;
|
|
8173
8189
|
function shouldSkipCompatibilityCheck() {
|
|
8174
8190
|
const value = process.env.DEEPLINE_SKIP_SDK_COMPAT_CHECK?.trim().toLowerCase();
|
|
8175
8191
|
return value === "1" || value === "true" || value === "yes";
|
|
@@ -8198,7 +8214,29 @@ function legacyCompatibilityCacheKey(baseUrl, command) {
|
|
|
8198
8214
|
command: command?.trim() || null
|
|
8199
8215
|
});
|
|
8200
8216
|
}
|
|
8217
|
+
function isCleanCompatibilityPolicy(response) {
|
|
8218
|
+
if (!response) return false;
|
|
8219
|
+
return response.ok === true && response.update_required !== true && response.status !== "unsupported" && !response.auto_update?.should_auto_update && !response.cli_family;
|
|
8220
|
+
}
|
|
8221
|
+
function readFreshCleanCompatibility(baseUrl, command, skillsVersion) {
|
|
8222
|
+
const cached = readCachedCompatibility(baseUrl, command, skillsVersion);
|
|
8223
|
+
return isCleanCompatibilityPolicy(cached) ? cached : null;
|
|
8224
|
+
}
|
|
8225
|
+
function readTrustedCleanCompatibility(baseUrl, command, skillsVersion, now = Date.now()) {
|
|
8226
|
+
const entry = readCachedCompatibilityEntry(baseUrl, command, skillsVersion);
|
|
8227
|
+
if (!entry || !isSavedWithin(entry.savedAt, SDK_COMPATIBILITY_TRUST_MS, now))
|
|
8228
|
+
return null;
|
|
8229
|
+
return isCleanCompatibilityPolicy(entry.response) ? entry.response : null;
|
|
8230
|
+
}
|
|
8231
|
+
function isSavedWithin(savedAt, windowMs, now) {
|
|
8232
|
+
if (typeof savedAt !== "number") return false;
|
|
8233
|
+
const age = now - savedAt;
|
|
8234
|
+
return Number.isFinite(age) && age >= 0 && age <= windowMs;
|
|
8235
|
+
}
|
|
8201
8236
|
function readCachedCompatibility(baseUrl, command, skillsVersion) {
|
|
8237
|
+
return readCachedCompatibilityEntry(baseUrl, command, skillsVersion)?.response ?? null;
|
|
8238
|
+
}
|
|
8239
|
+
function readCachedCompatibilityEntry(baseUrl, command, skillsVersion) {
|
|
8202
8240
|
try {
|
|
8203
8241
|
const path = sdkCompatibilityCachePath(baseUrl);
|
|
8204
8242
|
const legacyPath = legacySdkCompatibilityCachePath();
|
|
@@ -8211,14 +8249,31 @@ function readCachedCompatibility(baseUrl, command, skillsVersion) {
|
|
|
8211
8249
|
readFileSync3(cachePath, "utf8")
|
|
8212
8250
|
);
|
|
8213
8251
|
const entry = parsed.entries?.[compatibilityCacheKey(baseUrl, command, skillsVersion)] ?? (useLegacyCache ? parsed.entries?.[legacyCompatibilityCacheKey(baseUrl, command)] : void 0);
|
|
8214
|
-
if (!entry ||
|
|
8252
|
+
if (!entry || !isSavedWithin(entry.savedAt, SDK_COMPATIBILITY_CACHE_TTL_MS, Date.now())) {
|
|
8215
8253
|
return null;
|
|
8216
8254
|
}
|
|
8217
|
-
return entry
|
|
8255
|
+
return entry;
|
|
8218
8256
|
} catch {
|
|
8219
8257
|
return null;
|
|
8220
8258
|
}
|
|
8221
8259
|
}
|
|
8260
|
+
function invalidateCachedCompatibility(baseUrl, command, skillsVersion) {
|
|
8261
|
+
try {
|
|
8262
|
+
const path = sdkCompatibilityCachePath(baseUrl);
|
|
8263
|
+
const legacyPath = legacySdkCompatibilityCachePath();
|
|
8264
|
+
const cachePath = !existsSync3(path) && existsSync3(legacyPath) ? legacyPath : path;
|
|
8265
|
+
if (!existsSync3(cachePath)) return;
|
|
8266
|
+
const existing = JSON.parse(
|
|
8267
|
+
readFileSync3(cachePath, "utf8")
|
|
8268
|
+
);
|
|
8269
|
+
const entries = existing.entries ?? {};
|
|
8270
|
+
delete entries[compatibilityCacheKey(baseUrl, command, skillsVersion)];
|
|
8271
|
+
delete entries[legacyCompatibilityCacheKey(baseUrl, command)];
|
|
8272
|
+
writeFileSync3(cachePath, `${JSON.stringify({ entries }, null, 2)}
|
|
8273
|
+
`);
|
|
8274
|
+
} catch {
|
|
8275
|
+
}
|
|
8276
|
+
}
|
|
8222
8277
|
function writeCachedCompatibility(baseUrl, command, skillsVersion, response) {
|
|
8223
8278
|
try {
|
|
8224
8279
|
const path = sdkCompatibilityCachePath(baseUrl);
|
|
@@ -8239,7 +8294,10 @@ async function checkSdkCompatibility(baseUrl, options = {}) {
|
|
|
8239
8294
|
return { response: null, error: null };
|
|
8240
8295
|
}
|
|
8241
8296
|
const controller = new AbortController();
|
|
8242
|
-
const timeout = setTimeout(
|
|
8297
|
+
const timeout = setTimeout(
|
|
8298
|
+
() => controller.abort(),
|
|
8299
|
+
options.timeoutMs ?? CHECK_TIMEOUT_MS
|
|
8300
|
+
);
|
|
8243
8301
|
try {
|
|
8244
8302
|
const url = new URL("/api/v2/sdk/compat", baseUrl);
|
|
8245
8303
|
url.searchParams.set("version", SDK_VERSION);
|
|
@@ -8261,14 +8319,17 @@ async function checkSdkCompatibility(baseUrl, options = {}) {
|
|
|
8261
8319
|
signal: controller.signal
|
|
8262
8320
|
});
|
|
8263
8321
|
const data = await response.json().catch(() => null);
|
|
8264
|
-
if (data) {
|
|
8265
|
-
|
|
8266
|
-
|
|
8267
|
-
options.command,
|
|
8268
|
-
options.skillsVersion,
|
|
8269
|
-
data
|
|
8322
|
+
if (!data || typeof data.ok !== "boolean" || typeof data.status !== "string") {
|
|
8323
|
+
throw new Error(
|
|
8324
|
+
`SDK compatibility endpoint returned a non-policy response (HTTP ${response.status}).`
|
|
8270
8325
|
);
|
|
8271
8326
|
}
|
|
8327
|
+
writeCachedCompatibility(
|
|
8328
|
+
baseUrl,
|
|
8329
|
+
options.command,
|
|
8330
|
+
options.skillsVersion,
|
|
8331
|
+
data
|
|
8332
|
+
);
|
|
8272
8333
|
return { response: data, error: null };
|
|
8273
8334
|
} catch (error) {
|
|
8274
8335
|
const cached = readCachedCompatibility(
|
|
@@ -8277,6 +8338,13 @@ async function checkSdkCompatibility(baseUrl, options = {}) {
|
|
|
8277
8338
|
options.skillsVersion
|
|
8278
8339
|
);
|
|
8279
8340
|
if (cached) {
|
|
8341
|
+
if (options.timeoutMs !== void 0 && options.timeoutMs < CHECK_TIMEOUT_MS) {
|
|
8342
|
+
invalidateCachedCompatibility(
|
|
8343
|
+
baseUrl,
|
|
8344
|
+
options.command,
|
|
8345
|
+
options.skillsVersion
|
|
8346
|
+
);
|
|
8347
|
+
}
|
|
8280
8348
|
return { response: cached, error: null };
|
|
8281
8349
|
}
|
|
8282
8350
|
return {
|
|
@@ -35166,7 +35234,19 @@ function renderMonitorGet(payload) {
|
|
|
35166
35234
|
const field = asRecord2(value);
|
|
35167
35235
|
const path = asString(field?.path);
|
|
35168
35236
|
const description = asString(field?.description);
|
|
35169
|
-
|
|
35237
|
+
const semantics = asString(field?.semantics);
|
|
35238
|
+
const applicability = asString(field?.applicability);
|
|
35239
|
+
const grammar = asRecord2(field?.grammar);
|
|
35240
|
+
const grammarSyntax = asString(grammar?.syntax);
|
|
35241
|
+
return path ? [
|
|
35242
|
+
{
|
|
35243
|
+
path,
|
|
35244
|
+
description,
|
|
35245
|
+
semantics,
|
|
35246
|
+
applicability,
|
|
35247
|
+
grammarSyntax
|
|
35248
|
+
}
|
|
35249
|
+
] : [];
|
|
35170
35250
|
}) : [];
|
|
35171
35251
|
if (specFields.length > 0) {
|
|
35172
35252
|
lines.push("", "Monitor spec:");
|
|
@@ -35174,6 +35254,15 @@ function renderMonitorGet(payload) {
|
|
|
35174
35254
|
lines.push(
|
|
35175
35255
|
` ${field.path}${field.description ? ` \u2014 ${field.description}` : ""}`
|
|
35176
35256
|
);
|
|
35257
|
+
if (field.semantics && field.semantics !== field.description) {
|
|
35258
|
+
lines.push(` Behavior: ${field.semantics}`);
|
|
35259
|
+
}
|
|
35260
|
+
if (field.applicability) {
|
|
35261
|
+
lines.push(` Applies to: ${field.applicability}`);
|
|
35262
|
+
}
|
|
35263
|
+
if (field.grammarSyntax) {
|
|
35264
|
+
lines.push(` Format: ${field.grammarSyntax}`);
|
|
35265
|
+
}
|
|
35177
35266
|
}
|
|
35178
35267
|
}
|
|
35179
35268
|
lines.push("", `Current SQL listener consumers (${boundPlays.length}):`);
|
|
@@ -35938,8 +36027,10 @@ Notes:
|
|
|
35938
36027
|
Read-only. Returns the exact editable definition, selected Deepline pricing,
|
|
35939
36028
|
billing state, output streams, dependent published plays, and monitor_spec.
|
|
35940
36029
|
When monitor_spec.available is true, its fields describe the deployed type's
|
|
35941
|
-
editable fields
|
|
35942
|
-
|
|
36030
|
+
editable fields, constraints, and provider-specific behavior. For TAMRadar,
|
|
36031
|
+
this includes the effective updates_since precision and engagement timing
|
|
36032
|
+
rules. Otherwise use the stored definition and check before proposing an
|
|
36033
|
+
update so scope and downstream effects are visible.
|
|
35943
36034
|
|
|
35944
36035
|
Examples:
|
|
35945
36036
|
deepline monitors get my-monitor --json
|
|
@@ -38329,13 +38420,12 @@ function buildSkillsAddArgs(baseUrl, skillName, options = {}) {
|
|
|
38329
38420
|
import { spawn as spawn2, spawnSync } from "child_process";
|
|
38330
38421
|
import { randomUUID as randomUUID7 } from "crypto";
|
|
38331
38422
|
import {
|
|
38423
|
+
appendFileSync,
|
|
38332
38424
|
existsSync as existsSync13,
|
|
38333
38425
|
mkdirSync as mkdirSync10,
|
|
38334
|
-
readdirSync as readdirSync4,
|
|
38335
38426
|
readFileSync as readFileSync14,
|
|
38336
38427
|
renameSync,
|
|
38337
|
-
|
|
38338
|
-
statSync as statSync5,
|
|
38428
|
+
rmSync as rmSync5,
|
|
38339
38429
|
unlinkSync as unlinkSync2,
|
|
38340
38430
|
writeFileSync as writeFileSync14
|
|
38341
38431
|
} from "fs";
|
|
@@ -38694,7 +38784,6 @@ async function maybeReportSdkCliFailure(input2) {
|
|
|
38694
38784
|
|
|
38695
38785
|
// src/cli/skills-sync.ts
|
|
38696
38786
|
var CHECK_TIMEOUT_MS2 = 3e3;
|
|
38697
|
-
var SKILLS_SYNC_CLAIM_MAX_AGE_MS = 60 * 60 * 1e3;
|
|
38698
38787
|
function shouldSkipSkillsSync() {
|
|
38699
38788
|
if (detectAgentRuntime() === "claude_cowork") {
|
|
38700
38789
|
return true;
|
|
@@ -38705,65 +38794,286 @@ function shouldSkipSkillsSync() {
|
|
|
38705
38794
|
function unavailableSkillsNoticePath(baseUrl) {
|
|
38706
38795
|
return join15(sdkCliStateDirPath(baseUrl), "skills-sync-unavailable-version");
|
|
38707
38796
|
}
|
|
38708
|
-
|
|
38797
|
+
var SKILLS_SYNC_IN_PROGRESS_TTL_MS = 10 * 60 * 1e3;
|
|
38798
|
+
var SKILLS_SYNC_IN_PROGRESS_PID_CAP_MS = 6 * 60 * 60 * 1e3;
|
|
38799
|
+
var agentLeaseSegment = skillsAgentPathSegment;
|
|
38800
|
+
function sortedLeaseAgents(agents) {
|
|
38801
|
+
const expanded = agents.includes("*") ? [...agents, ...KNOWN_SKILL_AGENTS] : agents;
|
|
38802
|
+
return [...new Set(expanded)].sort((a, b) => a.localeCompare(b));
|
|
38803
|
+
}
|
|
38804
|
+
function inProgressSkillsSyncPath(baseUrl, agent) {
|
|
38709
38805
|
return join15(
|
|
38710
38806
|
sdkCliStateDirPath(baseUrl),
|
|
38711
|
-
`skills-sync-
|
|
38807
|
+
`skills-sync-in-progress-${agentLeaseSegment(agent)}`
|
|
38712
38808
|
);
|
|
38713
38809
|
}
|
|
38714
|
-
function
|
|
38715
|
-
|
|
38716
|
-
|
|
38717
|
-
|
|
38810
|
+
function readInProgressSkillsSyncLeaseFromDir(dir) {
|
|
38811
|
+
const claim = readMarkedSkillsSyncVersion(join15(dir, "claim"));
|
|
38812
|
+
const [version = "", startedAt = ""] = claim.split(" ");
|
|
38813
|
+
const pidRaw = readMarkedSkillsSyncVersion(join15(dir, "pid"));
|
|
38814
|
+
return {
|
|
38815
|
+
claimToken: version && startedAt ? `${version} ${startedAt}` : "",
|
|
38816
|
+
version,
|
|
38817
|
+
startedAt: Number(startedAt),
|
|
38818
|
+
pid: /^\d+$/.test(pidRaw) ? Number(pidRaw) : null,
|
|
38819
|
+
owner: readMarkedSkillsSyncVersion(join15(dir, "owner"))
|
|
38820
|
+
};
|
|
38821
|
+
}
|
|
38822
|
+
function readInProgressSkillsSyncLease(baseUrl, agent) {
|
|
38823
|
+
return readInProgressSkillsSyncLeaseFromDir(
|
|
38824
|
+
inProgressSkillsSyncPath(baseUrl, agent)
|
|
38825
|
+
);
|
|
38826
|
+
}
|
|
38827
|
+
function readInProgressSkillsSyncLeases(baseUrl, agents) {
|
|
38828
|
+
return new Map(
|
|
38829
|
+
sortedLeaseAgents(agents).map((agent) => [
|
|
38830
|
+
agent,
|
|
38831
|
+
readInProgressSkillsSyncLease(baseUrl, agent)
|
|
38832
|
+
])
|
|
38718
38833
|
);
|
|
38719
38834
|
}
|
|
38720
|
-
|
|
38835
|
+
var UNRESOLVED_SKILLS_CLAIM_VERSION = "unresolved";
|
|
38836
|
+
function claimedSkillsVersion(leases) {
|
|
38837
|
+
for (const lease of leases.values()) {
|
|
38838
|
+
if (lease.version && lease.version !== UNRESOLVED_SKILLS_CLAIM_VERSION) {
|
|
38839
|
+
return lease.version;
|
|
38840
|
+
}
|
|
38841
|
+
}
|
|
38842
|
+
return "";
|
|
38843
|
+
}
|
|
38844
|
+
function isProcessAlive(pid) {
|
|
38721
38845
|
try {
|
|
38722
|
-
|
|
38723
|
-
|
|
38724
|
-
} catch {
|
|
38846
|
+
process.kill(pid, 0);
|
|
38847
|
+
return true;
|
|
38848
|
+
} catch (error) {
|
|
38849
|
+
return error.code === "EPERM";
|
|
38725
38850
|
}
|
|
38726
38851
|
}
|
|
38727
|
-
function
|
|
38728
|
-
|
|
38852
|
+
function isFreshInProgressSkillsSync(lease, now = Date.now()) {
|
|
38853
|
+
if (!Number.isFinite(lease.startedAt)) return false;
|
|
38854
|
+
const age = now - lease.startedAt;
|
|
38855
|
+
if (age < 0) return false;
|
|
38856
|
+
if (lease.pid !== null && isProcessAlive(lease.pid)) {
|
|
38857
|
+
return age < SKILLS_SYNC_IN_PROGRESS_PID_CAP_MS;
|
|
38858
|
+
}
|
|
38859
|
+
return age < SKILLS_SYNC_IN_PROGRESS_TTL_MS;
|
|
38860
|
+
}
|
|
38861
|
+
function quarantine(path, tag) {
|
|
38862
|
+
const holding = `${path}.${tag}-${process.pid}-${Date.now()}`;
|
|
38729
38863
|
try {
|
|
38730
|
-
|
|
38864
|
+
renameSync(path, holding);
|
|
38865
|
+
return holding;
|
|
38731
38866
|
} catch {
|
|
38732
|
-
return
|
|
38867
|
+
return null;
|
|
38733
38868
|
}
|
|
38734
|
-
|
|
38735
|
-
|
|
38736
|
-
|
|
38869
|
+
}
|
|
38870
|
+
function claimOneInProgressSkillsSync(baseUrl, remoteVersion, agent, owner) {
|
|
38871
|
+
const dir = inProgressSkillsSyncPath(baseUrl, agent);
|
|
38872
|
+
const errorCode = (error) => error.code;
|
|
38873
|
+
const create = () => {
|
|
38874
|
+
const claimToken = `${remoteVersion} ${Date.now()}`;
|
|
38875
|
+
const staging = `${dir}.staging-${process.pid}-${Date.now()}`;
|
|
38876
|
+
mkdirSync10(staging);
|
|
38877
|
+
writeFileSync14(join15(staging, "claim"), `${claimToken}
|
|
38878
|
+
`, "utf-8");
|
|
38879
|
+
writeFileSync14(join15(staging, "owner"), `${owner}
|
|
38880
|
+
`, "utf-8");
|
|
38737
38881
|
try {
|
|
38738
|
-
|
|
38739
|
-
|
|
38740
|
-
|
|
38741
|
-
|
|
38742
|
-
|
|
38743
|
-
|
|
38744
|
-
|
|
38882
|
+
renameSync(staging, dir);
|
|
38883
|
+
} catch (error) {
|
|
38884
|
+
rmSync5(staging, { recursive: true, force: true });
|
|
38885
|
+
const code = errorCode(error);
|
|
38886
|
+
const err = new Error("lease directory already exists");
|
|
38887
|
+
err.code = code === "EEXIST" || code === "ENOTEMPTY" ? "EEXIST" : String(code ?? "");
|
|
38888
|
+
throw err;
|
|
38889
|
+
}
|
|
38890
|
+
return { state: "claimed", claimToken };
|
|
38891
|
+
};
|
|
38892
|
+
try {
|
|
38893
|
+
mkdirSync10(dirname14(dir), { recursive: true });
|
|
38894
|
+
return create();
|
|
38895
|
+
} catch (error) {
|
|
38896
|
+
if (errorCode(error) !== "EEXIST") return { state: "unavailable" };
|
|
38897
|
+
}
|
|
38898
|
+
if (isFreshInProgressSkillsSync(readInProgressSkillsSyncLease(baseUrl, agent))) {
|
|
38899
|
+
return { state: "held" };
|
|
38900
|
+
}
|
|
38901
|
+
const tombstone = quarantine(dir, "stale");
|
|
38902
|
+
if (!tombstone) {
|
|
38903
|
+
return { state: "held" };
|
|
38904
|
+
}
|
|
38905
|
+
rmSync5(tombstone, { recursive: true, force: true });
|
|
38906
|
+
try {
|
|
38907
|
+
return create();
|
|
38908
|
+
} catch (error) {
|
|
38909
|
+
return errorCode(error) === "EEXIST" ? { state: "held" } : { state: "unavailable" };
|
|
38910
|
+
}
|
|
38911
|
+
}
|
|
38912
|
+
function claimInProgressSkillsSync(baseUrl, remoteVersion, agents) {
|
|
38913
|
+
const claimTokens = /* @__PURE__ */ new Map();
|
|
38914
|
+
const owner = randomUUID7();
|
|
38915
|
+
for (const agent of sortedLeaseAgents(agents)) {
|
|
38916
|
+
const claim = claimOneInProgressSkillsSync(
|
|
38917
|
+
baseUrl,
|
|
38918
|
+
remoteVersion,
|
|
38919
|
+
agent,
|
|
38920
|
+
owner
|
|
38921
|
+
);
|
|
38922
|
+
if (claim.state !== "claimed") {
|
|
38923
|
+
releaseInProgressSkillsSync(baseUrl, claimTokens);
|
|
38924
|
+
return { state: claim.state };
|
|
38925
|
+
}
|
|
38926
|
+
claimTokens.set(agent, claim.claimToken);
|
|
38927
|
+
}
|
|
38928
|
+
return { state: "claimed", claimTokens, owner };
|
|
38929
|
+
}
|
|
38930
|
+
function claimAndSpawnDetachedSkillsSync(baseUrl, agents, remoteVersion, spawnDetached) {
|
|
38931
|
+
const claim = claimInProgressSkillsSync(baseUrl, remoteVersion, agents);
|
|
38932
|
+
if (claim.state !== "claimed") return claim.state;
|
|
38933
|
+
const { claimTokens, owner } = claim;
|
|
38934
|
+
spawnDetached([SKILLS_AUTO_SYNC_COMMAND, "--claim", owner], () => {
|
|
38935
|
+
releaseInProgressSkillsSync(baseUrl, claimTokens);
|
|
38936
|
+
if (remoteVersion !== UNRESOLVED_SKILLS_CLAIM_VERSION) {
|
|
38937
|
+
markFailedSkillsSync(baseUrl, remoteVersion, agents);
|
|
38745
38938
|
}
|
|
38746
|
-
|
|
38939
|
+
deferSkillsNotice(
|
|
38940
|
+
baseUrl,
|
|
38941
|
+
agents
|
|
38942
|
+
)(
|
|
38943
|
+
"Deepline skills refresh failed to start; run `deepline skills` to retry."
|
|
38944
|
+
);
|
|
38945
|
+
});
|
|
38946
|
+
return "claimed";
|
|
38947
|
+
}
|
|
38948
|
+
function recordOwnPidOnInProgressSkillsSync(baseUrl, leases) {
|
|
38949
|
+
for (const [agent, lease] of leases) {
|
|
38950
|
+
if (!lease.claimToken) continue;
|
|
38747
38951
|
try {
|
|
38748
|
-
|
|
38749
|
-
|
|
38952
|
+
writeFileSync14(
|
|
38953
|
+
join15(inProgressSkillsSyncPath(baseUrl, agent), "pid"),
|
|
38954
|
+
`${process.pid}
|
|
38955
|
+
`,
|
|
38956
|
+
"utf-8"
|
|
38957
|
+
);
|
|
38958
|
+
} catch {
|
|
38959
|
+
}
|
|
38960
|
+
}
|
|
38961
|
+
}
|
|
38962
|
+
function releaseInProgressSkillsSync(baseUrl, claimTokens) {
|
|
38963
|
+
for (const [agent, claimToken] of claimTokens) {
|
|
38964
|
+
const dir = inProgressSkillsSyncPath(baseUrl, agent);
|
|
38965
|
+
if (!claimToken) {
|
|
38966
|
+
try {
|
|
38967
|
+
rmSync5(dir, { recursive: true, force: true });
|
|
38968
|
+
} catch {
|
|
38750
38969
|
}
|
|
38751
|
-
|
|
38752
|
-
|
|
38753
|
-
|
|
38970
|
+
continue;
|
|
38971
|
+
}
|
|
38972
|
+
const tombstone = quarantine(dir, "release");
|
|
38973
|
+
if (!tombstone) continue;
|
|
38974
|
+
try {
|
|
38975
|
+
if (readInProgressSkillsSyncLeaseFromDir(tombstone).claimToken !== claimToken) {
|
|
38976
|
+
renameSync(tombstone, dir);
|
|
38754
38977
|
continue;
|
|
38755
38978
|
}
|
|
38756
|
-
if (owners.length !== 1) return { status: "held" };
|
|
38757
|
-
renameSync(path, `${path}-stale-${owners[0]}`);
|
|
38758
38979
|
} catch {
|
|
38759
|
-
|
|
38980
|
+
}
|
|
38981
|
+
rmSync5(tombstone, { recursive: true, force: true });
|
|
38982
|
+
}
|
|
38983
|
+
}
|
|
38984
|
+
function claimTokensOf(leases) {
|
|
38985
|
+
return new Map(
|
|
38986
|
+
[...leases].map(([agent, lease]) => [agent, lease.claimToken])
|
|
38987
|
+
);
|
|
38988
|
+
}
|
|
38989
|
+
async function acquireSkillsInstallLease(baseUrl, agents, version, options = {
|
|
38990
|
+
waitMs: 9e4
|
|
38991
|
+
}) {
|
|
38992
|
+
const pollMs = options.pollMs ?? 250;
|
|
38993
|
+
const deadline = Date.now() + options.waitMs;
|
|
38994
|
+
let waited = false;
|
|
38995
|
+
for (; ; ) {
|
|
38996
|
+
const claim = claimInProgressSkillsSync(baseUrl, version, agents);
|
|
38997
|
+
if (claim.state === "unavailable") {
|
|
38998
|
+
return { release: () => {
|
|
38999
|
+
} };
|
|
39000
|
+
}
|
|
39001
|
+
if (claim.state === "claimed") {
|
|
39002
|
+
recordOwnPidOnInProgressSkillsSync(
|
|
39003
|
+
baseUrl,
|
|
39004
|
+
readInProgressSkillsSyncLeases(baseUrl, agents)
|
|
39005
|
+
);
|
|
39006
|
+
return {
|
|
39007
|
+
release: () => releaseInProgressSkillsSync(baseUrl, claim.claimTokens)
|
|
39008
|
+
};
|
|
39009
|
+
}
|
|
39010
|
+
if (Date.now() >= deadline) return null;
|
|
39011
|
+
if (!waited) {
|
|
39012
|
+
waited = true;
|
|
39013
|
+
options.onWait?.();
|
|
39014
|
+
}
|
|
39015
|
+
await new Promise((resolve21) => setTimeout(resolve21, pollMs));
|
|
39016
|
+
}
|
|
39017
|
+
}
|
|
39018
|
+
function skillsInstallLeasePath(baseUrl, agents) {
|
|
39019
|
+
return sortedLeaseAgents(agents).map((agent) => inProgressSkillsSyncPath(baseUrl, agent)).join(", ");
|
|
39020
|
+
}
|
|
39021
|
+
function deferredSkillsNoticePath(baseUrl, agents) {
|
|
39022
|
+
return join15(
|
|
39023
|
+
sdkCliStateDirPath(baseUrl),
|
|
39024
|
+
`skills-sync-notice-${sortedLeaseAgents(agents).map(agentLeaseSegment).join("-")}`
|
|
39025
|
+
);
|
|
39026
|
+
}
|
|
39027
|
+
function deferSkillsNotice(baseUrl, agents) {
|
|
39028
|
+
const path = deferredSkillsNoticePath(baseUrl, agents);
|
|
39029
|
+
return (text) => {
|
|
39030
|
+
try {
|
|
39031
|
+
mkdirSync10(dirname14(path), { recursive: true });
|
|
39032
|
+
appendFileSync(path, `${text.trimEnd()}
|
|
39033
|
+
`, "utf-8");
|
|
39034
|
+
} catch {
|
|
39035
|
+
}
|
|
39036
|
+
};
|
|
39037
|
+
}
|
|
39038
|
+
function flushDeferredSkillsNotices(baseUrl, agents) {
|
|
39039
|
+
const path = deferredSkillsNoticePath(baseUrl, agents);
|
|
39040
|
+
if (!existsSync13(path)) return;
|
|
39041
|
+
const tombstone = quarantine(path, "consuming");
|
|
39042
|
+
if (!tombstone) return;
|
|
39043
|
+
let text = "";
|
|
39044
|
+
try {
|
|
39045
|
+
text = readFileSync14(tombstone, "utf-8");
|
|
39046
|
+
} catch {
|
|
39047
|
+
return;
|
|
39048
|
+
} finally {
|
|
39049
|
+
try {
|
|
39050
|
+
unlinkSync2(tombstone);
|
|
39051
|
+
} catch {
|
|
38760
39052
|
}
|
|
38761
39053
|
}
|
|
38762
|
-
|
|
39054
|
+
if (text.trim()) writeSdkSkillsStatusLine(text.trimEnd());
|
|
39055
|
+
}
|
|
39056
|
+
function flushDeferredSkillsSyncNotices(baseUrl) {
|
|
39057
|
+
if (shouldSkipSkillsSync() || hasActivePluginSkills()) return;
|
|
39058
|
+
const agents = resolveAutoSyncSkillAgents();
|
|
39059
|
+
if (agents.length === 0) return;
|
|
39060
|
+
flushDeferredSkillsNotices(baseUrl, agents);
|
|
39061
|
+
}
|
|
39062
|
+
var SKILLS_AUTO_SYNC_COMMAND = "skills-auto-sync";
|
|
39063
|
+
function spawnDetachedSkillsSyncChild(argv, onSpawnError) {
|
|
39064
|
+
const child = spawn2(process.execPath, [process.argv[1] ?? "", ...argv], {
|
|
39065
|
+
detached: true,
|
|
39066
|
+
stdio: "ignore",
|
|
39067
|
+
env: process.env
|
|
39068
|
+
});
|
|
39069
|
+
child.on("error", () => onSpawnError?.());
|
|
39070
|
+
child.unref();
|
|
38763
39071
|
}
|
|
38764
|
-
function
|
|
38765
|
-
|
|
38766
|
-
|
|
39072
|
+
function failedSkillsSyncPath(baseUrl, agents) {
|
|
39073
|
+
return join15(
|
|
39074
|
+
sdkCliStateDirPath(baseUrl),
|
|
39075
|
+
`skills-sync-failed-${agents.map(agentLeaseSegment).join("-")}-version`
|
|
39076
|
+
);
|
|
38767
39077
|
}
|
|
38768
39078
|
function hasMarkedSkillsSyncVersion(path, version) {
|
|
38769
39079
|
return Boolean(version) && readMarkedSkillsSyncVersion(path) === version;
|
|
@@ -38785,12 +39095,12 @@ function writeMarkedSkillsSyncVersion(path, version) {
|
|
|
38785
39095
|
return false;
|
|
38786
39096
|
}
|
|
38787
39097
|
}
|
|
38788
|
-
function writeUnavailableSkillsNotice(baseUrl, remoteVersion, skillNames) {
|
|
39098
|
+
function writeUnavailableSkillsNotice(baseUrl, remoteVersion, skillNames, notice = writeSdkSkillsStatusLine) {
|
|
38789
39099
|
const path = unavailableSkillsNoticePath(baseUrl);
|
|
38790
39100
|
if (hasMarkedSkillsSyncVersion(path, remoteVersion)) return;
|
|
38791
39101
|
writeMarkedSkillsSyncVersion(path, remoteVersion);
|
|
38792
39102
|
const manualCommand = `npx ${buildSkillsInstallArgs(baseUrl, skillNames).join(" ")}`;
|
|
38793
|
-
|
|
39103
|
+
notice(
|
|
38794
39104
|
`Deepline agent skills are out of date, but neither \`bunx\` nor \`npx\` is available. Install Node.js/npm or Bun, then run:
|
|
38795
39105
|
${manualCommand}`
|
|
38796
39106
|
);
|
|
@@ -38975,7 +39285,7 @@ function runOneSkillsInstall(install) {
|
|
|
38975
39285
|
});
|
|
38976
39286
|
});
|
|
38977
39287
|
}
|
|
38978
|
-
async function runSkillsInstall(installs, agents) {
|
|
39288
|
+
async function runSkillsInstall(installs, agents, notice = writeSdkSkillsStatusLine) {
|
|
38979
39289
|
const failures = [];
|
|
38980
39290
|
for (const install of installs) {
|
|
38981
39291
|
const result = await runOneSkillsInstall(install);
|
|
@@ -38985,15 +39295,14 @@ async function runSkillsInstall(installs, agents) {
|
|
|
38985
39295
|
const details = failures.map((failure) => failure.detail).filter(Boolean).join("\n");
|
|
38986
39296
|
const attemptedCommands = failures.map((failure) => ` ${failure.manualCommand}`).join("\n");
|
|
38987
39297
|
const retryAgent = agents.at(0);
|
|
38988
|
-
|
|
39298
|
+
notice(
|
|
38989
39299
|
`Deepline agent-skills refresh failed for ${agents.join(", ")}. The Deepline command will continue; this only affects optional local agent instructions, not authentication, data, or billing.
|
|
38990
39300
|
` + (attemptedCommands ? `Attempted installer command${failures.length === 1 ? "" : "s"}:
|
|
38991
39301
|
${attemptedCommands}
|
|
38992
39302
|
` : "") + (details ? `Installer output:
|
|
38993
39303
|
${details}
|
|
38994
39304
|
` : "") + (retryAgent ? `To retry with full installer output: deepline skills --agent ${retryAgent} --json
|
|
38995
|
-
` : "") + `To temporarily suppress automatic skills sync: ${temporarySkillsSyncSkipCommand()}
|
|
38996
|
-
`
|
|
39305
|
+
` : "") + `To temporarily suppress automatic skills sync: ${temporarySkillsSyncSkipCommand()}`
|
|
38997
39306
|
);
|
|
38998
39307
|
return {
|
|
38999
39308
|
installed: false,
|
|
@@ -39068,72 +39377,132 @@ async function syncSdkSkillsIfNeeded(baseUrl, options = {}) {
|
|
|
39068
39377
|
if (usingPluginSkills) {
|
|
39069
39378
|
return;
|
|
39070
39379
|
}
|
|
39071
|
-
const localVersion = readSdkSkillsLocalVersion(baseUrl);
|
|
39072
|
-
const update = options.update === void 0 ? await fetchSkillsUpdate(baseUrl, localVersion) : options.update ? {
|
|
39073
|
-
needsUpdate: options.update.needs_update,
|
|
39074
|
-
remoteVersion: options.update.remote.version
|
|
39075
|
-
} : null;
|
|
39076
|
-
if (!update?.needsUpdate || !update.remoteVersion) {
|
|
39077
|
-
return;
|
|
39078
|
-
}
|
|
39079
39380
|
const agents = resolveAutoSyncSkillAgents();
|
|
39080
|
-
if (
|
|
39381
|
+
if (options.mode === "detached" && agents.length > 0) {
|
|
39382
|
+
flushDeferredSkillsNotices(baseUrl, agents);
|
|
39383
|
+
}
|
|
39384
|
+
const ownsInProgressMarker = options.mode !== "detached" && agents.length > 0 && Boolean(options.claim);
|
|
39385
|
+
const leases = ownsInProgressMarker ? readInProgressSkillsSyncLeases(baseUrl, agents) : null;
|
|
39386
|
+
if (leases && [...leases.values()].some((lease) => lease.owner !== options.claim)) {
|
|
39081
39387
|
return;
|
|
39082
39388
|
}
|
|
39389
|
+
if (leases) recordOwnPidOnInProgressSkillsSync(baseUrl, leases);
|
|
39390
|
+
const claimedVersion = leases ? claimedSkillsVersion(leases) : "";
|
|
39391
|
+
if (options.mode === "detached" && agents.length > 0 && options.update === void 0 && !claimedVersion) {
|
|
39392
|
+
const outcome = claimAndSpawnDetachedSkillsSync(
|
|
39393
|
+
baseUrl,
|
|
39394
|
+
agents,
|
|
39395
|
+
UNRESOLVED_SKILLS_CLAIM_VERSION,
|
|
39396
|
+
options.spawnDetached ?? spawnDetachedSkillsSyncChild
|
|
39397
|
+
);
|
|
39398
|
+
if (outcome !== "unavailable") return;
|
|
39399
|
+
}
|
|
39400
|
+
try {
|
|
39401
|
+
const localVersion = readSdkSkillsLocalVersion(baseUrl);
|
|
39402
|
+
const update = options.update === void 0 ? claimedVersion ? { needsUpdate: true, remoteVersion: claimedVersion } : await fetchSkillsUpdate(baseUrl, localVersion) : options.update ? {
|
|
39403
|
+
needsUpdate: options.update.needs_update,
|
|
39404
|
+
remoteVersion: options.update.remote.version
|
|
39405
|
+
} : null;
|
|
39406
|
+
if (!update?.needsUpdate || !update.remoteVersion) {
|
|
39407
|
+
return;
|
|
39408
|
+
}
|
|
39409
|
+
if (agents.length > 0 && hasFailedSkillsSync(baseUrl, update.remoteVersion, agents)) {
|
|
39410
|
+
return;
|
|
39411
|
+
}
|
|
39412
|
+
if (options.mode === "detached" && agents.length === 0) {
|
|
39413
|
+
writeUnavailableSkillsNotice(
|
|
39414
|
+
baseUrl,
|
|
39415
|
+
update.remoteVersion,
|
|
39416
|
+
buildSdkSkillNames(DEFAULT_SDK_SKILL_NAMES)
|
|
39417
|
+
);
|
|
39418
|
+
return;
|
|
39419
|
+
}
|
|
39420
|
+
if (options.mode === "detached" && agents.length > 0) {
|
|
39421
|
+
const outcome = claimAndSpawnDetachedSkillsSync(
|
|
39422
|
+
baseUrl,
|
|
39423
|
+
agents,
|
|
39424
|
+
update.remoteVersion,
|
|
39425
|
+
options.spawnDetached ?? spawnDetachedSkillsSyncChild
|
|
39426
|
+
);
|
|
39427
|
+
if (outcome === "held") return;
|
|
39428
|
+
if (outcome === "claimed") {
|
|
39429
|
+
writeSdkSkillsStatusLine(
|
|
39430
|
+
"Deepline skills changed; refreshing agent skills in the background."
|
|
39431
|
+
);
|
|
39432
|
+
return;
|
|
39433
|
+
}
|
|
39434
|
+
}
|
|
39435
|
+
await runInlineSkillsSync(
|
|
39436
|
+
baseUrl,
|
|
39437
|
+
update.remoteVersion,
|
|
39438
|
+
agents,
|
|
39439
|
+
options.notices ?? "print"
|
|
39440
|
+
);
|
|
39441
|
+
} finally {
|
|
39442
|
+
if (leases) {
|
|
39443
|
+
releaseInProgressSkillsSync(baseUrl, claimTokensOf(leases));
|
|
39444
|
+
}
|
|
39445
|
+
}
|
|
39446
|
+
}
|
|
39447
|
+
async function runInlineSkillsSync(baseUrl, remoteVersion, agents, notices) {
|
|
39448
|
+
const update = { remoteVersion };
|
|
39449
|
+
const notice = notices === "defer" ? deferSkillsNotice(baseUrl, agents) : writeSdkSkillsStatusLine;
|
|
39083
39450
|
const remoteSkillNames = await fetchV1SkillNames(baseUrl);
|
|
39084
39451
|
const skillNames = buildSdkSkillNames(
|
|
39085
39452
|
remoteSkillNames.length > 0 ? remoteSkillNames : DEFAULT_SDK_SKILL_NAMES
|
|
39086
39453
|
);
|
|
39087
39454
|
if (skillNames.length === 0) return;
|
|
39088
39455
|
if (agents.length === 0) {
|
|
39089
|
-
writeUnavailableSkillsNotice(
|
|
39456
|
+
writeUnavailableSkillsNotice(
|
|
39457
|
+
baseUrl,
|
|
39458
|
+
update.remoteVersion,
|
|
39459
|
+
skillNames,
|
|
39460
|
+
notice
|
|
39461
|
+
);
|
|
39090
39462
|
return;
|
|
39091
39463
|
}
|
|
39092
39464
|
const installs = resolveSkillsInstallCommands(baseUrl, skillNames, agents);
|
|
39093
39465
|
if (installs.length === 0) {
|
|
39094
|
-
writeUnavailableSkillsNotice(
|
|
39466
|
+
writeUnavailableSkillsNotice(
|
|
39467
|
+
baseUrl,
|
|
39468
|
+
update.remoteVersion,
|
|
39469
|
+
skillNames,
|
|
39470
|
+
notice
|
|
39471
|
+
);
|
|
39095
39472
|
return;
|
|
39096
39473
|
}
|
|
39097
|
-
|
|
39098
|
-
if (claim.status === "held") return;
|
|
39099
|
-
try {
|
|
39100
|
-
if (hasFailedSkillsSync(baseUrl, update.remoteVersion, agents) || readSdkSkillsLocalVersion(baseUrl) === update.remoteVersion) {
|
|
39101
|
-
return;
|
|
39102
|
-
}
|
|
39474
|
+
if (notices === "print") {
|
|
39103
39475
|
writeSdkSkillsStatusLine(
|
|
39104
39476
|
"Deepline skills changed; syncing agent skills..."
|
|
39105
39477
|
);
|
|
39106
|
-
const installResult = await runSkillsInstall(installs, agents);
|
|
39107
|
-
if (!installResult.installed) {
|
|
39108
|
-
const markerWritten = markFailedSkillsSync(
|
|
39109
|
-
baseUrl,
|
|
39110
|
-
update.remoteVersion,
|
|
39111
|
-
agents
|
|
39112
|
-
);
|
|
39113
|
-
void maybeReportAutomaticSkillsSyncFailure({
|
|
39114
|
-
baseUrl,
|
|
39115
|
-
remoteSkillsVersion: update.remoteVersion,
|
|
39116
|
-
agents,
|
|
39117
|
-
skillsPackage: SKILLS_NPX_PACKAGE,
|
|
39118
|
-
targetSkillCount: skillNames.length,
|
|
39119
|
-
markerWritten,
|
|
39120
|
-
attempts: installResult.attempts
|
|
39121
|
-
});
|
|
39122
|
-
return;
|
|
39123
|
-
}
|
|
39124
|
-
runLegacySkillsCleanup(agents);
|
|
39125
|
-
writeSdkSkillsLocalVersion(baseUrl, update.remoteVersion, agents);
|
|
39126
|
-
clearUnavailableSkillsNotice(baseUrl);
|
|
39127
|
-
clearFailedSkillsSync(baseUrl, agents);
|
|
39128
|
-
writeSdkSkillsStatusLine("Deepline agent skills are up to date.");
|
|
39129
|
-
} finally {
|
|
39130
|
-
if (claim.status === "claimed") {
|
|
39131
|
-
clearSkillsSyncClaim(baseUrl, agents, claim.token);
|
|
39132
|
-
}
|
|
39133
39478
|
}
|
|
39479
|
+
const installResult = await runSkillsInstall(installs, agents, notice);
|
|
39480
|
+
if (!installResult.installed) {
|
|
39481
|
+
const markerWritten = markFailedSkillsSync(
|
|
39482
|
+
baseUrl,
|
|
39483
|
+
update.remoteVersion,
|
|
39484
|
+
agents
|
|
39485
|
+
);
|
|
39486
|
+
void maybeReportAutomaticSkillsSyncFailure({
|
|
39487
|
+
baseUrl,
|
|
39488
|
+
remoteSkillsVersion: update.remoteVersion,
|
|
39489
|
+
agents,
|
|
39490
|
+
skillsPackage: SKILLS_NPX_PACKAGE,
|
|
39491
|
+
targetSkillCount: skillNames.length,
|
|
39492
|
+
markerWritten,
|
|
39493
|
+
attempts: installResult.attempts
|
|
39494
|
+
});
|
|
39495
|
+
return;
|
|
39496
|
+
}
|
|
39497
|
+
runLegacySkillsCleanup(agents);
|
|
39498
|
+
writeSdkSkillsLocalVersion(baseUrl, update.remoteVersion, agents);
|
|
39499
|
+
clearUnavailableSkillsNotice(baseUrl);
|
|
39500
|
+
clearFailedSkillsSync(baseUrl, agents);
|
|
39501
|
+
notice("Deepline agent skills are up to date.");
|
|
39134
39502
|
}
|
|
39135
39503
|
|
|
39136
39504
|
// src/cli/commands/skills.ts
|
|
39505
|
+
var SKILLS_INSTALL_LEASE_WAIT_MS = 9e4;
|
|
39137
39506
|
var SKILLS_PROCESS_TIMEOUT_MS = 45e3;
|
|
39138
39507
|
var RUNTIME_TO_SKILLS_AGENT = {
|
|
39139
39508
|
antigravity: "antigravity",
|
|
@@ -39390,6 +39759,45 @@ async function runSkillsCommand(options, dependencies = {}) {
|
|
|
39390
39759
|
)
|
|
39391
39760
|
]);
|
|
39392
39761
|
}
|
|
39762
|
+
const lease = scope === "global" ? await acquireSkillsInstallLease(baseUrl, agents, plan.version, {
|
|
39763
|
+
waitMs: dependencies.installLeaseWaitMs ?? SKILLS_INSTALL_LEASE_WAIT_MS,
|
|
39764
|
+
onWait: () => process.stderr.write(
|
|
39765
|
+
"Waiting for a background Deepline skills refresh to finish...\n"
|
|
39766
|
+
)
|
|
39767
|
+
}) : { release: () => {
|
|
39768
|
+
} };
|
|
39769
|
+
if (!lease) {
|
|
39770
|
+
printCommandEnvelope(
|
|
39771
|
+
{
|
|
39772
|
+
ok: false,
|
|
39773
|
+
status: "failed",
|
|
39774
|
+
code: "SKILLS_SYNC_IN_PROGRESS",
|
|
39775
|
+
exitCode: 7,
|
|
39776
|
+
scope,
|
|
39777
|
+
agents,
|
|
39778
|
+
message: "A background Deepline skills refresh is still running for these agents.",
|
|
39779
|
+
next: `Retry in a moment: deepline skills --scope ${scope} --json. If no refresh is running, remove ${skillsInstallLeasePath(baseUrl, agents)}`
|
|
39780
|
+
},
|
|
39781
|
+
{ json: options.json }
|
|
39782
|
+
);
|
|
39783
|
+
return 7;
|
|
39784
|
+
}
|
|
39785
|
+
try {
|
|
39786
|
+
return await runSkillsInstallWithLease({
|
|
39787
|
+
options,
|
|
39788
|
+
dependencies,
|
|
39789
|
+
baseUrl,
|
|
39790
|
+
scope,
|
|
39791
|
+
root,
|
|
39792
|
+
agents,
|
|
39793
|
+
plan
|
|
39794
|
+
});
|
|
39795
|
+
} finally {
|
|
39796
|
+
lease.release();
|
|
39797
|
+
}
|
|
39798
|
+
}
|
|
39799
|
+
async function runSkillsInstallWithLease(input2) {
|
|
39800
|
+
const { options, dependencies, baseUrl, scope, root, agents, plan } = input2;
|
|
39393
39801
|
process.stderr.write(
|
|
39394
39802
|
`Replacing Deepline skills for ${agents.join(", ")} (${scope})...
|
|
39395
39803
|
`
|
|
@@ -39502,6 +39910,31 @@ Examples:
|
|
|
39502
39910
|
).action(async (options) => {
|
|
39503
39911
|
process.exitCode = await runSkillsCommand(options);
|
|
39504
39912
|
});
|
|
39913
|
+
program.command(SKILLS_AUTO_SYNC_COMMAND, { hidden: true }).description("Refresh Deepline agent skills in the background.").option(
|
|
39914
|
+
"--claim <token>",
|
|
39915
|
+
"Owner token of the leases this child was started for."
|
|
39916
|
+
).action(async (options) => {
|
|
39917
|
+
const claim = options.claim?.trim();
|
|
39918
|
+
if (!claim) {
|
|
39919
|
+
printCommandEnvelope(
|
|
39920
|
+
{
|
|
39921
|
+
ok: false,
|
|
39922
|
+
status: "failed",
|
|
39923
|
+
code: "SKILLS_AUTO_SYNC_CLAIM_REQUIRED",
|
|
39924
|
+
exitCode: 2,
|
|
39925
|
+
message: "skills-auto-sync is started by ordinary deepline commands and requires the lease token they pass; run `deepline skills` to install skills yourself."
|
|
39926
|
+
},
|
|
39927
|
+
{ json: true }
|
|
39928
|
+
);
|
|
39929
|
+
process.exitCode = 2;
|
|
39930
|
+
return;
|
|
39931
|
+
}
|
|
39932
|
+
await syncSdkSkillsIfNeeded(autoDetectBaseUrl().replace(/\/$/, ""), {
|
|
39933
|
+
mode: "inline",
|
|
39934
|
+
notices: "defer",
|
|
39935
|
+
claim
|
|
39936
|
+
});
|
|
39937
|
+
});
|
|
39505
39938
|
}
|
|
39506
39939
|
|
|
39507
39940
|
// src/cli/commands/setup.ts
|
|
@@ -40448,7 +40881,7 @@ import {
|
|
|
40448
40881
|
mkdirSync as mkdirSync13,
|
|
40449
40882
|
readFileSync as readFileSync17,
|
|
40450
40883
|
renameSync as renameSync2,
|
|
40451
|
-
rmSync as
|
|
40884
|
+
rmSync as rmSync6,
|
|
40452
40885
|
writeFileSync as writeFileSync17
|
|
40453
40886
|
} from "fs";
|
|
40454
40887
|
import { homedir as homedir10 } from "os";
|
|
@@ -40518,7 +40951,7 @@ function writeCliUpdatePreferences(preferences, homeDir2 = homedir10()) {
|
|
|
40518
40951
|
});
|
|
40519
40952
|
renameSync2(tempPath, path);
|
|
40520
40953
|
} finally {
|
|
40521
|
-
|
|
40954
|
+
rmSync6(tempPath, { force: true });
|
|
40522
40955
|
}
|
|
40523
40956
|
}
|
|
40524
40957
|
function setCliAutoUpdateEnabled(enabled, homeDir2 = homedir10()) {
|
|
@@ -40574,7 +41007,7 @@ import {
|
|
|
40574
41007
|
realpathSync as realpathSync5,
|
|
40575
41008
|
readFileSync as readFileSync19,
|
|
40576
41009
|
renameSync as renameSync3,
|
|
40577
|
-
rmSync as
|
|
41010
|
+
rmSync as rmSync7,
|
|
40578
41011
|
unlinkSync as unlinkSync3,
|
|
40579
41012
|
writeFileSync as writeFileSync18
|
|
40580
41013
|
} from "fs";
|
|
@@ -40590,7 +41023,7 @@ import {
|
|
|
40590
41023
|
|
|
40591
41024
|
// src/cli/install-integrity.ts
|
|
40592
41025
|
import { createRequire } from "module";
|
|
40593
|
-
import { existsSync as existsSync17, readFileSync as readFileSync18, statSync as
|
|
41026
|
+
import { existsSync as existsSync17, readFileSync as readFileSync18, statSync as statSync5 } from "fs";
|
|
40594
41027
|
import { isAbsolute as isAbsolute6, join as join19, relative as relative6, resolve as resolve17 } from "path";
|
|
40595
41028
|
var SDK_SIDECAR_CRITICAL_PACKAGE_FILES = [
|
|
40596
41029
|
"dist/cli/index.mjs",
|
|
@@ -40630,7 +41063,7 @@ function parseJson(path) {
|
|
|
40630
41063
|
}
|
|
40631
41064
|
function isFile(path) {
|
|
40632
41065
|
try {
|
|
40633
|
-
return
|
|
41066
|
+
return statSync5(path).isFile();
|
|
40634
41067
|
} catch {
|
|
40635
41068
|
return false;
|
|
40636
41069
|
}
|
|
@@ -41302,7 +41735,7 @@ async function runPythonSidecarUpdatePlan(plan) {
|
|
|
41302
41735
|
versionsDir,
|
|
41303
41736
|
`.tmp-sdk-update-${process.pid}-${Date.now()}`
|
|
41304
41737
|
);
|
|
41305
|
-
|
|
41738
|
+
rmSync7(tempDir, { recursive: true, force: true });
|
|
41306
41739
|
mkdirSync14(tempDir, { recursive: true });
|
|
41307
41740
|
writeFileSync18(join20(tempDir, "package.json"), NPM_SDK_SIDECAR_PACKAGE_JSON);
|
|
41308
41741
|
const env = {
|
|
@@ -41324,7 +41757,7 @@ async function runPythonSidecarUpdatePlan(plan) {
|
|
|
41324
41757
|
);
|
|
41325
41758
|
const installExitCode = installResult.exitCode;
|
|
41326
41759
|
if (installExitCode !== 0) {
|
|
41327
|
-
|
|
41760
|
+
rmSync7(tempDir, { recursive: true, force: true });
|
|
41328
41761
|
return installExitCode;
|
|
41329
41762
|
}
|
|
41330
41763
|
const installedVersion = installedPackageVersion(tempDir);
|
|
@@ -41332,7 +41765,7 @@ async function runPythonSidecarUpdatePlan(plan) {
|
|
|
41332
41765
|
process.stderr.write(
|
|
41333
41766
|
"Updated Deepline SDK package did not report a version.\n"
|
|
41334
41767
|
);
|
|
41335
|
-
|
|
41768
|
+
rmSync7(tempDir, { recursive: true, force: true });
|
|
41336
41769
|
return 1;
|
|
41337
41770
|
}
|
|
41338
41771
|
const stagedFailure = sidecarInstallFailure(tempDir);
|
|
@@ -41341,7 +41774,7 @@ async function runPythonSidecarUpdatePlan(plan) {
|
|
|
41341
41774
|
`Updated Deepline SDK package is incomplete: ${stagedFailure}.
|
|
41342
41775
|
`
|
|
41343
41776
|
);
|
|
41344
|
-
|
|
41777
|
+
rmSync7(tempDir, { recursive: true, force: true });
|
|
41345
41778
|
return 1;
|
|
41346
41779
|
}
|
|
41347
41780
|
const finalDir = join20(versionsDir, installedVersion);
|
|
@@ -41349,7 +41782,7 @@ async function runPythonSidecarUpdatePlan(plan) {
|
|
|
41349
41782
|
const finalFailure = sidecarInstallFailure(finalDir);
|
|
41350
41783
|
let backupDir = null;
|
|
41351
41784
|
if (!finalFailure) {
|
|
41352
|
-
|
|
41785
|
+
rmSync7(tempDir, { recursive: true, force: true });
|
|
41353
41786
|
} else {
|
|
41354
41787
|
let shouldPublishTemp = true;
|
|
41355
41788
|
if (existsSync18(finalDir)) {
|
|
@@ -41362,11 +41795,11 @@ async function runPythonSidecarUpdatePlan(plan) {
|
|
|
41362
41795
|
} catch (error) {
|
|
41363
41796
|
const concurrentlyPublishedFailure = sidecarInstallFailure(finalDir);
|
|
41364
41797
|
if (!concurrentlyPublishedFailure) {
|
|
41365
|
-
|
|
41798
|
+
rmSync7(tempDir, { recursive: true, force: true });
|
|
41366
41799
|
backupDir = null;
|
|
41367
41800
|
shouldPublishTemp = false;
|
|
41368
41801
|
} else {
|
|
41369
|
-
|
|
41802
|
+
rmSync7(tempDir, { recursive: true, force: true });
|
|
41370
41803
|
process.stderr.write(
|
|
41371
41804
|
`Failed to preserve the incomplete Deepline SDK sidecar before repair: ${error.message}.
|
|
41372
41805
|
`
|
|
@@ -41379,10 +41812,10 @@ async function runPythonSidecarUpdatePlan(plan) {
|
|
|
41379
41812
|
try {
|
|
41380
41813
|
renameSync3(tempDir, finalDir);
|
|
41381
41814
|
} catch (error) {
|
|
41382
|
-
|
|
41815
|
+
rmSync7(tempDir, { recursive: true, force: true });
|
|
41383
41816
|
const concurrentlyPublishedFailure = sidecarInstallFailure(finalDir);
|
|
41384
41817
|
if (!concurrentlyPublishedFailure) {
|
|
41385
|
-
if (backupDir)
|
|
41818
|
+
if (backupDir) rmSync7(backupDir, { recursive: true, force: true });
|
|
41386
41819
|
backupDir = null;
|
|
41387
41820
|
} else {
|
|
41388
41821
|
let restoreFailure = "";
|
|
@@ -41406,7 +41839,7 @@ async function runPythonSidecarUpdatePlan(plan) {
|
|
|
41406
41839
|
const publishedFailure = sidecarStructureFailure(finalDir);
|
|
41407
41840
|
if (publishedFailure) {
|
|
41408
41841
|
if (backupDir && existsSync18(backupDir)) {
|
|
41409
|
-
|
|
41842
|
+
rmSync7(finalDir, { recursive: true, force: true });
|
|
41410
41843
|
try {
|
|
41411
41844
|
renameSync3(backupDir, finalDir);
|
|
41412
41845
|
backupDir = null;
|
|
@@ -41419,7 +41852,7 @@ async function runPythonSidecarUpdatePlan(plan) {
|
|
|
41419
41852
|
);
|
|
41420
41853
|
return 1;
|
|
41421
41854
|
}
|
|
41422
|
-
if (backupDir)
|
|
41855
|
+
if (backupDir) rmSync7(backupDir, { recursive: true, force: true });
|
|
41423
41856
|
writeSidecarLauncher({
|
|
41424
41857
|
path: plan.sidecarPath,
|
|
41425
41858
|
hostUrl: plan.hostUrl,
|
|
@@ -43560,14 +43993,15 @@ Examples:
|
|
|
43560
43993
|
deepline tools describe hunter_email_verifier --json
|
|
43561
43994
|
deepline tools describe deeplineagent --model openai/gpt-5.5 --json
|
|
43562
43995
|
deepline tools describe ai_inference --estimate-payload @payload.json --json
|
|
43996
|
+
deepline tools describe ai_evaluate --estimate-payload @payload.json --json
|
|
43563
43997
|
deepline tools execute hunter_email_verifier --input '{"email":"a@b.com"}'
|
|
43564
43998
|
`
|
|
43565
43999
|
).option("--json", "Emit JSON output. Also automatic when stdout is piped").option(
|
|
43566
44000
|
"--model <model>",
|
|
43567
|
-
"For
|
|
44001
|
+
"For language tools, include AI Gateway metadata; for ai_evaluate, set the quote payload model"
|
|
43568
44002
|
).option(
|
|
43569
44003
|
"--estimate-payload <payload>",
|
|
43570
|
-
"Quote an ai_inference or deeplineagent JSON payload (inline or @file)"
|
|
44004
|
+
"Quote an ai_evaluate, ai_inference, or deeplineagent JSON payload (inline or @file)"
|
|
43571
44005
|
).option("--pricing-only", "Only print pricing and billing semantics").option("--schema-only", "Only print input schema fields").option(
|
|
43572
44006
|
"--examples-only",
|
|
43573
44007
|
"Only print runnable examples and sample payloads"
|
|
@@ -43669,9 +44103,9 @@ async function getTool(toolId, options = {}) {
|
|
|
43669
44103
|
}
|
|
43670
44104
|
let inferenceQuote = null;
|
|
43671
44105
|
if (options.estimatePayload) {
|
|
43672
|
-
if (toolId !== "deeplineagent" && toolId !== "ai_inference") {
|
|
44106
|
+
if (toolId !== "deeplineagent" && toolId !== "ai_inference" && toolId !== "ai_evaluate") {
|
|
43673
44107
|
console.error(
|
|
43674
|
-
"--estimate-payload is only supported for deeplineagent and ai_inference."
|
|
44108
|
+
"--estimate-payload is only supported for ai_evaluate, deeplineagent, and ai_inference."
|
|
43675
44109
|
);
|
|
43676
44110
|
return 2;
|
|
43677
44111
|
}
|
|
@@ -43685,7 +44119,7 @@ async function getTool(toolId, options = {}) {
|
|
|
43685
44119
|
inferenceQuote = await client2.quoteInferenceTool(toolId, estimatePayload);
|
|
43686
44120
|
}
|
|
43687
44121
|
const modelDescription = options.model && (toolId === "deeplineagent" || toolId === "ai_inference") ? await client2.describeModel(options.model) : null;
|
|
43688
|
-
if (options.model && !modelDescription) {
|
|
44122
|
+
if (options.model && !modelDescription && toolId !== "ai_evaluate") {
|
|
43689
44123
|
console.error(
|
|
43690
44124
|
"--model is only supported for deeplineagent and ai_inference."
|
|
43691
44125
|
);
|
|
@@ -46263,7 +46697,7 @@ Exit codes:
|
|
|
46263
46697
|
`
|
|
46264
46698
|
);
|
|
46265
46699
|
program.hook("preAction", async (_thisCommand, actionCommand) => {
|
|
46266
|
-
if (actionCommand.name() === "version" || actionCommand.name() === "update" || actionCommand.name() === "setup" || actionCommand.name() === "skills" || actionCommand.name() === "doctor" || isAutoUpdateSettingsInvocation() || isDeprecatedCommandInvocation()) {
|
|
46700
|
+
if (actionCommand.name() === "version" || actionCommand.name() === "update" || actionCommand.name() === "setup" || actionCommand.name() === "skills" || actionCommand.name() === SKILLS_AUTO_SYNC_COMMAND || actionCommand.name() === "doctor" || isAutoUpdateSettingsInvocation() || isDeprecatedCommandInvocation()) {
|
|
46267
46701
|
return;
|
|
46268
46702
|
}
|
|
46269
46703
|
const compatibilityCommand = compatibilityCommandPath(actionCommand) || actionCommand.name();
|
|
@@ -46271,18 +46705,42 @@ Exit codes:
|
|
|
46271
46705
|
progress?.phase("checking sdk compatibility");
|
|
46272
46706
|
}
|
|
46273
46707
|
const baseUrl = autoDetectBaseUrl().replace(/\/$/, "");
|
|
46708
|
+
flushDeferredSkillsSyncNotices(baseUrl);
|
|
46274
46709
|
const shouldDeferSkillsSync = shouldDeferSkillsSyncForCommand();
|
|
46275
46710
|
const skillsVersion = shouldDeferSkillsSync ? void 0 : readSdkSkillsLocalVersion(baseUrl);
|
|
46276
|
-
const
|
|
46711
|
+
const trusted = readTrustedCleanCompatibility(
|
|
46712
|
+
baseUrl,
|
|
46713
|
+
compatibilityCommand,
|
|
46714
|
+
skillsVersion
|
|
46715
|
+
);
|
|
46716
|
+
const fastDeadline = trusted === null && readFreshCleanCompatibility(
|
|
46717
|
+
baseUrl,
|
|
46718
|
+
compatibilityCommand,
|
|
46719
|
+
skillsVersion
|
|
46720
|
+
) !== null;
|
|
46721
|
+
if (trusted) {
|
|
46722
|
+
recordCliTrace({
|
|
46723
|
+
phase: "cli.sdk_compatibility",
|
|
46724
|
+
ms: 0,
|
|
46725
|
+
ok: true,
|
|
46726
|
+
baseUrl,
|
|
46727
|
+
command: compatibilityCommand,
|
|
46728
|
+
skillsVersion: skillsVersion ?? null,
|
|
46729
|
+
source: "trusted_cache"
|
|
46730
|
+
});
|
|
46731
|
+
}
|
|
46732
|
+
const compatibility = trusted ? { response: trusted, error: null } : await traceCliSpan(
|
|
46277
46733
|
"cli.sdk_compatibility",
|
|
46278
46734
|
{
|
|
46279
46735
|
baseUrl,
|
|
46280
46736
|
command: compatibilityCommand,
|
|
46281
|
-
skillsVersion: skillsVersion ?? null
|
|
46737
|
+
skillsVersion: skillsVersion ?? null,
|
|
46738
|
+
fastDeadline
|
|
46282
46739
|
},
|
|
46283
46740
|
() => checkSdkCompatibility(baseUrl, {
|
|
46284
46741
|
command: compatibilityCommand,
|
|
46285
|
-
skillsVersion
|
|
46742
|
+
skillsVersion,
|
|
46743
|
+
...fastDeadline ? { timeoutMs: SDK_COMPATIBILITY_FAST_DEADLINE_MS } : {}
|
|
46286
46744
|
})
|
|
46287
46745
|
);
|
|
46288
46746
|
if (compatibility.error) {
|
|
@@ -46305,7 +46763,8 @@ Exit codes:
|
|
|
46305
46763
|
"cli.sdk_skills_sync",
|
|
46306
46764
|
{ baseUrl },
|
|
46307
46765
|
() => syncSdkSkillsIfNeeded(baseUrl, {
|
|
46308
|
-
update: skillsUpdate
|
|
46766
|
+
update: skillsUpdate,
|
|
46767
|
+
mode: "detached"
|
|
46309
46768
|
})
|
|
46310
46769
|
);
|
|
46311
46770
|
}
|