@sparkelf/dsh-dataops-managed 0.3.21 → 0.3.22

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.
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Compact search over the DataOps OpenAPI document.
3
+ *
4
+ * The document can be tens of thousands of lines; a model needs the operation that answers its
5
+ * question, not the whole contract. This module reads `paths` and returns only the fields that
6
+ * identify and parametrize a matching operation: method, path, operationId, summary, tags,
7
+ * parameters, request-body shape and security. It never executes anything and never accepts a
8
+ * URL: the caller names the fixed `/api/openapi.json` document, and the search stays inside it.
9
+ *
10
+ * @module api-docs
11
+ */
12
+ /** JSON-safe content a tool may return. */
13
+ type Json = null | boolean | number | string | Json[] | {
14
+ [key: string]: Json;
15
+ };
16
+ /** One compact parameter row. */
17
+ export interface ApiDocParameter {
18
+ name: string;
19
+ in: string;
20
+ required: boolean;
21
+ type: string;
22
+ }
23
+ /** A compact request-body description. */
24
+ export interface ApiDocRequestBody {
25
+ required: boolean;
26
+ contentTypes: string[];
27
+ schema: ApiDocSchemaSummary | null;
28
+ }
29
+ /** A compact schema projection: enough to see the fields a call needs. */
30
+ export interface ApiDocSchemaSummary {
31
+ type?: string;
32
+ ref?: string;
33
+ required?: string[];
34
+ properties?: Array<{
35
+ name: string;
36
+ type: string;
37
+ required: boolean;
38
+ }>;
39
+ }
40
+ /** One operation as the tool returns it. */
41
+ export interface ApiDocOperation {
42
+ method: string;
43
+ path: string;
44
+ operationId: string | null;
45
+ summary: string | null;
46
+ tags: string[];
47
+ parameters: ApiDocParameter[];
48
+ requestBody: ApiDocRequestBody | null;
49
+ security: Json[];
50
+ }
51
+ /** Everything the tool needs to report one search. */
52
+ export interface ApiDocsSearchResult {
53
+ title: string | null;
54
+ version: string | null;
55
+ openapi: string | null;
56
+ total: number;
57
+ returned: number;
58
+ truncated: boolean;
59
+ results: ApiDocOperation[];
60
+ }
61
+ /** Filters accepted by {@link searchOpenApiDocument}. */
62
+ export interface ApiDocsFilters {
63
+ query?: string;
64
+ tag?: string;
65
+ path?: string;
66
+ operation_id?: string;
67
+ method?: string;
68
+ }
69
+ /** Raised when the upstream body is not an OpenAPI document this module can search. */
70
+ export declare class ApiDocsUnavailableError extends Error {
71
+ }
72
+ /**
73
+ * Search one parsed OpenAPI document.
74
+ * @param document - Parsed `/api/openapi.json` body.
75
+ * @param filters - Keyword, tag, path, operationId and method filters.
76
+ * @returns Matching operations, bounded and ordered by relevance.
77
+ * @throws ApiDocsUnavailableError when the document has no searchable `paths` object.
78
+ */
79
+ export declare function searchOpenApiDocument(document: unknown, filters?: ApiDocsFilters): ApiDocsSearchResult;
80
+ export {};
@@ -16,6 +16,19 @@
16
16
  */
17
17
  /** What the last DataOps answer said about the stored credential. */
18
18
  export type AuthState = 'unknown' | 'valid' | 'expired';
19
+ /** One observer of the recorded credential observation. */
20
+ export type AuthStateListener = (state: AuthState) => void;
21
+ /**
22
+ * Observe every recorded transition.
23
+ *
24
+ * The tool manager uses this to drop its disclosure as soon as any DataOps call reports a 401:
25
+ * the scope that produced the tool list can no longer be trusted, and waiting for another
26
+ * explicit sync would leave tools offered against an ended session. Listener failures are
27
+ * contained so a broken observer cannot turn a credential observation into a failed call.
28
+ * @param listener - Called with the new state after it is recorded.
29
+ * @returns The exact unsubscriber.
30
+ */
31
+ export declare const onAuthStateChange: (listener: AuthStateListener) => (() => void);
19
32
  /**
20
33
  * Record that a DataOps call was accepted.
21
34
  *
@@ -7,11 +7,9 @@
7
7
  * signed in any more. This prompt names that state once, with the one action that clears it.
8
8
  *
9
9
  * It reports and nothing more. It does not retry, expire, or re-authenticate — the portal owns
10
- * the login form and is the only thing that can issue a session. It also cannot navigate the
11
- * operator there: the portal is a different origin, so this frame cannot read or drive its
12
- * window, and the gateway does not forward the browser's origin to the workspace. Guessing a
13
- * URL from inside here would open the wrong page on some deployments, so the dialog tells the
14
- * operator which window to switch to instead of pretending it can take them.
10
+ * the login form and is the only thing that can issue a session. Its action navigates the parent
11
+ * portal when the frame's ancestor origin is known, and opens the portal separately when the
12
+ * browser blocks top-level navigation from the frame.
15
13
  *
16
14
  * @module ReloginPrompt
17
15
  */
@@ -1,9 +1,9 @@
1
1
  /** English managed DataOps Settings copy. */
2
2
  export declare const en: {
3
- readonly nav: "DataOps";
4
- readonly title: "DataOps";
5
- readonly managed: "Connected to DataOps";
6
- readonly unavailable: "DataOps is not connected.";
3
+ readonly nav: "万相AI中台";
4
+ readonly title: "万相AI中台";
5
+ readonly managed: "Connected to 万相AI中台";
6
+ readonly unavailable: "万相AI中台 is not connected.";
7
7
  readonly loadFailed: "Loading failed. Try again.";
8
8
  readonly brandingTitle: "Wanxiang branding";
9
9
  readonly brandingToggle: "Wanxiang branding";
@@ -13,7 +13,7 @@ export declare const en: {
13
13
  readonly limitsInvalid: "Enter a size in MiB.";
14
14
  readonly limitsSave: "Save";
15
15
  readonly limitsSaving: "Saving…";
16
- readonly timeoutTitle: "DataOps query timeout";
16
+ readonly timeoutTitle: "万相AI中台 query timeout";
17
17
  readonly timeoutLabel: "Longest single query (seconds)";
18
18
  readonly timeoutInvalid: "Enter 1 to 3600 seconds.";
19
19
  readonly defaultsTitle: "Default configuration";
@@ -34,7 +34,7 @@ export declare const en: {
34
34
  readonly plazaUnshare: "Stop sharing";
35
35
  readonly plazaUnshared: "Removed from the plaza. Users who installed it keep their copy.";
36
36
  readonly plazaEmpty: "No skills have been shared yet.";
37
- readonly plazaUnavailable: "The skill plaza is available once this workspace is connected to DataOps.";
37
+ readonly plazaUnavailable: "The skill plaza is available once this workspace is connected to 万相AI中台.";
38
38
  readonly plazaLoadFailed: "The skill plaza could not be loaded. Try again.";
39
39
  readonly plazaActionFailed: "The action could not be completed. Try again.";
40
40
  readonly plazaRetry: "Try again";
@@ -123,9 +123,9 @@ export declare const en: {
123
123
  readonly permStatusApproved: "Approved";
124
124
  readonly permStatusRejected: "Rejected";
125
125
  readonly permDemo: "Demo data";
126
- readonly reloginTitle: "Sign in to DataOps again";
127
- readonly reloginBody: "This workspace can no longer reach DataOps: the sign-in for this session has ended, so settings, shared models and the skill plaza cannot load. Sign in again in the DataOps window, then reload this page.";
128
- readonly reloginAction: "Reload";
126
+ readonly reloginTitle: "Sign in to 万相AI中台 again";
127
+ readonly reloginBody: "Please sign in again.";
128
+ readonly reloginAction: "Sign in again";
129
129
  readonly reloginDismiss: "Later";
130
130
  readonly upgradeAvailableTitle: "A new workspace version is available";
131
131
  readonly upgradeAvailableBody: "Restart the workspace to apply it.";
@@ -0,0 +1,51 @@
1
+ /**
2
+ * The DataOps connector's workspace-visible state and skill-center catalogue.
3
+ *
4
+ * The skill center is skill-first, with connectors as its fourth tab. DataOps contributes one
5
+ * connector whose capability rows are derived from the same scope that drives tool disclosure;
6
+ * a capability the account cannot use is omitted rather than rendered as a disabled placeholder.
7
+ *
8
+ * This module owns only state and presentation. It never authorizes a tool call or a DataOps
9
+ * request: the backend remains the final boundary.
10
+ *
11
+ * @module connector-state
12
+ */
13
+ import { type DataOpsScope } from './tool-scope.ts';
14
+ /** Same-origin route the skill center's connector tab reads and writes. */
15
+ export declare const CONNECTORS_PATH = "/api/dsh-skill-center/connectors";
16
+ /** Connector id shown in the skill center. */
17
+ export declare const DATAOPS_CONNECTOR_ID = "dataops-managed";
18
+ /** Persisted enable state; a missing file means the connector is off. */
19
+ export interface DataOpsConnectorState {
20
+ enabled: boolean;
21
+ capabilities: Record<string, boolean>;
22
+ }
23
+ /** One capability row the skill center renders. */
24
+ export interface ConnectorCapabilityView {
25
+ id: string;
26
+ name: string;
27
+ description: string;
28
+ enabled: boolean;
29
+ permitted: boolean;
30
+ unavailableReason?: string;
31
+ }
32
+ /** One connector row the skill center renders. */
33
+ export interface ConnectorView {
34
+ id: string;
35
+ name: string;
36
+ vendor: string;
37
+ description: string;
38
+ enabled: boolean;
39
+ connected: boolean;
40
+ capabilities: ConnectorCapabilityView[];
41
+ }
42
+ /** Resolve the persisted state file without depending on a global DSH path. */
43
+ export declare const CONNECTOR_STATE_PATH: string;
44
+ /** Read state; a missing or corrupt file is a safe disabled state. */
45
+ export declare function readConnectorState(path?: string): Promise<DataOpsConnectorState>;
46
+ /** Persist state atomically. */
47
+ export declare function writeConnectorState(state: DataOpsConnectorState, path?: string): Promise<void>;
48
+ /** Build the connector row for one current scope. */
49
+ export declare function buildConnectorView(scope: DataOpsScope | undefined, state: DataOpsConnectorState): ConnectorView;
50
+ /** Whether one capability id is in the fixed catalogue. */
51
+ export declare function hasCapability(id: string): boolean;
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Owns the managed tool set for the workspace's current DataOps principal.
3
+ *
4
+ * A DSH workspace belongs to exactly one DataOps user, so the model's tool list can be derived
5
+ * from that user's current scope. The manager is the only writer of that list: it reads
6
+ * `/api/ai/review/context` when the credential changes (the `credentials/reference-updated`
7
+ * event, which is also what JWT adoption and `managed-auth` produce), on the first connect, and
8
+ * when the review-context route observes a different role set. It then reconciles the registry:
9
+ * newly allowed tools are registered, tools the role lost are disposed, and tools that remain
10
+ * allowed keep their registration.
11
+ *
12
+ * The manager never runs inside a tool call. Execution-time authorization belongs to DataOps;
13
+ * this is disclosure, so a scope sync that fails transiently keeps the current set rather than
14
+ * flapping, while a definitive 401/403/404/503 clears it.
15
+ *
16
+ * @module tool-manager
17
+ */
18
+ import type { Context } from '@deepseek-ai/cordis';
19
+ import type { ReviewApi, ReviewApiResult } from './review-api.ts';
20
+ import { type AiToolName, type DataOpsScope } from './tool-scope.ts';
21
+ /**
22
+ * Reconcile the managed tools with the current DataOps scope.
23
+ *
24
+ * Construct once per plugin activation. `refresh` is idempotent and coalesces concurrent calls;
25
+ * the constructor also subscribes to the credential observation so an expired session removes
26
+ * the tools without waiting for another explicit sync.
27
+ */
28
+ export declare class AiToolManager {
29
+ private readonly ctx;
30
+ private readonly reviewApi;
31
+ private readonly definitions;
32
+ private readonly registrations;
33
+ private readonly unsubscribeExpiry;
34
+ private disposeViewer;
35
+ private scope;
36
+ private revision;
37
+ private inflight;
38
+ private disposed;
39
+ constructor(ctx: Context, reviewApi: ReviewApi);
40
+ /** The scope the current registration set was derived from, when one has been read. */
41
+ currentScope(): DataOpsScope | undefined;
42
+ /** The tool names currently registered, for diagnostics and tests. */
43
+ registeredToolNames(): AiToolName[];
44
+ /**
45
+ * Re-read the workspace's DataOps scope and reconcile the tool list.
46
+ *
47
+ * Definitive denials clear the list; transient failures (network, 5xx) keep what the last good
48
+ * observation produced. The method never throws: sync happens in the background of a browser
49
+ * request and must not fail that request.
50
+ * @param force - Start a new read even when one is already in flight. Credential adoption uses
51
+ * this because an older read may have captured the previous token; its answer must not win
52
+ * over the scope the new token produces.
53
+ */
54
+ refresh(force?: boolean): Promise<void>;
55
+ /**
56
+ * Apply a context answer already fetched by a same-origin route.
57
+ *
58
+ * The review-context route is how the UI learns about a role change, so its answer is also the
59
+ * freshest scope this plugin will see. Reusing it avoids a second fetch on a page that polls.
60
+ * @param result - The upstream status and parsed body.
61
+ */
62
+ observeContext(result: ReviewApiResult): void;
63
+ /**
64
+ * Apply one parsed context body without contacting DataOps.
65
+ * @param body - Parsed `/api/ai/review/context` body.
66
+ */
67
+ applyContext(body: unknown): void;
68
+ /** Drop every managed tool because no usable DataOps scope is known. */
69
+ clear(): void;
70
+ /** Dispose every tool this manager registered and stop observing auth state. */
71
+ dispose(): void;
72
+ private loadScope;
73
+ /** Store the scope and make the registry match it. */
74
+ private applyScope;
75
+ /** Map one DataOps scope to the skill registry's audience filter. */
76
+ private applyViewer;
77
+ /** Dispose one registration, tolerating a disposer that has already run. */
78
+ private disposeRegistration;
79
+ /** Dispose the whole current set. */
80
+ private disposeRegistrations;
81
+ }
@@ -0,0 +1,25 @@
1
+ /**
2
+ * The canonical output contract shared by this plugin's model tools.
3
+ *
4
+ * Every managed tool returns one JSON value and renders it as pretty-printed text. Keeping the
5
+ * schema and renderer in one place means a new tool cannot accidentally return a shape the tool
6
+ * registry rejects.
7
+ *
8
+ * @module tool-output
9
+ */
10
+ /** JSON-safe content a tool may return. */
11
+ export type Json = null | boolean | number | string | Json[] | {
12
+ [key: string]: Json;
13
+ };
14
+ /** One text block as the tool registry accepts it. */
15
+ export type ToolContent = {
16
+ type: 'text';
17
+ text: string;
18
+ };
19
+ /** An open object schema: tools declare their canonical shape in code and docs. */
20
+ export declare const OPEN_OBJECT_SCHEMA: {
21
+ readonly type: "object";
22
+ readonly additionalProperties: true;
23
+ };
24
+ /** Render one canonical value as pretty JSON text. */
25
+ export declare const renderJson: (_args: unknown, value: unknown) => ToolContent[];
@@ -0,0 +1,156 @@
1
+ /**
2
+ * Which DataOps tools this workspace's model may see.
3
+ *
4
+ * This module is disclosure, not authorization. DataOps remains the only authority for every
5
+ * API call: its AuthGuard and PermissionGuard resolve the caller's current roles and grants,
6
+ * and every managed tool call still crosses that boundary. What happens here is narrower — a
7
+ * DSH workspace belongs to one DataOps principal, so the tool schemas offered to the model can
8
+ * follow that principal's current scope instead of advertising operations the role cannot use.
9
+ *
10
+ * The scope is the answer `/api/ai/review/context` gives for the stored JWT. It is read when the
11
+ * credential changes, on the first connect, and when the review-context route observes a new
12
+ * role set — never inside a tool `execute`. A tool that is already registered and whose role
13
+ * loses the capability is disposed by the manager.
14
+ *
15
+ * @module tool-scope
16
+ */
17
+ /** The subset of `/api/ai/review/context` that tool disclosure needs. */
18
+ export interface DataOpsScope {
19
+ /** Stable DataOps user id. */
20
+ userId?: string;
21
+ /** Login name, used only for diagnostics. */
22
+ username?: string;
23
+ /** Role display codes such as 超级管理员/管理员/部门管理员/应用人员. */
24
+ roleCodes?: string[];
25
+ /** The primary role code; DataOps normalizes it to one of the four portal roles. */
26
+ primaryRole?: string;
27
+ /** Stable role keys such as SUPER_ADMIN, when the context carries them. */
28
+ systemKeys?: string[];
29
+ /** The caller's department, when one is assigned. */
30
+ departmentCode?: string | null;
31
+ /**
32
+ * Effective permission keys from every role the caller holds.
33
+ *
34
+ * `permissions` is the current backend field; `permissionKeys` is accepted while a deployment
35
+ * still serves the older shape. A present but empty array is a denial, not a reason to fall
36
+ * back to role names.
37
+ */
38
+ permissions?: string[];
39
+ /** Older spelling of {@link permissions}. */
40
+ permissionKeys?: string[];
41
+ /** Data scope DataOps resolved for the caller. */
42
+ dataScope?: {
43
+ all?: boolean;
44
+ self?: boolean;
45
+ departmentCodes?: string[];
46
+ };
47
+ /** Review capability as the current context reports it (older nested shape). */
48
+ review?: {
49
+ canReview?: boolean;
50
+ canReviewGlobal?: boolean;
51
+ canManagePermissions?: boolean;
52
+ };
53
+ /** Review capability as the current context reports it (top-level shape). */
54
+ canReview?: boolean;
55
+ /** Whether the caller may review global (department-less) resources. */
56
+ canReviewGlobal?: boolean;
57
+ }
58
+ /** The permission each managed tool needs before it is offered to the model. */
59
+ export interface ToolAccessPolicy {
60
+ /** One `skill:*` capability; checked against the context's effective permission list. */
61
+ readonly permission?: string;
62
+ /** Review capability from the context, independent of a permission key. */
63
+ readonly reviewer?: boolean;
64
+ /** Only the DataOps 超级管理员 role sees this tool. */
65
+ readonly superAdminOnly?: boolean;
66
+ }
67
+ /**
68
+ * Tool-to-capability disclosure map.
69
+ *
70
+ * `review_notifications_list/read` intentionally carry no policy: every authenticated principal
71
+ * owns their own notification inbox. `dataops_api_docs` is gated by the role itself because the
72
+ * backend grants the OpenAPI reader to 超级管理员 by default; an administrator who happens to hold
73
+ * `developer:openapi:read` is still outside that role and does not receive the tool.
74
+ */
75
+ export declare const AI_TOOL_ACCESS: {
76
+ readonly skill_list: {
77
+ readonly permission: "skill:read";
78
+ };
79
+ readonly skill_get: {
80
+ readonly permission: "skill:read";
81
+ };
82
+ readonly skill_submit: {
83
+ readonly permission: "skill:submit";
84
+ };
85
+ readonly skill_install: {
86
+ readonly permission: "skill:install";
87
+ };
88
+ readonly skill_uninstall: {
89
+ readonly permission: "skill:install";
90
+ };
91
+ readonly skill_enable: {
92
+ readonly permission: "skill:manage";
93
+ };
94
+ readonly skill_disable: {
95
+ readonly permission: "skill:manage";
96
+ };
97
+ readonly skill_unshare: {
98
+ readonly permission: "skill:manage";
99
+ };
100
+ readonly skill_delete: {
101
+ readonly permission: "skill:manage";
102
+ };
103
+ readonly review_scan: {
104
+ readonly permission: "skill:read";
105
+ readonly reviewer: true;
106
+ };
107
+ readonly review_decide: {
108
+ readonly permission: "skill:review:decide";
109
+ readonly reviewer: true;
110
+ };
111
+ readonly review_notifications_list: {};
112
+ readonly review_notifications_read: {};
113
+ readonly dataops_api_docs: {
114
+ readonly superAdminOnly: true;
115
+ };
116
+ };
117
+ /** Every managed tool name, in the order the manager considers them. */
118
+ export declare const AI_TOOL_NAMES: AiToolName[];
119
+ /** One managed tool name. */
120
+ export type AiToolName = keyof typeof AI_TOOL_ACCESS;
121
+ /** Whether the context carries the stable super-administrator role. */
122
+ export declare const isSuperAdmin: (scope: DataOpsScope) => boolean;
123
+ /** Whether the context carries an administrator or super-administrator role. */
124
+ export declare const isAdmin: (scope: DataOpsScope) => boolean;
125
+ /** Whether the context carries a department-administrator role. */
126
+ export declare const isDepartmentAdmin: (scope: DataOpsScope) => boolean;
127
+ /**
128
+ * Whether the caller may run review operations.
129
+ *
130
+ * The current backend returns `canReview` at the top level; the nested `review` shape is
131
+ * accepted for older contexts. Role membership is a fallback, not an override.
132
+ */
133
+ export declare const canReview: (scope: DataOpsScope) => boolean;
134
+ /**
135
+ * Whether the caller holds one capability.
136
+ *
137
+ * A context that carries a permission list is authoritative. Before the list existed, the
138
+ * four-role fallback kept the old behavior; it is only used when neither spelling is present.
139
+ */
140
+ export declare const hasPermission: (scope: DataOpsScope, key: string) => boolean;
141
+ /**
142
+ * Whether one tool should be registered for this scope.
143
+ *
144
+ * Every check is disclosure metadata, not an execution gate: a visible tool still lets DataOps
145
+ * answer with 403 when the underlying grant changed between a scope sync and the call.
146
+ */
147
+ export declare function isToolVisible(name: AiToolName, scope: DataOpsScope): boolean;
148
+ /**
149
+ * Validate one `/api/ai/review/context` body.
150
+ *
151
+ * A body without `roleCodes` is not a usable scope: treating it as "no roles" would let the
152
+ * role-name fallback hand an ordinary capability set to an answer this plugin cannot interpret.
153
+ * @param body - Parsed JSON from the context endpoint.
154
+ * @returns The normalized scope, or undefined when the answer is not a context document.
155
+ */
156
+ export declare function normalizeScope(body: unknown): DataOpsScope | undefined;
@@ -1,10 +1,12 @@
1
1
  /**
2
- * Model tools for the skill centre and the shared review queues.
2
+ * Model tools for the skill centre, the shared review queues, and the DataOps API reference.
3
3
  *
4
- * Every tool reads the caller's DataOps role from `/api/ai/review/context` and asks DataOps on
5
- * every call; the Host never caches an authorization decision. Mutations require user approval
6
- * and write an audit line. Secret material is never a parameter and never a return value: the
7
- * API only sees the workspace JWT that the credential service already holds.
4
+ * Registration is disclosure, not authorization. `AiToolManager` computes the workspace's
5
+ * current DataOps scope once per credential/role sync and registers only the tools that scope
6
+ * can use; these definitions assume they were registered for a principal that may call them.
7
+ * Every `execute` therefore validates parameters, asks for user approval where a mutation needs
8
+ * it, writes its audit line, and lets DataOps answer — no per-call role read, no local permission
9
+ * tree, and no replacement for the backend's AuthGuard/PermissionGuard.
8
10
  *
9
11
  * The skill plaza is the catalogue. `scope=mine` exposes the caller's pending/rejected rows,
10
12
  * the public list exposes what the caller may install, and the admin list (administrators only)
@@ -16,6 +18,24 @@
16
18
  * @module tools
17
19
  */
18
20
  import type { Context } from '@deepseek-ai/cordis';
21
+ import { type ToolDefinition } from '@deepseek-ai/dsh-tools';
19
22
  import type { ReviewApi } from './review-api.ts';
20
- /** Register the skill-centre and review tools. */
21
- export declare function registerAiManagementTools(ctx: Context, reviewApi: ReviewApi): () => void;
23
+ import { type AiToolName, type DataOpsScope } from './tool-scope.ts';
24
+ /** One managed tool together with the name the disclosure map uses. */
25
+ export interface AiManagedTool {
26
+ name: AiToolName;
27
+ definition: ToolDefinition;
28
+ }
29
+ /**
30
+ * Build every managed tool definition.
31
+ *
32
+ * The definitions are built once; `readScope` is a live getter so a tool that survives a role
33
+ * change reports the scope the manager currently holds instead of the one it was registered
34
+ * with. An undefined scope can only be observed by an in-flight call during disposal, where the
35
+ * safe behavior is to show only the public catalogue.
36
+ * @param ctx - Host context used for local skills, approval and audit.
37
+ * @param reviewApi - Same-origin bridge holding the workspace JWT.
38
+ * @param readScope - Live accessor for the manager's current scope.
39
+ * @returns One definition per managed tool name.
40
+ */
41
+ export declare function buildAiManagementTools(ctx: Context, reviewApi: ReviewApi, readScope: () => DataOpsScope | undefined): AiManagedTool[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sparkelf/dsh-dataops-managed",
3
- "version": "0.3.21",
3
+ "version": "0.3.22",
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",