ds-harness-remote 0.3.29 → 0.3.31

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/index.js CHANGED
@@ -5636,7 +5636,9 @@ var SWITCHED_DOMAINS = [
5636
5636
  "agentPresets",
5637
5637
  "events",
5638
5638
  "goals",
5639
- "llm"
5639
+ "llm",
5640
+ "settings",
5641
+ "credentials"
5640
5642
  ];
5641
5643
  var ApiProxySwitch = class {
5642
5644
  remote;
@@ -13210,7 +13212,7 @@ function normalizeServerUrl(value) {
13210
13212
  }
13211
13213
 
13212
13214
  // src/version.ts
13213
- var PLUGIN_VERSION = "0.3.29";
13215
+ var PLUGIN_VERSION = "0.3.31";
13214
13216
 
13215
13217
  // src/server-api.ts
13216
13218
  var HostServerApi = class {
@@ -13881,6 +13883,7 @@ var ClientModeRuntime = class {
13881
13883
  ...this.proxySwitch.status(),
13882
13884
  connected: this.connected !== void 0,
13883
13885
  transport: this.connected?.client.getStats().mode ?? "Disconnected",
13886
+ preferredTransports: this.config.forceRelay ? ["relay"] : ["lan", "p2p", "turn", "relay"],
13884
13887
  remoteFeatures: this.connected?.features ?? remoteHostFeatures(),
13885
13888
  ...this.pendingWorkspaceSelection === void 0 ? {} : { workspaceSelection: { ...this.pendingWorkspaceSelection } },
13886
13889
  hostAuthorizationAvailable: this.host !== void 0,
@@ -16072,6 +16075,59 @@ var commandExecuteSchema = external_exports.object({
16072
16075
  var commandListSchema = external_exports.object({
16073
16076
  agentId: external_exports.string().min(1).max(128)
16074
16077
  }).strict();
16078
+ var credentialRefSchema = external_exports.string().regex(/^[A-Za-z_][A-Za-z0-9_]*$/, "Invalid credential reference name").max(128);
16079
+ var CONFIG_PLANE_SETTINGS_BYTES = 64 * 1024;
16080
+ var CONFIG_PLANE_MAX_OPS = 64;
16081
+ var CONFIG_PLANE_MAX_PATH_SEGMENTS = 8;
16082
+ var CONFIG_PLANE_MAX_PATH_SEGMENT_BYTES = 64;
16083
+ var CONFIG_PLANE_MAX_CREDENTIAL_VALUE_BYTES = 8 * 1024;
16084
+ var CONFIG_PLANE_MAX_BASE_URL_BYTES = 2048;
16085
+ var CONFIG_PLANE_MAX_NS_BYTES = 128;
16086
+ var settingsDescribeSchema = external_exports.object({}).strict();
16087
+ var settingsWriteBase = {
16088
+ ns: external_exports.string().min(1).max(CONFIG_PLANE_MAX_NS_BYTES),
16089
+ expectedRevision: external_exports.number().int().nonnegative().optional()
16090
+ };
16091
+ var settingsUpdateSchema = external_exports.object({
16092
+ ...settingsWriteBase,
16093
+ patch: external_exports.record(external_exports.string().min(1).max(CONFIG_PLANE_MAX_PATH_SEGMENT_BYTES), external_exports.unknown())
16094
+ }).strict();
16095
+ var settingsReplaceSchema = external_exports.object({
16096
+ ...settingsWriteBase,
16097
+ section: external_exports.record(external_exports.string().min(1).max(CONFIG_PLANE_MAX_PATH_SEGMENT_BYTES), external_exports.unknown())
16098
+ }).strict();
16099
+ var settingsOpSchema = external_exports.union([
16100
+ external_exports.object({
16101
+ op: external_exports.literal("set"),
16102
+ path: external_exports.array(external_exports.string().min(1).max(CONFIG_PLANE_MAX_PATH_SEGMENT_BYTES)).max(CONFIG_PLANE_MAX_PATH_SEGMENTS),
16103
+ value: external_exports.unknown()
16104
+ }).strict(),
16105
+ external_exports.object({
16106
+ op: external_exports.literal("unset"),
16107
+ path: external_exports.array(external_exports.string().min(1).max(CONFIG_PLANE_MAX_PATH_SEGMENT_BYTES)).max(CONFIG_PLANE_MAX_PATH_SEGMENTS)
16108
+ }).strict()
16109
+ ]);
16110
+ var settingsMutateSchema = external_exports.object({
16111
+ ...settingsWriteBase,
16112
+ ops: external_exports.array(settingsOpSchema).min(1).max(CONFIG_PLANE_MAX_OPS)
16113
+ }).strict();
16114
+ var credentialsDescribeSchema = external_exports.object({
16115
+ refs: external_exports.array(credentialRefSchema).max(CONFIG_PLANE_MAX_OPS)
16116
+ }).strict();
16117
+ var credentialsSetSchema = external_exports.object({
16118
+ ref: credentialRefSchema,
16119
+ value: external_exports.string().min(1).max(CONFIG_PLANE_MAX_CREDENTIAL_VALUE_BYTES)
16120
+ }).strict();
16121
+ var credentialsUnsetSchema = external_exports.object({
16122
+ ref: credentialRefSchema
16123
+ }).strict();
16124
+ var discoverModelsSchema = external_exports.object({
16125
+ settingsNs: external_exports.string().min(1).max(CONFIG_PLANE_MAX_NS_BYTES),
16126
+ provider: external_exports.string().min(1).max(CONFIG_PLANE_MAX_NS_BYTES).optional(),
16127
+ baseURL: external_exports.string().max(CONFIG_PLANE_MAX_BASE_URL_BYTES).optional(),
16128
+ api: external_exports.string().min(1).max(CONFIG_PLANE_MAX_NS_BYTES).optional(),
16129
+ apiKey: external_exports.string().min(1).max(CONFIG_PLANE_MAX_CREDENTIAL_VALUE_BYTES).optional()
16130
+ }).strict();
16075
16131
  var HARNESS_API_ALLOWLIST = [
16076
16132
  "session.list",
16077
16133
  "session.search",
@@ -16111,7 +16167,15 @@ var HARNESS_API_ALLOWLIST = [
16111
16167
  "commands.execute",
16112
16168
  "commands.list",
16113
16169
  "llm.providers",
16114
- "llm.models"
16170
+ "llm.models",
16171
+ "llm.discoverModels",
16172
+ "settings.describe",
16173
+ "settings.update",
16174
+ "settings.replace",
16175
+ "settings.mutate",
16176
+ "credentials.describe",
16177
+ "credentials.set",
16178
+ "credentials.unset"
16115
16179
  ];
16116
16180
  var NATIVE_CALL_TIMEOUT_MS = 3e4;
16117
16181
  var MAX_ACTIVE_API_TRANSFERS = 2;
@@ -16425,7 +16489,8 @@ function createMethodMap(api, typertGateway) {
16425
16489
  const domain = domainProperty(wireDomain);
16426
16490
  const implementation = domains[domain]?.[action];
16427
16491
  if (typeof implementation !== "function") continue;
16428
- methods.set(method, implementation.bind(domains[domain]));
16492
+ const scoped = CONFIG_PLANE_METHODS.includes(method) ? scopeConfigPlaneMethod(api, method, implementation) : void 0;
16493
+ methods.set(method, scoped ?? implementation.bind(domains[domain]));
16429
16494
  }
16430
16495
  return methods;
16431
16496
  }
@@ -16437,6 +16502,167 @@ function domainProperty(wireDomain) {
16437
16502
  if (wireDomain === "goal") return "goals";
16438
16503
  return wireDomain;
16439
16504
  }
16505
+ var CONFIG_PLANE_METHODS = [
16506
+ "llm.discoverModels",
16507
+ "settings.describe",
16508
+ "settings.update",
16509
+ "settings.replace",
16510
+ "settings.mutate",
16511
+ "credentials.describe",
16512
+ "credentials.set",
16513
+ "credentials.unset"
16514
+ ];
16515
+ function scopeConfigPlaneMethod(api, method, native) {
16516
+ switch (method) {
16517
+ case "llm.discoverModels":
16518
+ return async (request, signal) => {
16519
+ const payload = parseConfigPlane(discoverModelsSchema, request.payload, "llm.discoverModels");
16520
+ if (payload.baseURL !== void 0) validateDiscoverBaseUrl(payload.baseURL);
16521
+ try {
16522
+ const response = await native({ rpcId: request.rpcId, payload }, signal);
16523
+ return sanitizeModelDiscoveryResponse(response, payload.settingsNs);
16524
+ } catch {
16525
+ return modelDiscoveryFailure(request.rpcId, payload.settingsNs);
16526
+ }
16527
+ };
16528
+ case "settings.describe":
16529
+ return async (request, signal) => {
16530
+ parseConfigPlane(settingsDescribeSchema, request.payload, "settings.describe");
16531
+ const response = await native({ rpcId: request.rpcId, payload: {} }, signal);
16532
+ return disableRemoteSettingsDocument(response);
16533
+ };
16534
+ case "settings.update":
16535
+ return async (request, signal) => {
16536
+ const payload = parseConfigPlane(settingsUpdateSchema, request.payload, "settings.update");
16537
+ await assertRegisteredSettingsNamespace(api, payload.ns);
16538
+ assertSerializedBytes(payload.patch, CONFIG_PLANE_SETTINGS_BYTES, "settings.update patch");
16539
+ return native({ rpcId: request.rpcId, payload }, signal);
16540
+ };
16541
+ case "settings.replace":
16542
+ return async (request, signal) => {
16543
+ const payload = parseConfigPlane(settingsReplaceSchema, request.payload, "settings.replace");
16544
+ await assertRegisteredSettingsNamespace(api, payload.ns);
16545
+ assertSerializedBytes(payload.section, CONFIG_PLANE_SETTINGS_BYTES, "settings.replace section");
16546
+ return native({ rpcId: request.rpcId, payload }, signal);
16547
+ };
16548
+ case "settings.mutate":
16549
+ return async (request, signal) => {
16550
+ const payload = parseConfigPlane(settingsMutateSchema, request.payload, "settings.mutate");
16551
+ await assertRegisteredSettingsNamespace(api, payload.ns);
16552
+ assertSerializedBytes(payload.ops, CONFIG_PLANE_SETTINGS_BYTES, "settings.mutate ops");
16553
+ return native({ rpcId: request.rpcId, payload }, signal);
16554
+ };
16555
+ case "credentials.describe":
16556
+ return async (request, signal) => {
16557
+ const payload = parseConfigPlane(credentialsDescribeSchema, request.payload, "credentials.describe");
16558
+ return native({ rpcId: request.rpcId, payload }, signal);
16559
+ };
16560
+ case "credentials.set":
16561
+ return async (request, signal) => {
16562
+ const payload = parseConfigPlane(credentialsSetSchema, request.payload, "credentials.set");
16563
+ return native({ rpcId: request.rpcId, payload }, signal);
16564
+ };
16565
+ case "credentials.unset":
16566
+ return async (request, signal) => {
16567
+ const payload = parseConfigPlane(credentialsUnsetSchema, request.payload, "credentials.unset");
16568
+ return native({ rpcId: request.rpcId, payload }, signal);
16569
+ };
16570
+ }
16571
+ }
16572
+ function parseConfigPlane(schema, payload, label) {
16573
+ try {
16574
+ return schema.parse(payload);
16575
+ } catch (error) {
16576
+ if (error instanceof external_exports.ZodError) {
16577
+ throw new RpcError("INVALID_MESSAGE", `The ${label} payload is invalid for the remote channel.`);
16578
+ }
16579
+ throw error;
16580
+ }
16581
+ }
16582
+ function validateDiscoverBaseUrl(value) {
16583
+ let url;
16584
+ try {
16585
+ url = new URL(value);
16586
+ } catch {
16587
+ throw new RpcError("INVALID_MESSAGE", "The model discovery baseURL is invalid.");
16588
+ }
16589
+ const local = url.hostname === "localhost" || url.hostname === "127.0.0.1" || url.hostname === "::1";
16590
+ if (url.protocol !== "https:" && !(local && url.protocol === "http:")) {
16591
+ throw new RpcError("INVALID_MESSAGE", "The model discovery baseURL must use HTTPS (HTTP is allowed only for localhost).");
16592
+ }
16593
+ if (url.username !== "" || url.password !== "") {
16594
+ throw new RpcError("INVALID_MESSAGE", "The model discovery baseURL must not contain credentials.");
16595
+ }
16596
+ if (url.hash !== "") {
16597
+ throw new RpcError("INVALID_MESSAGE", "The model discovery baseURL must not contain a fragment.");
16598
+ }
16599
+ }
16600
+ function assertSerializedBytes(value, maxBytes, label) {
16601
+ const bytes = new TextEncoder().encode(JSON.stringify(value)).byteLength;
16602
+ if (bytes > maxBytes) {
16603
+ throw new RpcError("INVALID_MESSAGE", `The ${label} exceeds the ${maxBytes}-byte remote limit.`);
16604
+ }
16605
+ }
16606
+ function sanitizeModelDiscoveryResponse(response, settingsNs) {
16607
+ const result = response.result;
16608
+ if (typeof result === "object" && result !== null && "ok" in result && result.ok === true) return response;
16609
+ return modelDiscoveryFailure(response.rpcId, settingsNs);
16610
+ }
16611
+ function modelDiscoveryFailure(rpcId, settingsNs) {
16612
+ return {
16613
+ rpcId,
16614
+ result: {
16615
+ ok: false,
16616
+ error: {
16617
+ code: "model-discovery-failed",
16618
+ message: "Model discovery failed.",
16619
+ details: { settingsNs }
16620
+ }
16621
+ }
16622
+ };
16623
+ }
16624
+ function disableRemoteSettingsDocument(response) {
16625
+ const result = response.result;
16626
+ if (typeof result !== "object" || result === null || !("ok" in result) || result.ok !== true) return response;
16627
+ const value = result.value;
16628
+ if (typeof value !== "object" || value === null) return response;
16629
+ return { ...response, result: { ...result, value: { ...value, hasDocument: false } } };
16630
+ }
16631
+ var EMPTY_SETTINGS_NAMESPACES = /* @__PURE__ */ new Set();
16632
+ async function assertRegisteredSettingsNamespace(api, ns) {
16633
+ const allowed = await registeredSettingsNamespaces(api);
16634
+ if (!allowed.has(ns)) throw deniedSettingsNamespace(ns);
16635
+ }
16636
+ async function registeredSettingsNamespaces(api) {
16637
+ const settings = api.settings;
16638
+ const describe = settings?.describe;
16639
+ if (typeof describe !== "function") return EMPTY_SETTINGS_NAMESPACES;
16640
+ const response = await withTimeout(
16641
+ describe.call(settings, { rpcId: "bridge-settings-scope", payload: {} }, AbortSignal.timeout(NATIVE_CALL_TIMEOUT_MS)),
16642
+ NATIVE_CALL_TIMEOUT_MS,
16643
+ "The Host settings.describe call timed out."
16644
+ );
16645
+ const value = unwrapNativeValue(response, "settings.describe");
16646
+ const list = typeof value === "object" && value !== null ? value.namespaces : void 0;
16647
+ if (!Array.isArray(list)) return EMPTY_SETTINGS_NAMESPACES;
16648
+ const namespaces = /* @__PURE__ */ new Set();
16649
+ for (const item of list) {
16650
+ if (typeof item !== "object" || item === null) continue;
16651
+ const ns = item.ns;
16652
+ if (typeof ns === "string" && ns.length > 0) namespaces.add(ns);
16653
+ }
16654
+ return namespaces;
16655
+ }
16656
+ function unwrapNativeValue(response, method) {
16657
+ const result = response.result;
16658
+ if (typeof result !== "object" || result === null || !("ok" in result) || result.ok !== true || !("value" in result)) {
16659
+ throw new RpcError("INTERNAL_ERROR", `The Host ${method} call did not succeed.`);
16660
+ }
16661
+ return result.value;
16662
+ }
16663
+ function deniedSettingsNamespace(ns) {
16664
+ return new RpcError("METHOD_NOT_ALLOWED", `Harness settings namespace ${JSON.stringify(ns)} is not registered on the Host.`);
16665
+ }
16440
16666
  function deniedMethod(method) {
16441
16667
  return new RpcError("METHOD_NOT_ALLOWED", `Harness API method ${JSON.stringify(method)} is not available in remote mode.`);
16442
16668
  }
@@ -16723,11 +16949,16 @@ function shortId5(value) {
16723
16949
  }
16724
16950
 
16725
16951
  // src/remote-file-content-provider.ts
16726
- function createRemoteFileContentProvider(call) {
16952
+ var REMOTE_FILE_SAVE_AS_MAX_BYTES = 100 * 1024 * 1024;
16953
+ function createRemoteFileContentProvider(call, options = {}) {
16727
16954
  return {
16728
16955
  id: "dsh-remote-files",
16729
16956
  priority: 1e4,
16730
16957
  supports: () => true,
16958
+ saveAsAllowed: () => ({
16959
+ allowed: currentSaveAsAllowed(options.saveAsAllowed),
16960
+ maxBytes: options.saveAsMaxBytes ?? REMOTE_FILE_SAVE_AS_MAX_BYTES
16961
+ }),
16731
16962
  async stat(locator, signal) {
16732
16963
  const value = await call("fileviewer.stat", { path: locator }, signal);
16733
16964
  if (!value.exists) return void 0;
@@ -16776,6 +17007,9 @@ function createRemoteFileContentProvider(call) {
16776
17007
  }
16777
17008
  };
16778
17009
  }
17010
+ function currentSaveAsAllowed(value) {
17011
+ return typeof value === "function" ? value() : value === true;
17012
+ }
16779
17013
  function decodeBase64(value) {
16780
17014
  const binary = atob(value);
16781
17015
  const bytes = new Uint8Array(binary.length);