@superdoc-dev/sdk 1.0.0-alpha.3 → 1.0.0-alpha.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/README.md +124 -0
- package/dist/generated/client.cjs +284 -0
- package/dist/generated/client.d.ts +8167 -0
- package/dist/generated/client.d.ts.map +1 -0
- package/dist/generated/client.js +279 -0
- package/dist/generated/contract.cjs +82368 -0
- package/dist/generated/contract.d.ts +34 -0
- package/dist/generated/contract.d.ts.map +1 -0
- package/dist/generated/contract.js +82383 -0
- package/dist/helpers/format.d.ts +79 -0
- package/dist/helpers/format.d.ts.map +1 -0
- package/dist/helpers/format.js +121 -0
- package/dist/index.cjs +45 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +29 -0
- package/dist/runtime/embedded-cli.cjs +100 -0
- package/dist/runtime/embedded-cli.d.ts +5 -0
- package/dist/runtime/embedded-cli.d.ts.map +1 -0
- package/dist/runtime/embedded-cli.js +94 -0
- package/dist/runtime/errors.cjs +22 -0
- package/dist/runtime/errors.d.ts +17 -0
- package/dist/runtime/errors.d.ts.map +1 -0
- package/dist/runtime/errors.js +18 -0
- package/dist/runtime/host.cjs +352 -0
- package/dist/runtime/host.d.ts +37 -0
- package/dist/runtime/host.d.ts.map +1 -0
- package/dist/runtime/host.js +347 -0
- package/dist/runtime/process.cjs +32 -0
- package/dist/runtime/process.d.ts +16 -0
- package/dist/runtime/process.d.ts.map +1 -0
- package/dist/runtime/process.js +27 -0
- package/dist/runtime/transport-common.cjs +77 -0
- package/dist/runtime/transport-common.d.ts +49 -0
- package/dist/runtime/transport-common.d.ts.map +1 -0
- package/dist/runtime/transport-common.js +72 -0
- package/dist/skills.cjs +148 -0
- package/dist/skills.d.ts +25 -0
- package/dist/skills.d.ts.map +1 -0
- package/dist/skills.js +140 -0
- package/dist/tools.cjs +307 -0
- package/dist/tools.d.ts +90 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +296 -0
- package/package.json +21 -11
- package/skills/editing-docx.md +24 -150
- package/tools/catalog.json +38846 -0
- package/tools/tool-name-map.json +179 -0
- package/tools/tools-policy.json +97 -0
- package/tools/tools.anthropic.json +17311 -0
- package/tools/tools.generic.json +37596 -0
- package/tools/tools.openai.json +17845 -0
- package/tools/tools.vercel.json +17845 -0
- package/src/__tests__/skills.test.ts +0 -166
- package/src/__tests__/tools.test.ts +0 -96
- package/src/generated/client.ts +0 -3643
- package/src/generated/contract.ts +0 -15952
- package/src/index.ts +0 -87
- package/src/runtime/__tests__/process.test.ts +0 -38
- package/src/runtime/__tests__/transport-common.test.ts +0 -174
- package/src/runtime/embedded-cli.ts +0 -109
- package/src/runtime/errors.ts +0 -30
- package/src/runtime/host.ts +0 -481
- package/src/runtime/process.ts +0 -45
- package/src/runtime/transport-common.ts +0 -169
- package/src/skills.ts +0 -195
- package/src/tools.ts +0 -701
package/dist/tools.d.ts
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import type { InvokeOptions } from './runtime/process.js';
|
|
2
|
+
export type ToolProvider = 'openai' | 'anthropic' | 'vercel' | 'generic';
|
|
3
|
+
export type ToolGroup = 'core' | 'format' | 'create' | 'tables' | 'sections' | 'lists' | 'comments' | 'trackChanges' | 'toc' | 'images' | 'history' | 'session';
|
|
4
|
+
export type ToolChooserMode = 'essential' | 'all';
|
|
5
|
+
export type ToolChooserInput = {
|
|
6
|
+
provider: ToolProvider;
|
|
7
|
+
groups?: ToolGroup[];
|
|
8
|
+
/** Default: 'essential'. When 'essential', only essential tools are returned (plus any from `groups`). */
|
|
9
|
+
mode?: ToolChooserMode;
|
|
10
|
+
/** Whether to include the discover_tools meta-tool. Default: true when mode='essential', false when mode='all'. */
|
|
11
|
+
includeDiscoverTool?: boolean;
|
|
12
|
+
};
|
|
13
|
+
export type ToolCatalog = {
|
|
14
|
+
contractVersion: string;
|
|
15
|
+
generatedAt: string | null;
|
|
16
|
+
namePolicyVersion: string;
|
|
17
|
+
exposureVersion: string;
|
|
18
|
+
toolCount: number;
|
|
19
|
+
tools: ToolCatalogEntry[];
|
|
20
|
+
};
|
|
21
|
+
type ToolCatalogEntry = {
|
|
22
|
+
operationId: string;
|
|
23
|
+
toolName: string;
|
|
24
|
+
profile: string;
|
|
25
|
+
source: string;
|
|
26
|
+
description: string;
|
|
27
|
+
inputSchema: Record<string, unknown>;
|
|
28
|
+
outputSchema: Record<string, unknown>;
|
|
29
|
+
mutates: boolean;
|
|
30
|
+
category: string;
|
|
31
|
+
essential?: boolean;
|
|
32
|
+
capabilities: string[];
|
|
33
|
+
constraints?: Record<string, unknown>;
|
|
34
|
+
errors: string[];
|
|
35
|
+
examples: unknown[];
|
|
36
|
+
commandTokens: string[];
|
|
37
|
+
profileTags: string[];
|
|
38
|
+
requiredCapabilities: string[];
|
|
39
|
+
sessionRequirements: {
|
|
40
|
+
requiresOpenContext: boolean;
|
|
41
|
+
supportsSessionTargeting: boolean;
|
|
42
|
+
};
|
|
43
|
+
intentId?: string;
|
|
44
|
+
};
|
|
45
|
+
/** All available tool groups from the policy. */
|
|
46
|
+
export declare function getAvailableGroups(): ToolGroup[];
|
|
47
|
+
export declare function getToolCatalog(): Promise<ToolCatalog>;
|
|
48
|
+
export declare function listTools(provider: ToolProvider): Promise<unknown[]>;
|
|
49
|
+
export declare function resolveToolOperation(toolName: string): Promise<string | null>;
|
|
50
|
+
/**
|
|
51
|
+
* Select tools for a specific provider.
|
|
52
|
+
*
|
|
53
|
+
* **mode='essential'** (default): Returns only essential tools + discover_tools.
|
|
54
|
+
* Pass `groups` to additionally load all tools from those categories.
|
|
55
|
+
*
|
|
56
|
+
* **mode='all'**: Returns all tools from requested groups (or all groups if
|
|
57
|
+
* `groups` is omitted). No discover_tools included by default.
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```ts
|
|
61
|
+
* // Default: 5 essential tools + discover_tools
|
|
62
|
+
* const { tools } = await chooseTools({ provider: 'openai' });
|
|
63
|
+
*
|
|
64
|
+
* // Essential + all comment tools
|
|
65
|
+
* const { tools } = await chooseTools({ provider: 'openai', groups: ['comments'] });
|
|
66
|
+
*
|
|
67
|
+
* // All tools (old behavior)
|
|
68
|
+
* const { tools } = await chooseTools({ provider: 'openai', mode: 'all' });
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
export declare function chooseTools(input: ToolChooserInput): Promise<{
|
|
72
|
+
tools: unknown[];
|
|
73
|
+
selected: Array<{
|
|
74
|
+
operationId: string;
|
|
75
|
+
toolName: string;
|
|
76
|
+
category: string;
|
|
77
|
+
mutates: boolean;
|
|
78
|
+
}>;
|
|
79
|
+
meta: {
|
|
80
|
+
provider: ToolProvider;
|
|
81
|
+
mode: string;
|
|
82
|
+
groups: string[];
|
|
83
|
+
selectedCount: number;
|
|
84
|
+
};
|
|
85
|
+
}>;
|
|
86
|
+
export declare function dispatchSuperDocTool(client: {
|
|
87
|
+
doc: Record<string, unknown>;
|
|
88
|
+
}, toolName: string, args?: Record<string, unknown>, invokeOptions?: InvokeOptions): Promise<unknown>;
|
|
89
|
+
export {};
|
|
90
|
+
//# sourceMappingURL=tools.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"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"}
|
package/dist/tools.js
ADDED
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { readFileSync } from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import { CONTRACT } from './generated/contract.js';
|
|
6
|
+
import { SuperDocCliError } from './runtime/errors.js';
|
|
7
|
+
// Resolve tools directory relative to package root (works from both src/ and dist/)
|
|
8
|
+
const toolsDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', 'tools');
|
|
9
|
+
const providerFileByName = {
|
|
10
|
+
openai: 'tools.openai.json',
|
|
11
|
+
anthropic: 'tools.anthropic.json',
|
|
12
|
+
vercel: 'tools.vercel.json',
|
|
13
|
+
generic: 'tools.generic.json',
|
|
14
|
+
};
|
|
15
|
+
let _policyCache = null;
|
|
16
|
+
function loadPolicy() {
|
|
17
|
+
if (_policyCache)
|
|
18
|
+
return _policyCache;
|
|
19
|
+
const raw = readFileSync(path.join(toolsDir, 'tools-policy.json'), 'utf8');
|
|
20
|
+
_policyCache = JSON.parse(raw);
|
|
21
|
+
return _policyCache;
|
|
22
|
+
}
|
|
23
|
+
function isRecord(value) {
|
|
24
|
+
return typeof value === 'object' && value != null && !Array.isArray(value);
|
|
25
|
+
}
|
|
26
|
+
function isPresent(value) {
|
|
27
|
+
if (value == null)
|
|
28
|
+
return false;
|
|
29
|
+
if (Array.isArray(value))
|
|
30
|
+
return value.length > 0;
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
function extractProviderToolName(tool) {
|
|
34
|
+
// Anthropic / Generic: top-level name
|
|
35
|
+
if (typeof tool.name === 'string')
|
|
36
|
+
return tool.name;
|
|
37
|
+
// OpenAI / Vercel: nested under function.name
|
|
38
|
+
if (isRecord(tool.function) && typeof tool.function.name === 'string') {
|
|
39
|
+
return tool.function.name;
|
|
40
|
+
}
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
function invalidArgument(message, details) {
|
|
44
|
+
throw new SuperDocCliError(message, { code: 'INVALID_ARGUMENT', details });
|
|
45
|
+
}
|
|
46
|
+
async function readJson(fileName) {
|
|
47
|
+
const filePath = path.join(toolsDir, fileName);
|
|
48
|
+
let raw = '';
|
|
49
|
+
try {
|
|
50
|
+
raw = await readFile(filePath, 'utf8');
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
throw new SuperDocCliError('Unable to load packaged tool artifact.', {
|
|
54
|
+
code: 'TOOLS_ASSET_NOT_FOUND',
|
|
55
|
+
details: {
|
|
56
|
+
filePath,
|
|
57
|
+
message: error instanceof Error ? error.message : String(error),
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
try {
|
|
62
|
+
return JSON.parse(raw);
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
throw new SuperDocCliError('Packaged tool artifact is invalid JSON.', {
|
|
66
|
+
code: 'TOOLS_ASSET_INVALID',
|
|
67
|
+
details: {
|
|
68
|
+
filePath,
|
|
69
|
+
message: error instanceof Error ? error.message : String(error),
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
async function loadProviderBundle(provider) {
|
|
75
|
+
return readJson(providerFileByName[provider]);
|
|
76
|
+
}
|
|
77
|
+
async function loadToolNameMap() {
|
|
78
|
+
return readJson('tool-name-map.json');
|
|
79
|
+
}
|
|
80
|
+
async function loadCatalog() {
|
|
81
|
+
return readJson('catalog.json');
|
|
82
|
+
}
|
|
83
|
+
/** All available tool groups from the policy. */
|
|
84
|
+
export function getAvailableGroups() {
|
|
85
|
+
const policy = loadPolicy();
|
|
86
|
+
return policy.groups;
|
|
87
|
+
}
|
|
88
|
+
const OPERATION_INDEX = Object.fromEntries(Object.entries(CONTRACT.operations).map(([id, op]) => [id, op]));
|
|
89
|
+
function validateDispatchArgs(operationId, args) {
|
|
90
|
+
const operation = OPERATION_INDEX[operationId];
|
|
91
|
+
if (!operation) {
|
|
92
|
+
invalidArgument(`Unknown operation id ${operationId}.`);
|
|
93
|
+
}
|
|
94
|
+
// Unknown-param rejection
|
|
95
|
+
const allowedParams = new Set(operation.params.map((param) => String(param.name)));
|
|
96
|
+
for (const key of Object.keys(args)) {
|
|
97
|
+
if (!allowedParams.has(key)) {
|
|
98
|
+
invalidArgument(`Unexpected parameter ${key} for ${operationId}.`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
// Required-param enforcement
|
|
102
|
+
for (const param of operation.params) {
|
|
103
|
+
if ('required' in param && Boolean(param.required) && args[param.name] == null) {
|
|
104
|
+
invalidArgument(`Missing required parameter ${param.name} for ${operationId}.`);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
// Constraint validation (CLI handles schema-level type validation authoritatively)
|
|
108
|
+
const constraints = 'constraints' in operation ? operation.constraints : undefined;
|
|
109
|
+
if (!constraints || !isRecord(constraints))
|
|
110
|
+
return;
|
|
111
|
+
const mutuallyExclusive = Array.isArray(constraints.mutuallyExclusive) ? constraints.mutuallyExclusive : [];
|
|
112
|
+
const requiresOneOf = Array.isArray(constraints.requiresOneOf) ? constraints.requiresOneOf : [];
|
|
113
|
+
const requiredWhen = Array.isArray(constraints.requiredWhen) ? constraints.requiredWhen : [];
|
|
114
|
+
for (const group of mutuallyExclusive) {
|
|
115
|
+
if (!Array.isArray(group))
|
|
116
|
+
continue;
|
|
117
|
+
const present = group.filter((name) => isPresent(args[name]));
|
|
118
|
+
if (present.length > 1) {
|
|
119
|
+
invalidArgument(`Arguments are mutually exclusive for ${operationId}: ${group.join(', ')}`, {
|
|
120
|
+
operationId,
|
|
121
|
+
group,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
for (const group of requiresOneOf) {
|
|
126
|
+
if (!Array.isArray(group))
|
|
127
|
+
continue;
|
|
128
|
+
const hasAny = group.some((name) => isPresent(args[name]));
|
|
129
|
+
if (!hasAny) {
|
|
130
|
+
invalidArgument(`One of the following arguments is required for ${operationId}: ${group.join(', ')}`, {
|
|
131
|
+
operationId,
|
|
132
|
+
group,
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
for (const rule of requiredWhen) {
|
|
137
|
+
if (!isRecord(rule))
|
|
138
|
+
continue;
|
|
139
|
+
const whenValue = args[rule.whenParam];
|
|
140
|
+
let shouldRequire = false;
|
|
141
|
+
if (Object.prototype.hasOwnProperty.call(rule, 'equals')) {
|
|
142
|
+
shouldRequire = whenValue === rule.equals;
|
|
143
|
+
}
|
|
144
|
+
else if (Object.prototype.hasOwnProperty.call(rule, 'present')) {
|
|
145
|
+
const present = rule.present === true;
|
|
146
|
+
shouldRequire = present ? isPresent(whenValue) : !isPresent(whenValue);
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
shouldRequire = isPresent(whenValue);
|
|
150
|
+
}
|
|
151
|
+
if (shouldRequire && !isPresent(args[rule.param])) {
|
|
152
|
+
invalidArgument(`Argument ${rule.param} is required by constraints for ${operationId}.`, {
|
|
153
|
+
operationId,
|
|
154
|
+
rule,
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
function resolveDocApiMethod(client, operationId) {
|
|
160
|
+
const tokens = operationId.split('.').slice(1);
|
|
161
|
+
let cursor = client.doc;
|
|
162
|
+
for (const token of tokens) {
|
|
163
|
+
if (!isRecord(cursor) || !(token in cursor)) {
|
|
164
|
+
throw new SuperDocCliError(`No SDK doc method found for operation ${operationId}.`, {
|
|
165
|
+
code: 'TOOL_DISPATCH_NOT_FOUND',
|
|
166
|
+
details: { operationId, token },
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
cursor = cursor[token];
|
|
170
|
+
}
|
|
171
|
+
if (typeof cursor !== 'function') {
|
|
172
|
+
throw new SuperDocCliError(`Resolved member for ${operationId} is not callable.`, {
|
|
173
|
+
code: 'TOOL_DISPATCH_NOT_FOUND',
|
|
174
|
+
details: { operationId },
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
return cursor;
|
|
178
|
+
}
|
|
179
|
+
export async function getToolCatalog() {
|
|
180
|
+
return loadCatalog();
|
|
181
|
+
}
|
|
182
|
+
export async function listTools(provider) {
|
|
183
|
+
const bundle = await loadProviderBundle(provider);
|
|
184
|
+
const tools = bundle.tools;
|
|
185
|
+
if (!Array.isArray(tools)) {
|
|
186
|
+
throw new SuperDocCliError('Tool provider bundle is missing tools array.', {
|
|
187
|
+
code: 'TOOLS_ASSET_INVALID',
|
|
188
|
+
details: { provider },
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
return tools;
|
|
192
|
+
}
|
|
193
|
+
export async function resolveToolOperation(toolName) {
|
|
194
|
+
const map = await loadToolNameMap();
|
|
195
|
+
return typeof map[toolName] === 'string' ? map[toolName] : null;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Select tools for a specific provider.
|
|
199
|
+
*
|
|
200
|
+
* **mode='essential'** (default): Returns only essential tools + discover_tools.
|
|
201
|
+
* Pass `groups` to additionally load all tools from those categories.
|
|
202
|
+
*
|
|
203
|
+
* **mode='all'**: Returns all tools from requested groups (or all groups if
|
|
204
|
+
* `groups` is omitted). No discover_tools included by default.
|
|
205
|
+
*
|
|
206
|
+
* @example
|
|
207
|
+
* ```ts
|
|
208
|
+
* // Default: 5 essential tools + discover_tools
|
|
209
|
+
* const { tools } = await chooseTools({ provider: 'openai' });
|
|
210
|
+
*
|
|
211
|
+
* // Essential + all comment tools
|
|
212
|
+
* const { tools } = await chooseTools({ provider: 'openai', groups: ['comments'] });
|
|
213
|
+
*
|
|
214
|
+
* // All tools (old behavior)
|
|
215
|
+
* const { tools } = await chooseTools({ provider: 'openai', mode: 'all' });
|
|
216
|
+
* ```
|
|
217
|
+
*/
|
|
218
|
+
export async function chooseTools(input) {
|
|
219
|
+
const catalog = await loadCatalog();
|
|
220
|
+
const policy = loadPolicy();
|
|
221
|
+
const mode = input.mode ?? policy.defaults.mode ?? 'essential';
|
|
222
|
+
const includeDiscover = input.includeDiscoverTool ?? mode === 'essential';
|
|
223
|
+
let selected;
|
|
224
|
+
if (mode === 'essential') {
|
|
225
|
+
// Essential tools + any explicitly requested groups
|
|
226
|
+
const essentialNames = new Set(policy.essentialTools ?? []);
|
|
227
|
+
const requestedGroups = input.groups ? new Set(input.groups) : null;
|
|
228
|
+
selected = catalog.tools.filter((tool) => {
|
|
229
|
+
if (essentialNames.has(tool.toolName))
|
|
230
|
+
return true;
|
|
231
|
+
if (requestedGroups && requestedGroups.has(tool.category))
|
|
232
|
+
return true;
|
|
233
|
+
return false;
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
237
|
+
// mode='all': original behavior — filter by groups
|
|
238
|
+
const alwaysInclude = new Set(policy.defaults.alwaysInclude ?? ['core']);
|
|
239
|
+
let groups;
|
|
240
|
+
if (input.groups) {
|
|
241
|
+
groups = new Set([...input.groups, ...alwaysInclude]);
|
|
242
|
+
}
|
|
243
|
+
else {
|
|
244
|
+
groups = new Set(policy.groups);
|
|
245
|
+
}
|
|
246
|
+
selected = catalog.tools.filter((tool) => groups.has(tool.category));
|
|
247
|
+
}
|
|
248
|
+
// Build provider-formatted tools from the provider bundle
|
|
249
|
+
const bundle = await loadProviderBundle(input.provider);
|
|
250
|
+
const providerTools = Array.isArray(bundle.tools) ? bundle.tools : [];
|
|
251
|
+
const providerIndex = new Map(providerTools
|
|
252
|
+
.filter((tool) => isRecord(tool))
|
|
253
|
+
.map((tool) => [extractProviderToolName(tool), tool])
|
|
254
|
+
.filter((entry) => entry[0] !== null));
|
|
255
|
+
const selectedProviderTools = selected
|
|
256
|
+
.map((tool) => providerIndex.get(tool.toolName))
|
|
257
|
+
.filter((tool) => Boolean(tool));
|
|
258
|
+
// Append discover_tools if requested
|
|
259
|
+
if (includeDiscover) {
|
|
260
|
+
const discoverTool = providerIndex.get('discover_tools');
|
|
261
|
+
if (discoverTool) {
|
|
262
|
+
selectedProviderTools.push(discoverTool);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
const resolvedGroups = mode === 'essential' ? (input.groups ?? []) : (input.groups ?? policy.groups);
|
|
266
|
+
return {
|
|
267
|
+
tools: selectedProviderTools,
|
|
268
|
+
selected: selected.map((tool) => ({
|
|
269
|
+
operationId: tool.operationId,
|
|
270
|
+
toolName: tool.toolName,
|
|
271
|
+
category: tool.category,
|
|
272
|
+
mutates: tool.mutates,
|
|
273
|
+
})),
|
|
274
|
+
meta: {
|
|
275
|
+
provider: input.provider,
|
|
276
|
+
mode,
|
|
277
|
+
groups: [...resolvedGroups],
|
|
278
|
+
selectedCount: selectedProviderTools.length,
|
|
279
|
+
},
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
export async function dispatchSuperDocTool(client, toolName, args = {}, invokeOptions) {
|
|
283
|
+
const operationId = await resolveToolOperation(toolName);
|
|
284
|
+
if (!operationId) {
|
|
285
|
+
throw new SuperDocCliError(`Unknown SuperDoc tool: ${toolName}`, {
|
|
286
|
+
code: 'TOOL_NOT_FOUND',
|
|
287
|
+
details: { toolName },
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
if (!isRecord(args)) {
|
|
291
|
+
invalidArgument(`Tool arguments for ${toolName} must be an object.`);
|
|
292
|
+
}
|
|
293
|
+
validateDispatchArgs(operationId, args);
|
|
294
|
+
const method = resolveDocApiMethod(client, operationId);
|
|
295
|
+
return method(args, invokeOptions);
|
|
296
|
+
}
|
package/package.json
CHANGED
|
@@ -1,31 +1,41 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@superdoc-dev/sdk",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.31",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
|
-
"main": "./
|
|
7
|
-
"module": "./
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"require": "./dist/index.cjs"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
8
16
|
"files": [
|
|
9
|
-
"
|
|
17
|
+
"dist",
|
|
10
18
|
"skills",
|
|
11
19
|
"tools"
|
|
12
20
|
],
|
|
13
|
-
"optionalDependencies": {
|
|
14
|
-
"@superdoc-dev/sdk-darwin-arm64": "1.0.0-alpha.3",
|
|
15
|
-
"@superdoc-dev/sdk-darwin-x64": "1.0.0-alpha.3",
|
|
16
|
-
"@superdoc-dev/sdk-linux-arm64": "1.0.0-alpha.3",
|
|
17
|
-
"@superdoc-dev/sdk-linux-x64": "1.0.0-alpha.3",
|
|
18
|
-
"@superdoc-dev/sdk-windows-x64": "1.0.0-alpha.3"
|
|
19
|
-
},
|
|
20
21
|
"devDependencies": {
|
|
21
22
|
"@types/bun": "^1.3.8",
|
|
22
23
|
"@types/node": "22.19.2",
|
|
24
|
+
"rollup": "^4.31.0",
|
|
23
25
|
"typescript": "^5.9.2"
|
|
24
26
|
},
|
|
27
|
+
"optionalDependencies": {
|
|
28
|
+
"@superdoc-dev/sdk-darwin-arm64": "1.0.0-alpha.31",
|
|
29
|
+
"@superdoc-dev/sdk-darwin-x64": "1.0.0-alpha.31",
|
|
30
|
+
"@superdoc-dev/sdk-linux-arm64": "1.0.0-alpha.31",
|
|
31
|
+
"@superdoc-dev/sdk-linux-x64": "1.0.0-alpha.31",
|
|
32
|
+
"@superdoc-dev/sdk-windows-x64": "1.0.0-alpha.31"
|
|
33
|
+
},
|
|
25
34
|
"publishConfig": {
|
|
26
35
|
"access": "public"
|
|
27
36
|
},
|
|
28
37
|
"scripts": {
|
|
38
|
+
"build": "tsc && rollup -c rollup.cjs.config.mjs",
|
|
29
39
|
"typecheck": "tsc --noEmit"
|
|
30
40
|
}
|
|
31
41
|
}
|
package/skills/editing-docx.md
CHANGED
|
@@ -1,157 +1,31 @@
|
|
|
1
|
-
|
|
2
|
-
name: superdoc
|
|
3
|
-
description: Session-first SuperDoc CLI workflows for querying and editing DOCX files (find/inspect, comments lifecycle, text mutations, tracked-changes review, and close safely).
|
|
4
|
-
---
|
|
1
|
+
# Editing DOCX Documents with SuperDoc SDK
|
|
5
2
|
|
|
6
|
-
|
|
3
|
+
You are a document editing assistant using the SuperDoc SDK. You have access to tools
|
|
4
|
+
that let you open, read, search, and modify `.docx` files programmatically.
|
|
7
5
|
|
|
8
|
-
|
|
6
|
+
## Workflow
|
|
9
7
|
|
|
10
|
-
|
|
8
|
+
1. **Open** the document with `doc.open`
|
|
9
|
+
2. **Inspect** it with `doc.info` to understand structure
|
|
10
|
+
3. **Find** content with `doc.find` using text search or node type queries
|
|
11
|
+
4. **Modify** content using `doc.insert`, `doc.replace`, `doc.delete`, or formatting operations
|
|
12
|
+
5. **Save** changes with `doc.save`
|
|
13
|
+
6. **Close** when done with `doc.close`
|
|
11
14
|
|
|
12
|
-
|
|
13
|
-
2. Prefer session mode: `open` once, then run commands without `<doc>`.
|
|
14
|
-
3. Treat CLI envelopes as truth (`ok`, `data`, `error`).
|
|
15
|
-
4. Re-query before mutating if target addresses might be stale.
|
|
16
|
-
5. If matches are ambiguous, ask user which match(es) to modify.
|
|
17
|
-
6. End every workflow with an explicit persistence + close decision:
|
|
18
|
-
- `save --out ...` then `close`
|
|
19
|
-
- `save --in-place` then `close`
|
|
20
|
-
- `close --discard`
|
|
15
|
+
## Key Operations
|
|
21
16
|
|
|
22
|
-
|
|
17
|
+
- `doc.find` — Search by text pattern, node type, or structured query
|
|
18
|
+
- `doc.getNode` — Get a specific node by address
|
|
19
|
+
- `doc.insert` — Insert text at a position
|
|
20
|
+
- `doc.replace` — Replace content at a position
|
|
21
|
+
- `doc.delete` — Delete content at a position
|
|
22
|
+
- `doc.format.*` — Apply bold, italic, underline, strikethrough
|
|
23
|
+
- `doc.comments.*` — Add, edit, resolve, remove comments
|
|
24
|
+
- `doc.trackChanges.*` — Accept/reject tracked changes
|
|
23
25
|
|
|
24
|
-
|
|
26
|
+
## Best Practices
|
|
25
27
|
|
|
26
|
-
|
|
27
|
-
`
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
1. Open a session:
|
|
32
|
-
```bash
|
|
33
|
-
superdoc open ./contract.docx --output json
|
|
34
|
-
```
|
|
35
|
-
2. Query and inspect:
|
|
36
|
-
```bash
|
|
37
|
-
superdoc describe --output json
|
|
38
|
-
superdoc describe command doc.find --output json
|
|
39
|
-
superdoc info --output json
|
|
40
|
-
superdoc find --type text --pattern "termination" --output json
|
|
41
|
-
superdoc get-node --address-json '{"kind":"block","nodeType":"paragraph","nodeId":"p1"}' --output json
|
|
42
|
-
```
|
|
43
|
-
3. Mutate (using target JSON from `find` results):
|
|
44
|
-
```bash
|
|
45
|
-
superdoc comments add --target-json '{"kind":"text","blockId":"p1","range":{"start":10,"end":20}}' --text "Please clarify this clause." --output json
|
|
46
|
-
superdoc replace --target-json '{"kind":"text","blockId":"p1","range":{"start":10,"end":20}}' --text "Updated clause text" --dry-run --output json
|
|
47
|
-
superdoc replace --target-json '{"kind":"text","blockId":"p1","range":{"start":10,"end":20}}' --text "Updated clause text" --output json
|
|
48
|
-
```
|
|
49
|
-
4. Verify:
|
|
50
|
-
```bash
|
|
51
|
-
superdoc find --type text --pattern "Updated clause text" --output json
|
|
52
|
-
```
|
|
53
|
-
5. Save and close:
|
|
54
|
-
```bash
|
|
55
|
-
superdoc save --out ./contract.reviewed.docx --output json
|
|
56
|
-
superdoc close --output json
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
## Command Patterns (Session Mode)
|
|
60
|
-
|
|
61
|
-
### Session lifecycle
|
|
62
|
-
- `superdoc open <doc> [--session <id>] --output json`
|
|
63
|
-
- `superdoc status [--session <id>] --output json`
|
|
64
|
-
- `superdoc save [--in-place] [--out <path>] [--force] --output json`
|
|
65
|
-
- `superdoc close [--discard] --output json`
|
|
66
|
-
- `superdoc session list --output json`
|
|
67
|
-
- `superdoc session save <id> [--in-place] [--out <path>] [--force] --output json`
|
|
68
|
-
- `superdoc session use <id> --output json`
|
|
69
|
-
- `superdoc session set-default <id> --output json`
|
|
70
|
-
- `superdoc session close <id> --discard --output json`
|
|
71
|
-
|
|
72
|
-
### Query
|
|
73
|
-
- `superdoc describe --output json`
|
|
74
|
-
- `superdoc describe command <operationId> --output json`
|
|
75
|
-
- `superdoc info --output json`
|
|
76
|
-
- `superdoc find --type text --pattern "<text>" --output json`
|
|
77
|
-
- `superdoc find --query-json '{...}' --output json`
|
|
78
|
-
- `superdoc get-node --address-json '{...}' --output json`
|
|
79
|
-
- `superdoc get-node-by-id --id <nodeId> [--node-type <type>] --output json`
|
|
80
|
-
|
|
81
|
-
### Mutate
|
|
82
|
-
- `superdoc create paragraph [--input-json '{...}'] [--text "..."] [--at document-start|document-end] [--before-address-json '{...}'] [--after-address-json '{...}'] [--dry-run] [--change-mode direct|tracked] --output json`
|
|
83
|
-
- `superdoc comments add --target-json '{...}' --text "..." --output json`
|
|
84
|
-
- `superdoc comments edit --id <commentId> --text "..." [--expected-revision <n>] [--force] --output json`
|
|
85
|
-
- `superdoc comments reply --parent-id <commentId> --text "..." [--expected-revision <n>] [--force] --output json`
|
|
86
|
-
- `superdoc comments move --id <commentId> --target-json '{...}' [--expected-revision <n>] [--force] --output json`
|
|
87
|
-
- `superdoc comments resolve --id <commentId> [--expected-revision <n>] [--force] --output json`
|
|
88
|
-
- `superdoc comments remove --id <commentId> [--expected-revision <n>] [--force] --output json`
|
|
89
|
-
- `superdoc comments set-internal --id <commentId> --is-internal <true|false> [--expected-revision <n>] [--force] --output json`
|
|
90
|
-
- `superdoc insert [--target-json '{...}'] --text "..." [--dry-run] [--change-mode direct|tracked] --output json`
|
|
91
|
-
- `superdoc replace --target-json '{...}' --text "..." [--dry-run] [--change-mode direct|tracked] --output json`
|
|
92
|
-
- `superdoc delete --target-json '{...}' [--dry-run] [--change-mode direct|tracked] --output json`
|
|
93
|
-
- `superdoc format bold --target-json '{...}' [--dry-run] [--change-mode direct|tracked] --output json`
|
|
94
|
-
|
|
95
|
-
### Comments read/navigation
|
|
96
|
-
- `superdoc comments get --id <commentId> --output json`
|
|
97
|
-
- `superdoc comments list [--include-resolved <true|false>] --output json`
|
|
98
|
-
- `superdoc comments set-active --id <commentId> --output json`
|
|
99
|
-
- `superdoc comments set-active --clear --output json`
|
|
100
|
-
- `superdoc comments go-to --id <commentId> --output json`
|
|
101
|
-
|
|
102
|
-
### Track changes
|
|
103
|
-
- `superdoc track-changes list [--type insert|delete|format] [--limit <n>] [--offset <n>] --output json`
|
|
104
|
-
- `superdoc track-changes get --id <trackedChangeId> --output json`
|
|
105
|
-
- `superdoc track-changes accept --id <trackedChangeId> [--expected-revision <n>] [--force] --output json`
|
|
106
|
-
- `superdoc track-changes reject --id <trackedChangeId> [--expected-revision <n>] [--force] --output json`
|
|
107
|
-
- `superdoc track-changes accept-all [--expected-revision <n>] [--force] --output json`
|
|
108
|
-
- `superdoc track-changes reject-all [--expected-revision <n>] [--force] --output json`
|
|
109
|
-
|
|
110
|
-
### Stateless fallback
|
|
111
|
-
If a command includes `<doc>` (or `--doc`), it runs statelessly for that call.
|
|
112
|
-
For stateless mutate commands, provide `--out <path>`.
|
|
113
|
-
|
|
114
|
-
## Target Selection Guidance
|
|
115
|
-
|
|
116
|
-
- Prefer structural creation for new block insertion:
|
|
117
|
-
- `create paragraph` creates a new paragraph block and returns structural handles (`paragraph`, `insertionPoint`).
|
|
118
|
-
- Prefer `find --type text --pattern ...` first.
|
|
119
|
-
- Use `data.result.context[*].textRanges[*]` as `--target-json` for text edits/comments.
|
|
120
|
-
- `insert` may omit `--target-json`; it defaults to the first editable insertion point (first paragraph start when available).
|
|
121
|
-
- When multiple matches exist, apply a deterministic policy:
|
|
122
|
-
- first match only, or
|
|
123
|
-
- first N matches, or
|
|
124
|
-
- user-selected match indexes.
|
|
125
|
-
- For uncertain targets, run `get-node` before mutate.
|
|
126
|
-
|
|
127
|
-
## Mutation Mode Guidance
|
|
128
|
-
|
|
129
|
-
- Use `--change-mode direct|tracked` to control whether edits create tracked changes.
|
|
130
|
-
- `create paragraph` supports `--change-mode tracked` for tracked structural creation.
|
|
131
|
-
- `replace`, `insert`, `delete`, and `format bold` support `--change-mode tracked`.
|
|
132
|
-
- `track-changes *` commands are for review lifecycle (list/get/accept/reject), not content insertion.
|
|
133
|
-
- Deterministic tracked-change outcomes:
|
|
134
|
-
- unknown/stale ids -> `TRACK_CHANGE_NOT_FOUND`
|
|
135
|
-
- no applicable `accept-all`/`reject-all` change -> `NO_OP` receipt
|
|
136
|
-
- missing tracking capability -> `TRACK_CHANGE_COMMAND_UNAVAILABLE`
|
|
137
|
-
|
|
138
|
-
## Scenario Prompts (Copy/Paste)
|
|
139
|
-
|
|
140
|
-
1. Open `./contracts/msa.docx`, find `termination`, add comments to the first 2 matches asking for clearer notice period, then save to `./contracts/msa.reviewed.docx`.
|
|
141
|
-
2. Use the active session to find `governing law`, inspect the top match node, then add a concise legal-risk comment.
|
|
142
|
-
3. Open two sessions (`vendor-a`, `vendor-b`) on different docs, switch between them, and add one comment in each.
|
|
143
|
-
4. Run a redline pass replacing `shall` with `must` for the first 3 matches: dry-run first, then apply.
|
|
144
|
-
5. Run `track-changes list`, inspect one change with `track-changes get`, then accept it by id.
|
|
145
|
-
6. Open from stdin (`open -`), run `find`, add one comment, then `save --out` and `close`.
|
|
146
|
-
|
|
147
|
-
## Collaboration (Node-Only, Optional)
|
|
148
|
-
|
|
149
|
-
Use only when collaboration runtime is available in your environment.
|
|
150
|
-
|
|
151
|
-
```bash
|
|
152
|
-
superdoc open ./contract.docx --collaboration-json '{"providerType":"hocuspocus","url":"ws://localhost:1234","documentId":"contract-1","tokenEnv":"SUPERDOC_COLLAB_TOKEN"}' --output json
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
Notes:
|
|
156
|
-
- Collaboration commands are command-scoped (connect -> sync -> operate -> disconnect).
|
|
157
|
-
- Python collaboration is not supported; expect `NOT_SUPPORTED`.
|
|
28
|
+
- Always open before operating, save when done
|
|
29
|
+
- Use `doc.find` to locate content before modifying
|
|
30
|
+
- Use `doc.info` to check document capabilities
|
|
31
|
+
- Handle errors gracefully — operations may fail if targets are invalid
|