@sparkelf/dsh-dataops-managed 0.3.14 → 0.3.16

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/lib/index.js CHANGED
@@ -692,6 +692,29 @@ function asByteCount(value) {
692
692
  return typeof value === "number" && Number.isSafeInteger(value) && value > 0 ? value : null;
693
693
  }
694
694
  /**
695
+ * A rejection DataOps answered with, carrying its status and message.
696
+ *
697
+ * Without this the caller can only tell that something failed, and a value DataOps refused —
698
+ * which the user can correct — is indistinguishable from a fault in the request path.
699
+ */
700
+ var WorkspaceLimitsRejection = class extends Error {
701
+ status;
702
+ constructor(status, message) {
703
+ super(message);
704
+ this.status = status;
705
+ this.name = "WorkspaceLimitsRejection";
706
+ }
707
+ };
708
+ /** Read DataOps' own explanation from a failed response, falling back to the status line. */
709
+ async function rejectionMessage(response, fallback) {
710
+ try {
711
+ const message = asRecord(await response.json())?.message;
712
+ if (typeof message === "string" && message.trim() !== "") return message;
713
+ if (Array.isArray(message) && typeof message[0] === "string") return message[0];
714
+ } catch {}
715
+ return `${fallback} with HTTP ${String(response.status)}`;
716
+ }
717
+ /**
695
718
  * The workspace limits an administrator sets in DataOps.
696
719
  *
697
720
  * The plugin holds the DataOps JWT, so the browser cannot read these itself; this class is the
@@ -724,7 +747,7 @@ var WorkspaceLimits = class {
724
747
  if (token === void 0) return void 0;
725
748
  const response = await fetch(new URL("/api/ai/attachment-settings", this.apiBase()), { headers: { authorization: `Bearer ${token}` } });
726
749
  if (response.status === 401) return void 0;
727
- if (!response.ok) throw new Error(`Workspace limits read failed with HTTP ${String(response.status)}`);
750
+ if (!response.ok) throw new WorkspaceLimitsRejection(response.status, await rejectionMessage(response, "Workspace limits read failed"));
728
751
  const body = asRecord(await response.json());
729
752
  const settings = body === null ? null : asRecord(body.settings);
730
753
  const size = settings === null ? null : asRecord(settings.workspaceSize);
@@ -757,7 +780,7 @@ var WorkspaceLimits = class {
757
780
  body: JSON.stringify({ workspaceSize: limits })
758
781
  });
759
782
  if (response.status === 401) return void 0;
760
- if (!response.ok) throw new Error(`Workspace limits write failed with HTTP ${String(response.status)}`);
783
+ if (!response.ok) throw new WorkspaceLimitsRejection(response.status, await rejectionMessage(response, "Workspace limits write failed"));
761
784
  return this.status();
762
785
  }
763
786
  };
@@ -792,6 +815,11 @@ const MODEL_SYNC_PATH = "/integrations/dataops/model-sync";
792
815
  const SKILL_PLAZA_PATH = "/integrations/dataops/skill-plaza";
793
816
  /** Same-origin route the Settings panel uses to read and change this workspace's limits. */
794
817
  const WORKSPACE_LIMITS_PATH = "/integrations/dataops/workspace-limits";
818
+ /** Same-origin route the Settings panel uses to read and change the tool-call timeout. */
819
+ const TOOL_TIMEOUT_PATH = "/integrations/dataops/tool-timeout";
820
+ /** The ends a tool-call timeout may take, in whole seconds. */
821
+ const TOOL_TIMEOUT_MIN_SECONDS = 1;
822
+ const TOOL_TIMEOUT_MAX_SECONDS = 3600;
795
823
  /** The live sync instance, so the settings routes can act on it after activation. */
796
824
  let modelSyncRef;
797
825
  /** The live plaza instance, so the skill center routes can act on it after activation. */
@@ -810,21 +838,54 @@ let settingsSyncRef;
810
838
  function currentSettingsSync() {
811
839
  return settingsSyncRef;
812
840
  }
841
+ /**
842
+ * Read the value behind a possibly-volatile field.
843
+ *
844
+ * A volatile field always arrives as a reference, but the plain shape is accepted too so a
845
+ * caller that validated the config without a settings service still reads its value.
846
+ * @param field - The config field as the runtime supplied it.
847
+ * @param fallback - Value to use when nothing is stored yet.
848
+ * @returns The current value.
849
+ */
850
+ function volatileValue(field, fallback) {
851
+ if (field === void 0) return fallback;
852
+ if (typeof field === "object" && field !== null && "get" in field && typeof field.get === "function") return field.get() ?? fallback;
853
+ return field;
854
+ }
855
+ /**
856
+ * Per-tool-call timeout a workspace starts with.
857
+ *
858
+ * Named rather than inlined so the schema default and the read fallback cannot drift: the field is
859
+ * volatile, so a workspace that never changed it reads no value at all and both places have to
860
+ * answer the same number.
861
+ */
862
+ const DEFAULT_TOOL_CALL_TIMEOUT_MS = 3e5;
863
+ /** Default sync state before this workspace stored anything. */
864
+ const MODEL_SYNC_DEFAULT = {
865
+ detached: false,
866
+ adoptedModelIds: [],
867
+ privateModelIds: []
868
+ };
813
869
  /** Schemastery parser for managed DataOps configuration. */
814
870
  const Config = z.object({
815
871
  baseUrl: z.string().default("http://host.docker.internal:3101"),
816
872
  serverName: z.string().default("dataops"),
817
873
  credentialRef: z.string().role("credential-ref").default("DATAOPS_ACCESS_TOKEN"),
818
- toolCallTimeoutMs: z.number().min(1).default(3e5),
874
+ /**
875
+ * Volatile so the settings service persists it in this workspace's document: the timeout an
876
+ * operator needs depends on the query behind a tool, which is deployment knowledge the profile
877
+ * that mounts this plugin does not have.
878
+ *
879
+ * `z.any()` like the sync state above, and for the same reason: a volatile field is delivered
880
+ * to `apply` as a reference rather than a value, so a narrowed schema would describe a shape
881
+ * the runtime does not pass. The range is enforced where the value is read.
882
+ */
883
+ toolCallTimeoutMs: z.any().default(DEFAULT_TOOL_CALL_TIMEOUT_MS).volatile(),
819
884
  /**
820
885
  * Volatile so the settings service persists it in this workspace's document. The shape is
821
886
  * left open because the sync state is this plugin's own record, not user configuration.
822
887
  */
823
- modelSync: z.any().default({
824
- detached: false,
825
- adoptedModelIds: [],
826
- privateModelIds: []
827
- }).volatile(),
888
+ modelSync: z.any().default(MODEL_SYNC_DEFAULT).volatile(),
828
889
  /** Volatile for the same reason as `modelSync`: it is this plugin's own record. */
829
890
  settingsSync: z.any().default(SECTION_SYNC_DEFAULT).volatile(),
830
891
  /**
@@ -857,7 +918,7 @@ async function apply(ctx, config) {
857
918
  url: `${baseUrl}/api/ai/data-query/mcp`,
858
919
  headers: {},
859
920
  bearerTokenRef: config.credentialRef,
860
- toolCallTimeoutMs: config.toolCallTimeoutMs
921
+ toolCallTimeoutMs: volatileValue(config.toolCallTimeoutMs, DEFAULT_TOOL_CALL_TIMEOUT_MS)
861
922
  });
862
923
  mcpFiber = fiber;
863
924
  try {
@@ -873,23 +934,47 @@ async function apply(ctx, config) {
873
934
  mcpFiber = void 0;
874
935
  if (fiber !== void 0 && fiber.uid !== null) await fiber.dispose();
875
936
  }, "dataops-managed: MCP lifecycle");
876
- if (await ctx.credentials.resolve(accessRef) !== void 0) await ensureMcp();
937
+ /**
938
+ * Connect the MCP client when a JWT is already stored.
939
+ *
940
+ * A connect can fail for reasons this plugin does not own — the stored JWT may have expired,
941
+ * or DataOps may be unreachable at this moment — and those are states the settings routes
942
+ * report and recover from. Awaiting it here would abort activation, leaving the plugin with
943
+ * no routes at all: the panel then cannot read the very state that explains the failure, and
944
+ * the browser reports a connection error instead. The routes below are registered first, and
945
+ * a failed connect is reported rather than thrown.
946
+ */
947
+ const connectExisting = async () => {
948
+ if (await ctx.credentials.resolve(accessRef) === void 0) return;
949
+ try {
950
+ await ensureMcp();
951
+ } catch (error) {
952
+ ctx.logger.warn("dataops-managed: connecting the DataOps MCP server failed; the settings routes stay up so a new JWT can be connected");
953
+ ctx.logger.warn(error);
954
+ }
955
+ };
877
956
  /**
878
957
  * The sync state lives in this plugin's own Config, so the settings service persists it in
879
958
  * the workspace document and it survives a restart.
880
959
  */
881
960
  const syncStore = {
882
- read: () => ({
883
- detached: config.modelSync?.detached === true,
884
- adoptedModelIds: Array.isArray(config.modelSync?.adoptedModelIds) ? config.modelSync.adoptedModelIds : [],
885
- privateModelIds: Array.isArray(config.modelSync?.privateModelIds) ? config.modelSync.privateModelIds : []
886
- }),
961
+ read: () => {
962
+ const state = volatileValue(config.modelSync, MODEL_SYNC_DEFAULT);
963
+ return {
964
+ detached: state?.detached === true,
965
+ adoptedModelIds: Array.isArray(state?.adoptedModelIds) ? state.adoptedModelIds : [],
966
+ privateModelIds: Array.isArray(state?.privateModelIds) ? state.privateModelIds : []
967
+ };
968
+ },
887
969
  write: async (next) => {
888
970
  await ctx.settings.update(MANAGED_PLUGIN_ID, { modelSync: next });
889
971
  }
890
972
  };
891
973
  const settingsSync = new SettingsSync(ctx, {
892
- read: () => ({ sections: typeof config.settingsSync?.sections === "object" && config.settingsSync.sections !== null ? config.settingsSync.sections : {} }),
974
+ read: () => {
975
+ const state = volatileValue(config.settingsSync, SECTION_SYNC_DEFAULT);
976
+ return { sections: typeof state?.sections === "object" && state.sections !== null ? state.sections : {} };
977
+ },
893
978
  write: async (next) => {
894
979
  await ctx.settings.update(MANAGED_PLUGIN_ID, { settingsSync: next });
895
980
  }
@@ -1198,12 +1283,61 @@ async function apply(ctx, config) {
1198
1283
  }
1199
1284
  writeJson(response, 200, status);
1200
1285
  } catch (error) {
1286
+ if (error instanceof WorkspaceLimitsRejection) {
1287
+ writeJson(response, error.status, { error: error.message });
1288
+ return;
1289
+ }
1201
1290
  ctx.logger.warn("dataops-managed: workspace limits request failed");
1202
1291
  ctx.logger.warn(error);
1203
1292
  writeJson(response, 500, { error: error instanceof Error ? error.message : String(error) });
1204
1293
  }
1205
1294
  }
1206
1295
  }), "dataops-managed: workspace limits route");
1296
+ /**
1297
+ * The tool-call timeout, stored in this plugin's own Config.
1298
+ *
1299
+ * The settings service keeps the value in this workspace's document and updates the volatile
1300
+ * reference in place, so a change takes effect on the next connection without a restart. The
1301
+ * profile therefore does not have to anticipate how long a deployment's queries take.
1302
+ */
1303
+ ctx.effect(() => ctx.webServer.register({
1304
+ kind: "exact",
1305
+ path: TOOL_TIMEOUT_PATH,
1306
+ handler: async (request, response) => {
1307
+ const read = () => volatileValue(config.toolCallTimeoutMs, DEFAULT_TOOL_CALL_TIMEOUT_MS);
1308
+ if (request.method === "GET") {
1309
+ writeJson(response, 200, { toolCallTimeoutMs: read() });
1310
+ return;
1311
+ }
1312
+ if (request.method !== "POST") {
1313
+ response.writeHead(405, {
1314
+ allow: "GET, POST",
1315
+ "content-length": "0"
1316
+ });
1317
+ response.end();
1318
+ return;
1319
+ }
1320
+ try {
1321
+ const milliseconds = (await readJson(request))?.toolCallTimeoutMs;
1322
+ if (typeof milliseconds !== "number" || !Number.isSafeInteger(milliseconds)) {
1323
+ writeJson(response, 400, { error: "toolCallTimeoutMs must be a whole number of milliseconds" });
1324
+ return;
1325
+ }
1326
+ const seconds = milliseconds / 1e3;
1327
+ if (seconds < 1 || seconds > 3600) {
1328
+ writeJson(response, 400, { error: "the timeout must be between " + String(1) + " and " + String(TOOL_TIMEOUT_MAX_SECONDS) + " seconds" });
1329
+ return;
1330
+ }
1331
+ await ctx.settings.update(MANAGED_PLUGIN_ID, { toolCallTimeoutMs: milliseconds });
1332
+ writeJson(response, 200, { toolCallTimeoutMs: milliseconds });
1333
+ } catch (error) {
1334
+ ctx.logger.warn("dataops-managed: tool timeout request failed");
1335
+ ctx.logger.warn(error);
1336
+ writeJson(response, 500, { error: error instanceof Error ? error.message : String(error) });
1337
+ }
1338
+ }
1339
+ }), "dataops-managed: tool timeout route");
1340
+ await connectExisting();
1207
1341
  }
1208
1342
  /** Read and parse a JSON request body, tolerating an absent one. */
1209
1343
  async function readJson(request) {
@@ -1227,4 +1361,4 @@ function writeJson(response, status, body) {
1227
1361
  response.end(payload);
1228
1362
  }
1229
1363
  //#endregion
1230
- export { Config, MANAGED_AUTH_PATH, MANAGED_PLUGIN_ID, MODEL_SYNC_PATH, SKILL_PLAZA_PATH, WORKSPACE_LIMITS_PATH, apply, currentModelSync, currentSettingsSync, currentSkillPlaza, currentWorkspaceLimits, inject, name };
1364
+ export { Config, DEFAULT_TOOL_CALL_TIMEOUT_MS, MANAGED_AUTH_PATH, MANAGED_PLUGIN_ID, MODEL_SYNC_PATH, SKILL_PLAZA_PATH, TOOL_TIMEOUT_MAX_SECONDS, TOOL_TIMEOUT_MIN_SECONDS, TOOL_TIMEOUT_PATH, WORKSPACE_LIMITS_PATH, apply, currentModelSync, currentSettingsSync, currentSkillPlaza, currentWorkspaceLimits, inject, name };
@@ -1,6 +1,5 @@
1
1
  import type { InjectFace } from '@deepseek-ai/dsh-client-ui-slots';
2
2
  import type { en } from './locales.ts';
3
- import { MODEL_SYNC_PATH } from './model-sync-client.ts';
4
3
  /** Values injected by the DSH Settings slot. */
5
4
  export interface ManagedDataOpsSectionInjected {
6
5
  /** Translate one managed DataOps Settings message key. */
@@ -9,10 +8,9 @@ export interface ManagedDataOpsSectionInjected {
9
8
  /** Props accepted by the managed DataOps Settings section. */
10
9
  export type ManagedDataOpsSectionProps = Partial<InjectFace<ManagedDataOpsSectionInjected>>;
11
10
  /**
12
- * Explain the DataOps-managed JWT and permission owner, and share model configuration.
11
+ * The DataOps settings this workspace owns: its connection state, its branding, its file ceilings,
12
+ * and the default configuration it publishes to other workspaces.
13
13
  * @param props - Settings slot injection values.
14
14
  * @returns The localized managed DataOps section, or nothing before injection.
15
15
  */
16
16
  export declare function ManagedDataOpsSection(props: ManagedDataOpsSectionProps): import("react").JSX.Element | null;
17
- /** Re-exported so the settings entry can be discovered from the section alone. */
18
- export { MODEL_SYNC_PATH };
@@ -2,27 +2,26 @@
2
2
  export declare const en: {
3
3
  readonly nav: "DataOps";
4
4
  readonly title: "DataOps";
5
- readonly managed: "Managed by this DataOps workspace";
6
- readonly description: "DSH uses your current DataOps session JWT. DataOps applies its role and resource permissions to every tool request.";
7
- readonly identityLabel: "Identity and permissions";
8
- readonly identityValue: "Current DataOps JWT";
9
- readonly toolsLabel: "DataOps tools";
10
- readonly toolsValue: "Authorized by DataOps on every request";
11
- readonly brandingTitle: "Apply Wanxiang branding";
12
- readonly brandingDescription: "Use the Wanxiang Data Platform identity in navigation, the New Session welcome view, browser title, and favicon.";
13
- readonly brandingToggle: "Apply Wanxiang branding";
14
- readonly modelsTitle: "Model configuration";
15
- readonly modelsDescription: "Share the models configured here with other users, and choose which of them they may use.";
16
- readonly modelsUnavailable: "Model configuration is unavailable until this workspace is connected to DataOps.";
5
+ readonly managed: "Connected to DataOps";
6
+ readonly unavailable: "DataOps is not connected.";
7
+ readonly loadFailed: "Loading failed. Try again.";
8
+ readonly brandingTitle: "Wanxiang branding";
9
+ readonly brandingToggle: "Wanxiang branding";
10
+ readonly limitsTitle: "File size limits";
11
+ readonly limitsFileReadLabel: "Largest file to read (MiB)";
12
+ readonly limitsUploadLabel: "Largest file to upload (MiB)";
13
+ readonly limitsInvalid: "Enter a size in MiB.";
14
+ readonly limitsSave: "Save";
15
+ readonly limitsSaving: "Saving…";
16
+ readonly timeoutTitle: "Tool call timeout";
17
+ readonly timeoutLabel: "Longest single call (seconds)";
18
+ readonly timeoutInvalid: "Enter 1 to 3600 seconds.";
17
19
  readonly defaultsTitle: "Default configuration";
18
- readonly defaultsDescription: "Publish the configuration this workspace holds — models, permissions, and general settings — as the values other users start from. Their workspace takes that copy once and may then change anything, and a change they make is never overwritten.";
19
- readonly defaultsActionTitle: "Publish as the default";
20
- readonly defaultsNotAdmin: "Only an administrator may publish the default configuration.";
21
- readonly defaultsNeverPublished: "Not published yet.";
22
- readonly defaultsPublishedAt: "Last published:";
23
- readonly defaultsPublish: "Publish default configuration";
20
+ readonly defaultsPublish: "Publish";
24
21
  readonly defaultsPublishing: "Publishing…";
25
- readonly loadFailed: "The model configuration could not be loaded. Try again.";
22
+ readonly defaultsPublishedAt: "Last published";
23
+ readonly defaultsNeverPublished: "Not published yet";
24
+ readonly defaultsNotAdmin: "Administrators only";
26
25
  readonly plazaTitle: "Skill plaza";
27
26
  readonly plazaIntro: "Skills other users shared. Install one to use it in this workspace, or share a skill of your own.";
28
27
  readonly plazaSearch: "Search skills";
@@ -39,14 +38,6 @@ export declare const en: {
39
38
  readonly plazaActionFailed: "The action could not be completed. Try again.";
40
39
  readonly plazaRetry: "Try again";
41
40
  readonly plazaRefresh: "Refresh";
42
- readonly limitsTitle: "Workspace limits";
43
- readonly limitsDescription: "The largest files this workspace may read and upload. Set by an administrator in DataOps.";
44
- readonly limitsUnavailable: "Workspace limits are available once this workspace is connected to DataOps.";
45
- readonly limitsFileReadLabel: "Largest file to read";
46
- readonly limitsUploadLabel: "Largest file to upload";
47
- readonly limitsUnit: "Units are MiB.";
48
- readonly limitsSave: "Save limits";
49
- readonly limitsSaving: "Saving…";
50
41
  };
51
42
  /** Stable key set shared by every managed DataOps locale. */
52
43
  export type ManagedDataOpsKey = keyof typeof en;
@@ -0,0 +1,22 @@
1
+ /** Same-origin tool-call timeout calls from the DataOps settings surface. */
2
+ /** Route the plugin's Host half serves for the tool-call timeout. */
3
+ export declare const TOOL_TIMEOUT_PATH = "/integrations/dataops/tool-timeout";
4
+ /** The two ends a timeout may take, in seconds, matching what the Host enforces. */
5
+ export declare const TOOL_TIMEOUT_MIN_SECONDS = 1;
6
+ export declare const TOOL_TIMEOUT_MAX_SECONDS = 3600;
7
+ /** The timeout as this workspace currently holds it. */
8
+ export interface ToolTimeout {
9
+ /** How long one tool call may run before it is abandoned. */
10
+ toolCallTimeoutMs: number;
11
+ }
12
+ /**
13
+ * Read the tool-call timeout the panel shows.
14
+ * @returns The timeout, or null when the workspace is not connected.
15
+ */
16
+ export declare function fetchToolTimeout(): Promise<ToolTimeout | null>;
17
+ /**
18
+ * Store a new tool-call timeout.
19
+ * @param milliseconds - How long one tool call may run.
20
+ * @returns The stored timeout, or null when the workspace is not connected.
21
+ */
22
+ export declare function saveToolTimeout(milliseconds: number): Promise<ToolTimeout | null>;
@@ -14,6 +14,15 @@ export interface WorkspaceLimitsStatus {
14
14
  canWrite: boolean;
15
15
  readOnlyReason: string | null;
16
16
  }
17
+ /**
18
+ * A write DataOps refused, carrying the reason it gave.
19
+ *
20
+ * The message is written for the person who set the value, so the panel shows it as-is rather
21
+ * than replacing it with a generic failure notice.
22
+ */
23
+ export declare class WorkspaceLimitsRejection extends Error {
24
+ constructor(message: string);
25
+ }
17
26
  /**
18
27
  * Read the workspace limits the panel shows.
19
28
  * @returns The status, or null when the workspace is not connected to DataOps.
@@ -18,6 +18,11 @@ export declare const MODEL_SYNC_PATH = "/integrations/dataops/model-sync";
18
18
  export declare const SKILL_PLAZA_PATH = "/integrations/dataops/skill-plaza";
19
19
  /** Same-origin route the Settings panel uses to read and change this workspace's limits. */
20
20
  export declare const WORKSPACE_LIMITS_PATH = "/integrations/dataops/workspace-limits";
21
+ /** Same-origin route the Settings panel uses to read and change the tool-call timeout. */
22
+ export declare const TOOL_TIMEOUT_PATH = "/integrations/dataops/tool-timeout";
23
+ /** The ends a tool-call timeout may take, in whole seconds. */
24
+ export declare const TOOL_TIMEOUT_MIN_SECONDS = 1;
25
+ export declare const TOOL_TIMEOUT_MAX_SECONDS = 3600;
21
26
  /** The live skill plaza, once this plugin activated. */
22
27
  export declare function currentSkillPlaza(): SkillPlaza | undefined;
23
28
  /** The live model-sync instance, once this plugin activated. */
@@ -25,6 +30,18 @@ export declare function currentModelSync(): ModelSync | undefined;
25
30
  export { currentWorkspaceLimits };
26
31
  /** @returns The live instance, or undefined before this plugin activated. */
27
32
  export declare function currentSettingsSync(): SettingsSync | undefined;
33
+ /**
34
+ * A volatile config reference.
35
+ *
36
+ * A field marked volatile is not stored with the plugin's own configuration: the settings
37
+ * service keeps it in this workspace's document and hands the plugin a reference that it
38
+ * updates in place, so a value written through the Settings panel is visible without a
39
+ * restart. Reading the field directly therefore reads the reference, not the value.
40
+ */
41
+ interface VolatileRef<T> {
42
+ /** The current value behind the reference. */
43
+ get(): T;
44
+ }
28
45
  /** Configuration for the DataOps-managed MCP connection. */
29
46
  export interface Config {
30
47
  /** DataOps browser/API origin reachable from the DSH Host. */
@@ -33,23 +50,32 @@ export interface Config {
33
50
  serverName: string;
34
51
  /** DSH credential reference that stores the current DataOps access JWT. */
35
52
  credentialRef: string;
36
- /** Per-tool-call timeout forwarded to the MCP client. */
37
- toolCallTimeoutMs: number;
53
+ /**
54
+ * Per-tool-call timeout forwarded to the MCP client.
55
+ *
56
+ * Volatile, so the settings service stores the platform default in this workspace's document
57
+ * and the panel can raise it without a profile edit. The read goes through `volatileValue`.
58
+ */
59
+ toolCallTimeoutMs: number | VolatileRef<number>;
38
60
  /**
39
61
  * Model-sync state this workspace keeps.
40
62
  *
41
63
  * Volatile, so the settings service stores it in this workspace's own document. It belongs
42
64
  * to the workspace rather than to DataOps because it records whether the user here wrote
43
65
  * their own models, which is a fact about this workspace.
66
+ *
67
+ * Volatile, so the runtime supplies a reference and the read goes through `volatileValue`.
44
68
  */
45
- modelSync: ModelSyncState;
69
+ modelSync: ModelSyncState | VolatileRef<ModelSyncState>;
46
70
  /**
47
71
  * Settings-distribution state this workspace keeps.
48
72
  *
49
73
  * Volatile, like the model-sync state beside it, and for the same reason: it records whether
50
74
  * the user here wrote their own values, which is a fact about this workspace.
75
+ *
76
+ * Volatile, like the field above, so the read goes through `volatileValue`.
51
77
  */
52
- settingsSync: SectionSyncState;
78
+ settingsSync: SectionSyncState | VolatileRef<SectionSyncState>;
53
79
  /**
54
80
  * Settings namespaces this deployment distributes to other workspaces.
55
81
  *
@@ -67,6 +93,14 @@ export interface ModelSyncState {
67
93
  /** Model ids the administrator keeps private; every other model is offered by default. */
68
94
  privateModelIds: string[];
69
95
  }
96
+ /**
97
+ * Per-tool-call timeout a workspace starts with.
98
+ *
99
+ * Named rather than inlined so the schema default and the read fallback cannot drift: the field is
100
+ * volatile, so a workspace that never changed it reads no value at all and both places have to
101
+ * answer the same number.
102
+ */
103
+ export declare const DEFAULT_TOOL_CALL_TIMEOUT_MS = 300000;
70
104
  /** Schemastery parser for managed DataOps configuration. */
71
105
  export declare const Config: z<Config>;
72
106
  /**
@@ -23,6 +23,19 @@ export interface WorkspaceLimitsConfig {
23
23
  /** DSH credential reference holding the current DataOps access JWT. */
24
24
  credentialRef: string;
25
25
  }
26
+ /**
27
+ * A rejection DataOps answered with, carrying its status and message.
28
+ *
29
+ * Without this the caller can only tell that something failed, and a value DataOps refused —
30
+ * which the user can correct — is indistinguishable from a fault in the request path.
31
+ */
32
+ export declare class WorkspaceLimitsRejection extends Error {
33
+ /** HTTP status DataOps answered with. */
34
+ readonly status: number;
35
+ constructor(
36
+ /** HTTP status DataOps answered with. */
37
+ status: number, message: string);
38
+ }
26
39
  /**
27
40
  * The workspace limits an administrator sets in DataOps.
28
41
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sparkelf/dsh-dataops-managed",
3
- "version": "0.3.14",
3
+ "version": "0.3.16",
4
4
  "description": "DataOps JWT intake and credential-backed MCP tools for managed DeepSeek Harness workspaces.",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
@@ -73,7 +73,7 @@
73
73
  "@deepseek-ai/dsh-settings": ">=0.1.7-rc.2",
74
74
  "@deepseek-ai/dsh-skill": ">=0.2.0-rc.2",
75
75
  "@deepseek-ai/dsh-tools": ">=0.1.7-rc.2",
76
- "@deepseek-ai/schemastery": ">=3.18.1",
76
+ "@deepseek-ai/schemastery": ">=3.18.4",
77
77
  "@sparkelf/dsh-plugin-mcp-credentials": ">=0.1.0-rc.14",
78
78
  "react": ">=18.2.0 <20"
79
79
  },
@@ -91,7 +91,7 @@
91
91
  "@deepseek-ai/dsh-settings": "0.1.7-rc.2",
92
92
  "@deepseek-ai/dsh-skill": "0.2.0-rc.2",
93
93
  "@deepseek-ai/dsh-tools": "0.1.7-rc.2",
94
- "@deepseek-ai/schemastery": "3.18.2",
94
+ "@deepseek-ai/schemastery": "3.18.4",
95
95
  "@sparkelf/dsh-client-ui-skill-center": "0.2.0-rc.46",
96
96
  "@sparkelf/dsh-plugin-mcp-credentials": "0.1.0-rc.14",
97
97
  "@types/react": "~18.3.1",