@spinabot/brigade 1.9.0 → 1.10.0
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 +12 -10
- package/dist/agents/agent-loop.d.ts +55 -0
- package/dist/agents/agent-loop.d.ts.map +1 -1
- package/dist/agents/agent-loop.js +90 -1
- package/dist/agents/agent-loop.js.map +1 -1
- package/dist/agents/channels/inbound-pipeline.d.ts +22 -0
- package/dist/agents/channels/inbound-pipeline.d.ts.map +1 -1
- package/dist/agents/channels/inbound-pipeline.js +31 -1
- package/dist/agents/channels/inbound-pipeline.js.map +1 -1
- package/dist/agents/channels/media-capture.d.ts +69 -6
- package/dist/agents/channels/media-capture.d.ts.map +1 -1
- package/dist/agents/channels/media-capture.js +125 -8
- package/dist/agents/channels/media-capture.js.map +1 -1
- package/dist/agents/channels/telegram/media.d.ts.map +1 -1
- package/dist/agents/channels/telegram/media.js +16 -4
- package/dist/agents/channels/telegram/media.js.map +1 -1
- package/dist/agents/channels/whatsapp/media.d.ts +19 -0
- package/dist/agents/channels/whatsapp/media.d.ts.map +1 -1
- package/dist/agents/channels/whatsapp/media.js +37 -2
- package/dist/agents/channels/whatsapp/media.js.map +1 -1
- package/dist/agents/media-understanding/anthropic-adapter.d.ts +49 -0
- package/dist/agents/media-understanding/anthropic-adapter.d.ts.map +1 -0
- package/dist/agents/media-understanding/anthropic-adapter.js +162 -0
- package/dist/agents/media-understanding/anthropic-adapter.js.map +1 -0
- package/dist/agents/media-understanding/config.d.ts +57 -0
- package/dist/agents/media-understanding/config.d.ts.map +1 -0
- package/dist/agents/media-understanding/config.js +289 -0
- package/dist/agents/media-understanding/config.js.map +1 -0
- package/dist/agents/media-understanding/gemini-adapter.d.ts +57 -0
- package/dist/agents/media-understanding/gemini-adapter.d.ts.map +1 -0
- package/dist/agents/media-understanding/gemini-adapter.js +343 -0
- package/dist/agents/media-understanding/gemini-adapter.js.map +1 -0
- package/dist/agents/media-understanding/index.d.ts +58 -0
- package/dist/agents/media-understanding/index.d.ts.map +1 -0
- package/dist/agents/media-understanding/index.js +275 -0
- package/dist/agents/media-understanding/index.js.map +1 -0
- package/dist/agents/media-understanding/pi-adapter.d.ts +72 -0
- package/dist/agents/media-understanding/pi-adapter.d.ts.map +1 -0
- package/dist/agents/media-understanding/pi-adapter.js +160 -0
- package/dist/agents/media-understanding/pi-adapter.js.map +1 -0
- package/dist/agents/media-understanding/types.d.ts +189 -0
- package/dist/agents/media-understanding/types.d.ts.map +1 -0
- package/dist/agents/media-understanding/types.js +51 -0
- package/dist/agents/media-understanding/types.js.map +1 -0
- package/dist/agents/session-wiring.d.ts +11 -0
- package/dist/agents/session-wiring.d.ts.map +1 -1
- package/dist/agents/session-wiring.js +1 -0
- package/dist/agents/session-wiring.js.map +1 -1
- package/dist/agents/tools/analyze-media-tool.d.ts +263 -0
- package/dist/agents/tools/analyze-media-tool.d.ts.map +1 -0
- package/dist/agents/tools/analyze-media-tool.js +2321 -0
- package/dist/agents/tools/analyze-media-tool.js.map +1 -0
- package/dist/agents/tools/doc-shared.d.ts +187 -0
- package/dist/agents/tools/doc-shared.d.ts.map +1 -0
- package/dist/agents/tools/doc-shared.js +484 -0
- package/dist/agents/tools/doc-shared.js.map +1 -0
- package/dist/agents/tools/edit-document-tool.d.ts +133 -0
- package/dist/agents/tools/edit-document-tool.d.ts.map +1 -0
- package/dist/agents/tools/edit-document-tool.js +815 -0
- package/dist/agents/tools/edit-document-tool.js.map +1 -0
- package/dist/agents/tools/image-downscale.d.ts +93 -0
- package/dist/agents/tools/image-downscale.d.ts.map +1 -0
- package/dist/agents/tools/image-downscale.js +257 -0
- package/dist/agents/tools/image-downscale.js.map +1 -0
- package/dist/agents/tools/make-document-tool.d.ts +114 -0
- package/dist/agents/tools/make-document-tool.d.ts.map +1 -0
- package/dist/agents/tools/make-document-tool.js +542 -0
- package/dist/agents/tools/make-document-tool.js.map +1 -0
- package/dist/agents/tools/media-cache.d.ts +56 -0
- package/dist/agents/tools/media-cache.d.ts.map +1 -0
- package/dist/agents/tools/media-cache.js +133 -0
- package/dist/agents/tools/media-cache.js.map +1 -0
- package/dist/agents/tools/ooxml-images.d.ts +107 -0
- package/dist/agents/tools/ooxml-images.d.ts.map +1 -0
- package/dist/agents/tools/ooxml-images.js +308 -0
- package/dist/agents/tools/ooxml-images.js.map +1 -0
- package/dist/agents/tools/registry.d.ts +12 -0
- package/dist/agents/tools/registry.d.ts.map +1 -1
- package/dist/agents/tools/registry.js +47 -0
- package/dist/agents/tools/registry.js.map +1 -1
- package/dist/buildstamp.json +1 -1
- package/dist/cli/commands/doctor.d.ts.map +1 -1
- package/dist/cli/commands/doctor.js +41 -0
- package/dist/cli/commands/doctor.js.map +1 -1
- package/dist/core/console-stream.d.ts.map +1 -1
- package/dist/core/console-stream.js +7 -5
- package/dist/core/console-stream.js.map +1 -1
- package/dist/core/server.js +6 -1
- package/dist/core/server.js.map +1 -1
- package/dist/system-prompt/assembler.d.ts.map +1 -1
- package/dist/system-prompt/assembler.js +25 -1
- package/dist/system-prompt/assembler.js.map +1 -1
- package/dist/system-prompt/guidance.d.ts +30 -0
- package/dist/system-prompt/guidance.d.ts.map +1 -1
- package/dist/system-prompt/guidance.js +50 -0
- package/dist/system-prompt/guidance.js.map +1 -1
- package/package.json +9 -1
|
@@ -0,0 +1,484 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared helpers for the document AUTHORING tools (`make_document` +
|
|
3
|
+
* `edit_document`) — the WRITE siblings of `analyze_media`'s read side.
|
|
4
|
+
*
|
|
5
|
+
* ─────────────────────────────────────────────────────────────────────────
|
|
6
|
+
* WHY THIS MODULE
|
|
7
|
+
* ─────────────────────────────────────────────────────────────────────────
|
|
8
|
+
* `make_document` (CREATE) and `edit_document` (EDIT) share three concerns:
|
|
9
|
+
*
|
|
10
|
+
* 1. PATH SCOPING. Both tools READ an output path (and, for edit, a source
|
|
11
|
+
* path) and WRITE bytes to disk. They reuse the EXACT same posture as
|
|
12
|
+
* `analyze_media`'s local-file acquisition: the media-path guard
|
|
13
|
+
* (`validateOutboundMediaPath`, refuses secrets / system files /
|
|
14
|
+
* credential dirs) PLUS an allowed-root scoping (workspace / cwd / OS
|
|
15
|
+
* cache / temp / state subtree). Writing OUTSIDE those roots is refused —
|
|
16
|
+
* a prompt-injected "save the doc to ~/.ssh/authorized_keys" can never
|
|
17
|
+
* land. The output dir is created on demand inside an allowed root.
|
|
18
|
+
*
|
|
19
|
+
* 2. IMAGE EMBEDDING. docx/pptx/pdf can embed an image from a local path or
|
|
20
|
+
* a URL. Images are acquired with the SAME guard (local) / SSRF guard
|
|
21
|
+
* (URL) as `analyze_media`, then normalized + resized to a sane embed
|
|
22
|
+
* budget via jimp (pure-JS, zero native deps — preserves Brigade's
|
|
23
|
+
* no-native-build streak). The libraries (`docx`/`pdf-lib`/`pptxgenjs`)
|
|
24
|
+
* only accept a known raster format, so HEIC/SVG/unknown are re-encoded
|
|
25
|
+
* to PNG/JPEG by jimp first.
|
|
26
|
+
*
|
|
27
|
+
* 3. CLEAN ERRORS. A malformed input must surface as a
|
|
28
|
+
* `BrigadeToolInputError` (the model sees `.message` + self-corrects),
|
|
29
|
+
* never a raw library throw.
|
|
30
|
+
*
|
|
31
|
+
* The output-path roots intentionally MATCH `analyze_media`'s read roots so a
|
|
32
|
+
* file the agent just produced is immediately analyzable by the read tool, and
|
|
33
|
+
* vice-versa.
|
|
34
|
+
*/
|
|
35
|
+
import fs from "node:fs";
|
|
36
|
+
import fsp from "node:fs/promises";
|
|
37
|
+
import os from "node:os";
|
|
38
|
+
import path from "node:path";
|
|
39
|
+
import { fileURLToPath } from "node:url";
|
|
40
|
+
import { guardedFetch, SsrfBlockedError } from "../../infra/net/fetch-guard.js";
|
|
41
|
+
import { validateOutboundMediaPath } from "../../security/media-path-guard.js";
|
|
42
|
+
import { resolveCacheDir, resolveOsCacheDir, resolveStateDir, } from "../../config/paths.js";
|
|
43
|
+
import { BrigadeToolInputError } from "./common.js";
|
|
44
|
+
/** Canonical file extension for a format. */
|
|
45
|
+
export function extForFormat(format) {
|
|
46
|
+
return format; // docx/xlsx/pptx/pdf all match their extension
|
|
47
|
+
}
|
|
48
|
+
/** Lowercase extension (no dot) of a path. */
|
|
49
|
+
export function docExtensionOf(p) {
|
|
50
|
+
return path.extname(p).toLowerCase().replace(/^\./, "");
|
|
51
|
+
}
|
|
52
|
+
/** Map a file extension to a doc format (for edit-source detection). */
|
|
53
|
+
export function formatFromExtension(p) {
|
|
54
|
+
const ext = docExtensionOf(p);
|
|
55
|
+
if (ext === "docx" || ext === "xlsx" || ext === "pptx" || ext === "pdf")
|
|
56
|
+
return ext;
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
59
|
+
/* ─────────────────────────── allowed-root scoping ─────────────────────────── */
|
|
60
|
+
/**
|
|
61
|
+
* Roots a document path (input OR output) is allowed to live under. Mirrors
|
|
62
|
+
* `analyze_media`'s `allowedLocalRoots` so the two tools agree on where files
|
|
63
|
+
* may be read from and written to: workspace, process cwd, OS cache + temp,
|
|
64
|
+
* and the Brigade state media subtree (channels / cache / captures / workspace
|
|
65
|
+
* in both filesystem AND convex mode).
|
|
66
|
+
*/
|
|
67
|
+
export function allowedDocRoots(opts) {
|
|
68
|
+
const roots = new Set();
|
|
69
|
+
const add = (p) => {
|
|
70
|
+
if (!p)
|
|
71
|
+
return;
|
|
72
|
+
try {
|
|
73
|
+
roots.add(path.resolve(p));
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
/* ignore */
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
add(opts.workspaceDir);
|
|
80
|
+
add(opts.cwd);
|
|
81
|
+
add(resolveCacheDir());
|
|
82
|
+
add(process.env.TMPDIR || process.env.TEMP || process.env.TMP || "");
|
|
83
|
+
try {
|
|
84
|
+
add(os.tmpdir());
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
/* ignore */
|
|
88
|
+
}
|
|
89
|
+
try {
|
|
90
|
+
add(path.join(resolveStateDir(), "channels"));
|
|
91
|
+
add(path.join(resolveStateDir(), "cache"));
|
|
92
|
+
add(path.join(resolveStateDir(), "captures"));
|
|
93
|
+
add(path.join(resolveStateDir(), "workspace"));
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
/* ignore */
|
|
97
|
+
}
|
|
98
|
+
try {
|
|
99
|
+
const osCache = resolveOsCacheDir();
|
|
100
|
+
add(osCache);
|
|
101
|
+
add(path.join(osCache, "channels"));
|
|
102
|
+
add(path.join(osCache, "bluebubbles"));
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
/* ignore */
|
|
106
|
+
}
|
|
107
|
+
return [...roots].filter((r) => r.length > 0);
|
|
108
|
+
}
|
|
109
|
+
/** True when `resolved` is inside one of `roots` (containment, no `..` escape). */
|
|
110
|
+
export function isInsideAnyRoot(resolved, roots) {
|
|
111
|
+
for (const root of roots) {
|
|
112
|
+
const rel = path.relative(root, resolved);
|
|
113
|
+
if (rel === "" || (!rel.startsWith("..") && !path.isAbsolute(rel)))
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Resolve + validate an OUTPUT path for a document write.
|
|
120
|
+
*
|
|
121
|
+
* 1. media-path guard (refuse secrets / system files / credential dirs) —
|
|
122
|
+
* applied to the resolved absolute path so a benign basename can't smuggle
|
|
123
|
+
* a sensitive target.
|
|
124
|
+
* 2. allowed-root scoping — the FILE must land inside workspace / cwd / cache
|
|
125
|
+
* / temp / state subtree. We check the realpath of the nearest existing
|
|
126
|
+
* ANCESTOR (the file itself doesn't exist yet on a create), so symlinked
|
|
127
|
+
* parent dirs can't redirect the write outside the roots.
|
|
128
|
+
*
|
|
129
|
+
* Returns the absolute path to write to (NOT yet created). Throws
|
|
130
|
+
* `BrigadeToolInputError` when refused.
|
|
131
|
+
*/
|
|
132
|
+
export function resolveOutputPath(rawPath, opts) {
|
|
133
|
+
if (!rawPath || typeof rawPath !== "string" || !rawPath.trim()) {
|
|
134
|
+
throw new BrigadeToolInputError("output path required");
|
|
135
|
+
}
|
|
136
|
+
const base = (opts.cwd && opts.cwd.trim()) || (opts.workspaceDir && opts.workspaceDir.trim()) || process.cwd();
|
|
137
|
+
const abs = path.isAbsolute(rawPath) ? path.resolve(rawPath) : path.resolve(base, rawPath);
|
|
138
|
+
// Secret / system-file denylist (resolves symlinks of an existing target).
|
|
139
|
+
const verdict = validateOutboundMediaPath(abs);
|
|
140
|
+
if (!verdict.ok) {
|
|
141
|
+
throw new BrigadeToolInputError(verdict.reason ?? "refusing to write that path");
|
|
142
|
+
}
|
|
143
|
+
// Scope the realpath of the nearest existing ancestor so a symlinked parent
|
|
144
|
+
// can't redirect the write outside the allowed roots.
|
|
145
|
+
const roots = allowedDocRoots(opts);
|
|
146
|
+
const anchor = nearestExistingAncestorReal(abs);
|
|
147
|
+
if (!isInsideAnyRoot(anchor, roots)) {
|
|
148
|
+
throw new BrigadeToolInputError("refusing to write a path outside the allowed roots (workspace / current dir / cache / temp). " +
|
|
149
|
+
"Write into the workspace (omit `outputPath` for an auto-named file there).");
|
|
150
|
+
}
|
|
151
|
+
return abs;
|
|
152
|
+
}
|
|
153
|
+
/** Realpath of the deepest existing ancestor of `abs` (so non-existent leaves resolve safely). */
|
|
154
|
+
function nearestExistingAncestorReal(abs) {
|
|
155
|
+
let cur = abs;
|
|
156
|
+
for (let i = 0; i < 64; i++) {
|
|
157
|
+
try {
|
|
158
|
+
return fs.realpathSync(cur);
|
|
159
|
+
}
|
|
160
|
+
catch {
|
|
161
|
+
const parent = path.dirname(cur);
|
|
162
|
+
if (parent === cur)
|
|
163
|
+
return cur; // reached the root
|
|
164
|
+
cur = parent;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return cur;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Resolve + validate a SOURCE path for an edit, then read its bytes. Same
|
|
171
|
+
* posture as `analyze_media`'s `acquireLocalBytes`: media-path guard +
|
|
172
|
+
* allowed-root scoping over the realpath of the file itself (which must exist).
|
|
173
|
+
*/
|
|
174
|
+
export async function acquireSourceBytes(rawPath, opts) {
|
|
175
|
+
if (!rawPath || typeof rawPath !== "string" || !rawPath.trim()) {
|
|
176
|
+
throw new BrigadeToolInputError("source path required");
|
|
177
|
+
}
|
|
178
|
+
const verdict = validateOutboundMediaPath(rawPath);
|
|
179
|
+
if (!verdict.ok) {
|
|
180
|
+
throw new BrigadeToolInputError(verdict.reason ?? "refusing to read that path");
|
|
181
|
+
}
|
|
182
|
+
let resolved;
|
|
183
|
+
try {
|
|
184
|
+
resolved = fs.realpathSync(path.resolve(rawPath));
|
|
185
|
+
}
|
|
186
|
+
catch {
|
|
187
|
+
resolved = path.resolve(rawPath);
|
|
188
|
+
}
|
|
189
|
+
const roots = allowedDocRoots(opts);
|
|
190
|
+
if (!isInsideAnyRoot(resolved, roots)) {
|
|
191
|
+
throw new BrigadeToolInputError("refusing to read a source outside the allowed roots (workspace / current dir / cache / temp). " +
|
|
192
|
+
"Move the file into the workspace first.");
|
|
193
|
+
}
|
|
194
|
+
let stat;
|
|
195
|
+
try {
|
|
196
|
+
stat = await fsp.stat(resolved);
|
|
197
|
+
}
|
|
198
|
+
catch {
|
|
199
|
+
throw new BrigadeToolInputError(`source file not found: ${rawPath}`);
|
|
200
|
+
}
|
|
201
|
+
if (!stat.isFile())
|
|
202
|
+
throw new BrigadeToolInputError(`not a file: ${rawPath}`);
|
|
203
|
+
if (stat.size === 0)
|
|
204
|
+
throw new BrigadeToolInputError(`source file is empty: ${rawPath}`);
|
|
205
|
+
if (stat.size > opts.maxBytes) {
|
|
206
|
+
throw new BrigadeToolInputError(`source file is too large (${stat.size} bytes > ${opts.maxBytes} cap).`);
|
|
207
|
+
}
|
|
208
|
+
return fsp.readFile(resolved);
|
|
209
|
+
}
|
|
210
|
+
/** Create the parent dir for a resolved output path, then write the bytes. */
|
|
211
|
+
export async function writeDocFile(absPath, bytes) {
|
|
212
|
+
await fsp.mkdir(path.dirname(absPath), { recursive: true });
|
|
213
|
+
const buf = Buffer.isBuffer(bytes) ? bytes : Buffer.from(bytes);
|
|
214
|
+
await fsp.writeFile(absPath, buf);
|
|
215
|
+
return buf.length;
|
|
216
|
+
}
|
|
217
|
+
/* ─────────────────────────── image acquisition + normalization ─────────────────────────── */
|
|
218
|
+
/** Default embed budget — images larger than this are downscaled before embedding. */
|
|
219
|
+
const DEFAULT_IMAGE_EMBED_BYTES = 4 * 1024 * 1024; // 4 MiB
|
|
220
|
+
/** Max pixel dimension for an embedded image (keeps file size + render time sane). */
|
|
221
|
+
const DEFAULT_IMAGE_EMBED_DIM = 2000;
|
|
222
|
+
/** Hard cap on bytes fetched for an image source (URL or local). */
|
|
223
|
+
const IMAGE_ACQUIRE_CEILING = 24 * 1024 * 1024; // 24 MiB
|
|
224
|
+
/** Per-request HTTP timeout for a URL image source. */
|
|
225
|
+
const IMAGE_FETCH_TIMEOUT_MS = 30_000;
|
|
226
|
+
/**
|
|
227
|
+
* Acquire an image from a local path (guarded) or http(s) URL (SSRF-guarded),
|
|
228
|
+
* decode it with jimp, fit-inside the embed dimension, and re-encode to a
|
|
229
|
+
* library-friendly raster (PNG for sources with alpha, JPEG otherwise — but we
|
|
230
|
+
* keep it simple and decode→PNG, falling back to JPEG when PNG would be larger
|
|
231
|
+
* than the budget). Throws `BrigadeToolInputError` on any failure so the caller
|
|
232
|
+
* never leaks a raw jimp/fetch throw to the model.
|
|
233
|
+
*
|
|
234
|
+
* `loadImage` is a test seam (defaults to the lazy jimp loader) so embedding can
|
|
235
|
+
* be exercised without bundling a real codec.
|
|
236
|
+
*/
|
|
237
|
+
export async function acquireImageForEmbed(source, opts) {
|
|
238
|
+
const ref = (source.url ?? source.path ?? "").trim();
|
|
239
|
+
if (!ref)
|
|
240
|
+
throw new BrigadeToolInputError("image requires a `path` or `url`");
|
|
241
|
+
const isUrl = /^https?:\/\//i.test(ref) || Boolean(source.url);
|
|
242
|
+
const maxBytes = clampImageBytes(opts.maxBytes);
|
|
243
|
+
const maxDim = opts.maxDimension && opts.maxDimension > 0 ? opts.maxDimension : DEFAULT_IMAGE_EMBED_DIM;
|
|
244
|
+
let raw;
|
|
245
|
+
if (isUrl) {
|
|
246
|
+
raw = await fetchImageBytes(ref, { signal: opts.signal });
|
|
247
|
+
}
|
|
248
|
+
else {
|
|
249
|
+
raw = await acquireSourceBytes(ref, {
|
|
250
|
+
...(opts.workspaceDir ? { workspaceDir: opts.workspaceDir } : {}),
|
|
251
|
+
...(opts.cwd ? { cwd: opts.cwd } : {}),
|
|
252
|
+
maxBytes: IMAGE_ACQUIRE_CEILING,
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
const load = opts.loadImage ?? defaultImageLoader;
|
|
256
|
+
let img;
|
|
257
|
+
try {
|
|
258
|
+
img = await load(raw);
|
|
259
|
+
}
|
|
260
|
+
catch {
|
|
261
|
+
throw new BrigadeToolInputError("could not decode the image (unsupported or corrupt format). Use a PNG / JPEG / GIF / BMP source.");
|
|
262
|
+
}
|
|
263
|
+
try {
|
|
264
|
+
if (img.width() > maxDim || img.height() > maxDim) {
|
|
265
|
+
img.scaleToFit(maxDim, maxDim);
|
|
266
|
+
}
|
|
267
|
+
// Encode PNG first (lossless, broadly accepted). If it blows the budget,
|
|
268
|
+
// fall back to JPEG which compresses photos far better.
|
|
269
|
+
let bytes = await img.encodePng();
|
|
270
|
+
let format = "png";
|
|
271
|
+
let mimeType = "image/png";
|
|
272
|
+
if (bytes.length > maxBytes) {
|
|
273
|
+
const jpg = await img.encodeJpeg(80);
|
|
274
|
+
if (jpg.length < bytes.length) {
|
|
275
|
+
bytes = jpg;
|
|
276
|
+
format = "jpeg";
|
|
277
|
+
mimeType = "image/jpeg";
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
return { bytes, format, mimeType, width: img.width(), height: img.height() };
|
|
281
|
+
}
|
|
282
|
+
catch {
|
|
283
|
+
throw new BrigadeToolInputError("failed to process the image for embedding.");
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
function clampImageBytes(requested) {
|
|
287
|
+
if (typeof requested !== "number" || !Number.isFinite(requested))
|
|
288
|
+
return DEFAULT_IMAGE_EMBED_BYTES;
|
|
289
|
+
return Math.max(64 * 1024, Math.min(IMAGE_ACQUIRE_CEILING, Math.floor(requested)));
|
|
290
|
+
}
|
|
291
|
+
/** Fetch an image URL through the SSRF guard with a size + timeout cap. */
|
|
292
|
+
async function fetchImageBytes(url, opts) {
|
|
293
|
+
let response;
|
|
294
|
+
try {
|
|
295
|
+
const r = await guardedFetch(url, {
|
|
296
|
+
method: "GET",
|
|
297
|
+
headers: {
|
|
298
|
+
accept: "image/*,*/*",
|
|
299
|
+
"user-agent": "Mozilla/5.0 (compatible; Brigade/1.0; +https://brigade.spinabot.com)",
|
|
300
|
+
},
|
|
301
|
+
timeoutMs: IMAGE_FETCH_TIMEOUT_MS,
|
|
302
|
+
...(opts.signal ? { signal: opts.signal } : {}),
|
|
303
|
+
});
|
|
304
|
+
response = r.response;
|
|
305
|
+
}
|
|
306
|
+
catch (err) {
|
|
307
|
+
if (err instanceof SsrfBlockedError) {
|
|
308
|
+
throw new BrigadeToolInputError(`refused to fetch the image URL: ${err.reason}`);
|
|
309
|
+
}
|
|
310
|
+
throw new BrigadeToolInputError(`could not fetch the image URL: ${err instanceof Error ? err.message : String(err)}`);
|
|
311
|
+
}
|
|
312
|
+
if (response.status >= 400) {
|
|
313
|
+
throw new BrigadeToolInputError(`image fetch failed: HTTP ${response.status} for ${url}`);
|
|
314
|
+
}
|
|
315
|
+
const ab = await response.arrayBuffer();
|
|
316
|
+
const buf = Buffer.from(ab);
|
|
317
|
+
if (buf.length === 0)
|
|
318
|
+
throw new BrigadeToolInputError("image URL returned an empty body");
|
|
319
|
+
if (buf.length > IMAGE_ACQUIRE_CEILING) {
|
|
320
|
+
throw new BrigadeToolInputError("image URL body exceeds the acquisition ceiling");
|
|
321
|
+
}
|
|
322
|
+
return buf;
|
|
323
|
+
}
|
|
324
|
+
/** Default loader — lazily imports jimp (keeps the cost off the cold-start path). */
|
|
325
|
+
const defaultImageLoader = async (bytes) => {
|
|
326
|
+
const { Jimp, JimpMime } = await import("jimp");
|
|
327
|
+
const img = await Jimp.read(bytes);
|
|
328
|
+
return {
|
|
329
|
+
width: () => img.bitmap.width,
|
|
330
|
+
height: () => img.bitmap.height,
|
|
331
|
+
scaleToFit: (w, h) => {
|
|
332
|
+
img.scaleToFit({ w, h });
|
|
333
|
+
},
|
|
334
|
+
encodePng: async () => {
|
|
335
|
+
const buf = await img.getBuffer(JimpMime.png);
|
|
336
|
+
return Buffer.isBuffer(buf) ? buf : Buffer.from(buf);
|
|
337
|
+
},
|
|
338
|
+
encodeJpeg: async (quality) => {
|
|
339
|
+
const buf = await img.getBuffer(JimpMime.jpeg, { quality });
|
|
340
|
+
return Buffer.isBuffer(buf) ? buf : Buffer.from(buf);
|
|
341
|
+
},
|
|
342
|
+
};
|
|
343
|
+
};
|
|
344
|
+
/** True when `v` is a `{ formula }` object (and not null / an array). */
|
|
345
|
+
export function isFormulaCell(v) {
|
|
346
|
+
return (typeof v === "object" &&
|
|
347
|
+
v !== null &&
|
|
348
|
+
!Array.isArray(v) &&
|
|
349
|
+
typeof v.formula === "string" &&
|
|
350
|
+
v.formula.trim().length > 0);
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* Coerce a tool cell value into the shape exceljs's `cell.value` expects:
|
|
354
|
+
* - `{ formula }` → `{ formula }` (the leading "=" is stripped if present)
|
|
355
|
+
* - number → number
|
|
356
|
+
* - everything else → String(value)
|
|
357
|
+
*/
|
|
358
|
+
export function toExcelCellValue(v) {
|
|
359
|
+
if (isFormulaCell(v)) {
|
|
360
|
+
return { formula: v.formula.trim().replace(/^=+/, "") };
|
|
361
|
+
}
|
|
362
|
+
if (typeof v === "number")
|
|
363
|
+
return v;
|
|
364
|
+
return String(v ?? "");
|
|
365
|
+
}
|
|
366
|
+
/* ─────────────────────────── unicode PDF font ─────────────────────────── */
|
|
367
|
+
/**
|
|
368
|
+
* A Unicode TrueType font (DejaVu Sans) embedded into a `@cantoo/pdf-lib`
|
|
369
|
+
* document so created PDFs + stamps render Latin / Latin-supplement / Greek /
|
|
370
|
+
* Cyrillic / accents instead of the WinAnsi-only standard fonts (which throw or
|
|
371
|
+
* tofu on anything outside their set).
|
|
372
|
+
*
|
|
373
|
+
* The font asset ships gzipped at `assets/DejaVuSans.ttf.gz` (Bitstream Vera /
|
|
374
|
+
* public-domain-equivalent license). It is decompressed once and cached as raw
|
|
375
|
+
* TTF bytes for the process lifetime; `fontkit` is registered + the font is
|
|
376
|
+
* embedded (with subsetting) PER document, since a pdf-lib `PDFFont` is bound to
|
|
377
|
+
* the document it was embedded into.
|
|
378
|
+
*
|
|
379
|
+
* CJK / emoji are NOT covered by DejaVu Sans and still fall back to "?" via
|
|
380
|
+
* {@link sanitizeForFont}; Latin/Greek/Cyrillic/accented text renders correctly.
|
|
381
|
+
*/
|
|
382
|
+
/** Lazily-decompressed DejaVu Sans TTF bytes (cached for the process). */
|
|
383
|
+
let cachedUnicodeFontBytes;
|
|
384
|
+
/** In-flight decompression promise so concurrent callers share one gunzip. */
|
|
385
|
+
let unicodeFontBytesPromise;
|
|
386
|
+
/** Absolute path to the gzipped font asset (resolved relative to this module). */
|
|
387
|
+
function unicodeFontAssetPath() {
|
|
388
|
+
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
389
|
+
return path.join(here, "assets", "DejaVuSans.ttf.gz");
|
|
390
|
+
}
|
|
391
|
+
/**
|
|
392
|
+
* Read + gunzip the bundled DejaVu Sans TTF (cached). Throws
|
|
393
|
+
* `BrigadeToolInputError` if the asset is missing or unreadable so the caller
|
|
394
|
+
* can fall back to a standard font instead of leaking a raw throw.
|
|
395
|
+
*/
|
|
396
|
+
export async function loadUnicodeFontBytes() {
|
|
397
|
+
if (cachedUnicodeFontBytes)
|
|
398
|
+
return cachedUnicodeFontBytes;
|
|
399
|
+
if (!unicodeFontBytesPromise) {
|
|
400
|
+
unicodeFontBytesPromise = (async () => {
|
|
401
|
+
const { gunzipSync } = await import("fflate");
|
|
402
|
+
let gz;
|
|
403
|
+
try {
|
|
404
|
+
gz = await fsp.readFile(unicodeFontAssetPath());
|
|
405
|
+
}
|
|
406
|
+
catch {
|
|
407
|
+
throw new BrigadeToolInputError("the bundled Unicode PDF font asset is missing.");
|
|
408
|
+
}
|
|
409
|
+
let ttf;
|
|
410
|
+
try {
|
|
411
|
+
ttf = gunzipSync(new Uint8Array(gz));
|
|
412
|
+
}
|
|
413
|
+
catch {
|
|
414
|
+
throw new BrigadeToolInputError("the bundled Unicode PDF font asset is corrupt.");
|
|
415
|
+
}
|
|
416
|
+
cachedUnicodeFontBytes = Buffer.from(ttf);
|
|
417
|
+
return cachedUnicodeFontBytes;
|
|
418
|
+
})();
|
|
419
|
+
}
|
|
420
|
+
try {
|
|
421
|
+
return await unicodeFontBytesPromise;
|
|
422
|
+
}
|
|
423
|
+
catch (err) {
|
|
424
|
+
// Reset the cache so a transient failure can be retried on the next call.
|
|
425
|
+
unicodeFontBytesPromise = undefined;
|
|
426
|
+
throw err;
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
/**
|
|
430
|
+
* Register fontkit on `pdf` and embed the bundled DejaVu Sans (subset), returning
|
|
431
|
+
* the embedded font. Embeds PER document (a pdf-lib font is document-bound).
|
|
432
|
+
* `registerFontkit` is idempotent, so calling it once per document is safe.
|
|
433
|
+
*/
|
|
434
|
+
export async function embedUnicodeFont(pdf) {
|
|
435
|
+
const ttf = await loadUnicodeFontBytes();
|
|
436
|
+
const fk = await import("@pdf-lib/fontkit");
|
|
437
|
+
const fontkit = fk.default ?? fk;
|
|
438
|
+
pdf.registerFontkit(fontkit);
|
|
439
|
+
return pdf.embedFont(new Uint8Array(ttf), { subset: true });
|
|
440
|
+
}
|
|
441
|
+
/**
|
|
442
|
+
* Replace characters the embedded font cannot render (e.g. CJK ideographs,
|
|
443
|
+
* emoji) with "?" so a stray glyph never turns a valid draw into a fontkit
|
|
444
|
+
* encode throw. DejaVu Sans covers Latin / Latin-1 / Latin Extended / Greek /
|
|
445
|
+
* Cyrillic + common punctuation, so those pass through untouched.
|
|
446
|
+
*
|
|
447
|
+
* `font` is the embedded fontkit-backed font; we ask it per character whether a
|
|
448
|
+
* glyph exists. When the font handle can't answer (older fontkit), we keep the
|
|
449
|
+
* character (the font is a broad Unicode face, so false-strips are worse than a
|
|
450
|
+
* rare tofu).
|
|
451
|
+
*/
|
|
452
|
+
export function sanitizeForFont(text, font) {
|
|
453
|
+
const probe = font.widthOfTextAtSize;
|
|
454
|
+
if (typeof probe !== "function")
|
|
455
|
+
return String(text ?? "");
|
|
456
|
+
let out = "";
|
|
457
|
+
for (const ch of String(text ?? "")) {
|
|
458
|
+
// Always keep the whitespace/control chars the drawers handle themselves.
|
|
459
|
+
if (ch === "\n" || ch === "\r" || ch === "\t" || ch === " ") {
|
|
460
|
+
out += ch;
|
|
461
|
+
continue;
|
|
462
|
+
}
|
|
463
|
+
let ok = false;
|
|
464
|
+
try {
|
|
465
|
+
// A glyph the font lacks measures as 0 width (no advance) in fontkit.
|
|
466
|
+
ok = font.widthOfTextAtSize(ch, 1000) > 0;
|
|
467
|
+
}
|
|
468
|
+
catch {
|
|
469
|
+
ok = false;
|
|
470
|
+
}
|
|
471
|
+
out += ok ? ch : "?";
|
|
472
|
+
}
|
|
473
|
+
return out;
|
|
474
|
+
}
|
|
475
|
+
/* ─────────────────────────── misc ─────────────────────────── */
|
|
476
|
+
/** A short random token for auto-naming a generated document. */
|
|
477
|
+
export function shortToken() {
|
|
478
|
+
return Math.random().toString(36).slice(2, 8);
|
|
479
|
+
}
|
|
480
|
+
/** Default workspace-relative output name when the caller omits `outputPath`. */
|
|
481
|
+
export function defaultOutputName(format) {
|
|
482
|
+
return `document-${shortToken()}.${extForFormat(format)}`;
|
|
483
|
+
}
|
|
484
|
+
//# sourceMappingURL=doc-shared.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doc-shared.js","sourceRoot":"","sources":["../../../src/agents/tools/doc-shared.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,GAAG,MAAM,kBAAkB,CAAC;AACnC,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAChF,OAAO,EAAE,yBAAyB,EAAE,MAAM,oCAAoC,CAAC;AAC/E,OAAO,EACN,eAAe,EACf,iBAAiB,EACjB,eAAe,GACf,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAKpD,6CAA6C;AAC7C,MAAM,UAAU,YAAY,CAAC,MAAiB;IAC7C,OAAO,MAAM,CAAC,CAAC,+CAA+C;AAC/D,CAAC;AAED,8CAA8C;AAC9C,MAAM,UAAU,cAAc,CAAC,CAAS;IACvC,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AACzD,CAAC;AAED,wEAAwE;AACxE,MAAM,UAAU,mBAAmB,CAAC,CAAS;IAC5C,MAAM,GAAG,GAAG,cAAc,CAAC,CAAC,CAAC,CAAC;IAC9B,IAAI,GAAG,KAAK,MAAM,IAAI,GAAG,KAAK,MAAM,IAAI,GAAG,KAAK,MAAM,IAAI,GAAG,KAAK,KAAK;QAAE,OAAO,GAAG,CAAC;IACpF,OAAO,SAAS,CAAC;AAClB,CAAC;AAED,kFAAkF;AAElF;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAAC,IAA6C;IAC5E,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;IAChC,MAAM,GAAG,GAAG,CAAC,CAAU,EAAE,EAAE;QAC1B,IAAI,CAAC,CAAC;YAAE,OAAO;QACf,IAAI,CAAC;YACJ,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;QAC5B,CAAC;QAAC,MAAM,CAAC;YACR,YAAY;QACb,CAAC;IACF,CAAC,CAAC;IACF,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IACvB,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACd,GAAG,CAAC,eAAe,EAAE,CAAC,CAAC;IACvB,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC;IACrE,IAAI,CAAC;QACJ,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC;IAClB,CAAC;IAAC,MAAM,CAAC;QACR,YAAY;IACb,CAAC;IACD,IAAI,CAAC;QACJ,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,EAAE,UAAU,CAAC,CAAC,CAAC;QAC9C,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC;QAC3C,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,EAAE,UAAU,CAAC,CAAC,CAAC;QAC9C,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,EAAE,WAAW,CAAC,CAAC,CAAC;IAChD,CAAC;IAAC,MAAM,CAAC;QACR,YAAY;IACb,CAAC;IACD,IAAI,CAAC;QACJ,MAAM,OAAO,GAAG,iBAAiB,EAAE,CAAC;QACpC,GAAG,CAAC,OAAO,CAAC,CAAC;QACb,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC;QACpC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC;IACxC,CAAC;IAAC,MAAM,CAAC;QACR,YAAY;IACb,CAAC;IACD,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AAC/C,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,eAAe,CAAC,QAAgB,EAAE,KAAe;IAChE,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QAC1B,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QAC1C,IAAI,GAAG,KAAK,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;YAAE,OAAO,IAAI,CAAC;IACjF,CAAC;IACD,OAAO,KAAK,CAAC;AACd,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,iBAAiB,CAChC,OAAe,EACf,IAA6C;IAE7C,IAAI,CAAC,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC;QAChE,MAAM,IAAI,qBAAqB,CAAC,sBAAsB,CAAC,CAAC;IACzD,CAAC;IACD,MAAM,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IAC/G,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAE3F,2EAA2E;IAC3E,MAAM,OAAO,GAAG,yBAAyB,CAAC,GAAG,CAAC,CAAC;IAC/C,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,qBAAqB,CAAC,OAAO,CAAC,MAAM,IAAI,6BAA6B,CAAC,CAAC;IAClF,CAAC;IAED,4EAA4E;IAC5E,sDAAsD;IACtD,MAAM,KAAK,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;IACpC,MAAM,MAAM,GAAG,2BAA2B,CAAC,GAAG,CAAC,CAAC;IAChD,IAAI,CAAC,eAAe,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC;QACrC,MAAM,IAAI,qBAAqB,CAC9B,+FAA+F;YAC9F,4EAA4E,CAC7E,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACZ,CAAC;AAED,kGAAkG;AAClG,SAAS,2BAA2B,CAAC,GAAW;IAC/C,IAAI,GAAG,GAAG,GAAG,CAAC;IACd,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC;QAC7B,IAAI,CAAC;YACJ,OAAO,EAAE,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;QAC7B,CAAC;QAAC,MAAM,CAAC;YACR,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YACjC,IAAI,MAAM,KAAK,GAAG;gBAAE,OAAO,GAAG,CAAC,CAAC,mBAAmB;YACnD,GAAG,GAAG,MAAM,CAAC;QACd,CAAC;IACF,CAAC;IACD,OAAO,GAAG,CAAC;AACZ,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACvC,OAAe,EACf,IAA+D;IAE/D,IAAI,CAAC,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC;QAChE,MAAM,IAAI,qBAAqB,CAAC,sBAAsB,CAAC,CAAC;IACzD,CAAC;IACD,MAAM,OAAO,GAAG,yBAAyB,CAAC,OAAO,CAAC,CAAC;IACnD,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,qBAAqB,CAAC,OAAO,CAAC,MAAM,IAAI,4BAA4B,CAAC,CAAC;IACjF,CAAC;IACD,IAAI,QAAgB,CAAC;IACrB,IAAI,CAAC;QACJ,QAAQ,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;IACnD,CAAC;IAAC,MAAM,CAAC;QACR,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAClC,CAAC;IACD,MAAM,KAAK,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;IACpC,IAAI,CAAC,eAAe,CAAC,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC;QACvC,MAAM,IAAI,qBAAqB,CAC9B,gGAAgG;YAC/F,yCAAyC,CAC1C,CAAC;IACH,CAAC;IACD,IAAI,IAAc,CAAC;IACnB,IAAI,CAAC;QACJ,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACjC,CAAC;IAAC,MAAM,CAAC;QACR,MAAM,IAAI,qBAAqB,CAAC,0BAA0B,OAAO,EAAE,CAAC,CAAC;IACtE,CAAC;IACD,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE;QAAE,MAAM,IAAI,qBAAqB,CAAC,eAAe,OAAO,EAAE,CAAC,CAAC;IAC9E,IAAI,IAAI,CAAC,IAAI,KAAK,CAAC;QAAE,MAAM,IAAI,qBAAqB,CAAC,yBAAyB,OAAO,EAAE,CAAC,CAAC;IACzF,IAAI,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;QAC/B,MAAM,IAAI,qBAAqB,CAC9B,6BAA6B,IAAI,CAAC,IAAI,YAAY,IAAI,CAAC,QAAQ,QAAQ,CACvE,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;AAC/B,CAAC;AAED,8EAA8E;AAC9E,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,OAAe,EAAE,KAA0B;IAC7E,MAAM,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5D,MAAM,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAChE,MAAM,GAAG,CAAC,SAAS,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IAClC,OAAO,GAAG,CAAC,MAAM,CAAC;AACnB,CAAC;AAED,+FAA+F;AAE/F,sFAAsF;AACtF,MAAM,yBAAyB,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,QAAQ;AAC3D,sFAAsF;AACtF,MAAM,uBAAuB,GAAG,IAAI,CAAC;AACrC,oEAAoE;AACpE,MAAM,qBAAqB,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,SAAS;AACzD,uDAAuD;AACvD,MAAM,sBAAsB,GAAG,MAAM,CAAC;AAYtC;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACzC,MAAuC,EACvC,IAOC;IAED,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACrD,IAAI,CAAC,GAAG;QAAE,MAAM,IAAI,qBAAqB,CAAC,kCAAkC,CAAC,CAAC;IAC9E,MAAM,KAAK,GAAG,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAC/D,MAAM,QAAQ,GAAG,eAAe,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAChD,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,uBAAuB,CAAC;IAExG,IAAI,GAAW,CAAC;IAChB,IAAI,KAAK,EAAE,CAAC;QACX,GAAG,GAAG,MAAM,eAAe,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;IAC3D,CAAC;SAAM,CAAC;QACP,GAAG,GAAG,MAAM,kBAAkB,CAAC,GAAG,EAAE;YACnC,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,IAAI,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACjE,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACtC,QAAQ,EAAE,qBAAqB;SAC/B,CAAC,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,IAAI,kBAAkB,CAAC;IAClD,IAAI,GAAmB,CAAC;IACxB,IAAI,CAAC;QACJ,GAAG,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,CAAC;IACvB,CAAC;IAAC,MAAM,CAAC;QACR,MAAM,IAAI,qBAAqB,CAC9B,kGAAkG,CAClG,CAAC;IACH,CAAC;IACD,IAAI,CAAC;QACJ,IAAI,GAAG,CAAC,KAAK,EAAE,GAAG,MAAM,IAAI,GAAG,CAAC,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC;YACnD,GAAG,CAAC,UAAU,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAChC,CAAC;QACD,yEAAyE;QACzE,wDAAwD;QACxD,IAAI,KAAK,GAAG,MAAM,GAAG,CAAC,SAAS,EAAE,CAAC;QAClC,IAAI,MAAM,GAAmB,KAAK,CAAC;QACnC,IAAI,QAAQ,GAAG,WAAW,CAAC;QAC3B,IAAI,KAAK,CAAC,MAAM,GAAG,QAAQ,EAAE,CAAC;YAC7B,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;YACrC,IAAI,GAAG,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;gBAC/B,KAAK,GAAG,GAAG,CAAC;gBACZ,MAAM,GAAG,MAAM,CAAC;gBAChB,QAAQ,GAAG,YAAY,CAAC;YACzB,CAAC;QACF,CAAC;QACD,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,EAAE,CAAC;IAC9E,CAAC;IAAC,MAAM,CAAC;QACR,MAAM,IAAI,qBAAqB,CAAC,4CAA4C,CAAC,CAAC;IAC/E,CAAC;AACF,CAAC;AAED,SAAS,eAAe,CAAC,SAA6B;IACrD,IAAI,OAAO,SAAS,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC;QAAE,OAAO,yBAAyB,CAAC;IACnG,OAAO,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,qBAAqB,EAAE,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AACpF,CAAC;AAED,2EAA2E;AAC3E,KAAK,UAAU,eAAe,CAAC,GAAW,EAAE,IAA8B;IACzE,IAAI,QAAkB,CAAC;IACvB,IAAI,CAAC;QACJ,MAAM,CAAC,GAAG,MAAM,YAAY,CAAC,GAAG,EAAE;YACjC,MAAM,EAAE,KAAK;YACb,OAAO,EAAE;gBACR,MAAM,EAAE,aAAa;gBACrB,YAAY,EAAE,sEAAsE;aACpF;YACD,SAAS,EAAE,sBAAsB;YACjC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC/C,CAAC,CAAC;QACH,QAAQ,GAAG,CAAC,CAAC,QAAQ,CAAC;IACvB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACd,IAAI,GAAG,YAAY,gBAAgB,EAAE,CAAC;YACrC,MAAM,IAAI,qBAAqB,CAAC,mCAAmC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;QAClF,CAAC;QACD,MAAM,IAAI,qBAAqB,CAC9B,kCAAkC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CACpF,CAAC;IACH,CAAC;IACD,IAAI,QAAQ,CAAC,MAAM,IAAI,GAAG,EAAE,CAAC;QAC5B,MAAM,IAAI,qBAAqB,CAAC,4BAA4B,QAAQ,CAAC,MAAM,QAAQ,GAAG,EAAE,CAAC,CAAC;IAC3F,CAAC;IACD,MAAM,EAAE,GAAG,MAAM,QAAQ,CAAC,WAAW,EAAE,CAAC;IACxC,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC5B,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;QAAE,MAAM,IAAI,qBAAqB,CAAC,kCAAkC,CAAC,CAAC;IAC1F,IAAI,GAAG,CAAC,MAAM,GAAG,qBAAqB,EAAE,CAAC;QACxC,MAAM,IAAI,qBAAqB,CAAC,gDAAgD,CAAC,CAAC;IACnF,CAAC;IACD,OAAO,GAAG,CAAC;AACZ,CAAC;AAaD,qFAAqF;AACrF,MAAM,kBAAkB,GAAgB,KAAK,EAAE,KAAa,EAA2B,EAAE;IACxF,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,CAAC;IAChD,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACnC,OAAO;QACN,KAAK,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK;QAC7B,MAAM,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM;QAC/B,UAAU,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;YACpB,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QAC1B,CAAC;QACD,SAAS,EAAE,KAAK,IAAI,EAAE;YACrB,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;YAC9C,OAAO,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAA6B,CAAC,CAAC;QAChF,CAAC;QACD,UAAU,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;YAC7B,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;YAC5D,OAAO,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAA6B,CAAC,CAAC;QAChF,CAAC;KACD,CAAC;AACH,CAAC,CAAC;AAaF,yEAAyE;AACzE,MAAM,UAAU,aAAa,CAAC,CAAU;IACvC,OAAO,CACN,OAAO,CAAC,KAAK,QAAQ;QACrB,CAAC,KAAK,IAAI;QACV,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;QACjB,OAAQ,CAA2B,CAAC,OAAO,KAAK,QAAQ;QACvD,CAAyB,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CACpD,CAAC;AACH,CAAC;AAKD;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,CAAe;IAC/C,IAAI,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC;QACtB,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,EAAE,CAAC;IACzD,CAAC;IACD,IAAI,OAAO,CAAC,KAAK,QAAQ;QAAE,OAAO,CAAC,CAAC;IACpC,OAAO,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;AACxB,CAAC;AAED,8EAA8E;AAE9E;;;;;;;;;;;;;;GAcG;AAEH,0EAA0E;AAC1E,IAAI,sBAA0C,CAAC;AAC/C,8EAA8E;AAC9E,IAAI,uBAAoD,CAAC;AAEzD,kFAAkF;AAClF,SAAS,oBAAoB;IAC5B,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1D,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,mBAAmB,CAAC,CAAC;AACvD,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB;IACzC,IAAI,sBAAsB;QAAE,OAAO,sBAAsB,CAAC;IAC1D,IAAI,CAAC,uBAAuB,EAAE,CAAC;QAC9B,uBAAuB,GAAG,CAAC,KAAK,IAAI,EAAE;YACrC,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAC;YAC9C,IAAI,EAAU,CAAC;YACf,IAAI,CAAC;gBACJ,EAAE,GAAG,MAAM,GAAG,CAAC,QAAQ,CAAC,oBAAoB,EAAE,CAAC,CAAC;YACjD,CAAC;YAAC,MAAM,CAAC;gBACR,MAAM,IAAI,qBAAqB,CAAC,gDAAgD,CAAC,CAAC;YACnF,CAAC;YACD,IAAI,GAAe,CAAC;YACpB,IAAI,CAAC;gBACJ,GAAG,GAAG,UAAU,CAAC,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC;YACtC,CAAC;YAAC,MAAM,CAAC;gBACR,MAAM,IAAI,qBAAqB,CAAC,gDAAgD,CAAC,CAAC;YACnF,CAAC;YACD,sBAAsB,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAC1C,OAAO,sBAAsB,CAAC;QAC/B,CAAC,CAAC,EAAE,CAAC;IACN,CAAC;IACD,IAAI,CAAC;QACJ,OAAO,MAAM,uBAAuB,CAAC;IACtC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACd,0EAA0E;QAC1E,uBAAuB,GAAG,SAAS,CAAC;QACpC,MAAM,GAAG,CAAC;IACX,CAAC;AACF,CAAC;AAcD;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,GAAe;IACrD,MAAM,GAAG,GAAG,MAAM,oBAAoB,EAAE,CAAC;IACzC,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,CAAC;IAC5C,MAAM,OAAO,GAAI,EAA4B,CAAC,OAAO,IAAI,EAAE,CAAC;IAC5D,GAAG,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;IAC7B,OAAO,GAAG,CAAC,SAAS,CAAC,IAAI,UAAU,CAAC,GAAG,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;AAC7D,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,eAAe,CAAC,IAAY,EAAE,IAAiB;IAC9D,MAAM,KAAK,GAAI,IAAiE,CAAC,iBAAiB,CAAC;IACnG,IAAI,OAAO,KAAK,KAAK,UAAU;QAAE,OAAO,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;IAC3D,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,KAAK,MAAM,EAAE,IAAI,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC,EAAE,CAAC;QACrC,0EAA0E;QAC1E,IAAI,EAAE,KAAK,IAAI,IAAI,EAAE,KAAK,IAAI,IAAI,EAAE,KAAK,IAAI,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;YAC7D,GAAG,IAAI,EAAE,CAAC;YACV,SAAS;QACV,CAAC;QACD,IAAI,EAAE,GAAG,KAAK,CAAC;QACf,IAAI,CAAC;YACJ,sEAAsE;YACtE,EAAE,GAAG,IAAI,CAAC,iBAAiB,CAAC,EAAE,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;QAC3C,CAAC;QAAC,MAAM,CAAC;YACR,EAAE,GAAG,KAAK,CAAC;QACZ,CAAC;QACD,GAAG,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC;IACtB,CAAC;IACD,OAAO,GAAG,CAAC;AACZ,CAAC;AAED,kEAAkE;AAElE,iEAAiE;AACjE,MAAM,UAAU,UAAU;IACzB,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAC/C,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,iBAAiB,CAAC,MAAiB;IAClD,OAAO,YAAY,UAAU,EAAE,IAAI,YAAY,CAAC,MAAM,CAAC,EAAE,CAAC;AAC3D,CAAC"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `edit_document` — EDIT an existing Word / Excel / PowerPoint / PDF file in
|
|
3
|
+
* place (or to a sibling). The high-fidelity counterpart to `make_document`:
|
|
4
|
+
* where create builds a file from scratch, edit OPENS an existing one and
|
|
5
|
+
* mutates it, preserving the parts it does not touch.
|
|
6
|
+
*
|
|
7
|
+
* ─────────────────────────────────────────────────────────────────────────
|
|
8
|
+
* HIGH-FIDELITY TECHNIQUE (read before changing)
|
|
9
|
+
* ─────────────────────────────────────────────────────────────────────────
|
|
10
|
+
* Two strategies depending on format + action:
|
|
11
|
+
*
|
|
12
|
+
* • docx/pptx `replace_text` → the OOXML UNZIP→edit-XML→REZIP technique
|
|
13
|
+
* (the same one `analyze_media` reads with): `fflate.unzipSync` the file,
|
|
14
|
+
* run a string replacement over the text runs in `word/document.xml`
|
|
15
|
+
* (docx) or every `ppt/slides/slideN.xml` (pptx), then `fflate.zipSync`
|
|
16
|
+
* the entries back. This preserves ALL styling, themes, images, and
|
|
17
|
+
* relationships — only the run text changes. (A full `docx patchDocument`
|
|
18
|
+
* token-replace is available too via the `docx` lib, but the unzip-rezip
|
|
19
|
+
* path keeps arbitrary existing formatting that patchDocument would not
|
|
20
|
+
* round-trip, and works identically for pptx which has no patch API.)
|
|
21
|
+
*
|
|
22
|
+
* • docx `append` → re-open is not needed: we unzip, splice new paragraph
|
|
23
|
+
* XML before `</w:body>`, and rezip — additive, style-preserving.
|
|
24
|
+
*
|
|
25
|
+
* • xlsx `set_cells` / `append_rows` → `exceljs` read→modify→write, which
|
|
26
|
+
* preserves the other sheets + their formatting.
|
|
27
|
+
*
|
|
28
|
+
* • pdf `fill_form` / `merge` / `split` / `stamp` / `add_pages` /
|
|
29
|
+
* `remove_pages` → `@cantoo/pdf-lib` load→mutate→save.
|
|
30
|
+
*
|
|
31
|
+
* SECURITY: the SOURCE path is scoped with the SAME guard as `analyze_media`'s
|
|
32
|
+
* local reads (`acquireSourceBytes`), and the OUTPUT path with the same write
|
|
33
|
+
* guard as `make_document` (`resolveOutputPath`). Reading a source OR writing an
|
|
34
|
+
* output outside the allowed roots is refused. Default output overwrites the
|
|
35
|
+
* source. NOT owner-only — editing a workspace file is safe and the path guards
|
|
36
|
+
* are the boundary.
|
|
37
|
+
*
|
|
38
|
+
* Robust to malformed input: every failure surfaces as a `BrigadeToolInputError`
|
|
39
|
+
* (clean `.message` to the model), never a raw library throw.
|
|
40
|
+
*/
|
|
41
|
+
import { Type } from "typebox";
|
|
42
|
+
import type { BrigadeTool } from "./types.js";
|
|
43
|
+
import { type DocFormat } from "./doc-shared.js";
|
|
44
|
+
declare const EditDocumentParams: Type.TObject<{
|
|
45
|
+
source: Type.TString;
|
|
46
|
+
format: Type.TOptional<Type.TUnion<[Type.TLiteral<"docx">, Type.TLiteral<"xlsx">, Type.TLiteral<"pptx">, Type.TLiteral<"pdf">]>>;
|
|
47
|
+
action: Type.TString;
|
|
48
|
+
outputPath: Type.TOptional<Type.TString>;
|
|
49
|
+
find: Type.TOptional<Type.TString>;
|
|
50
|
+
replace: Type.TOptional<Type.TString>;
|
|
51
|
+
values: Type.TOptional<Type.TRecord<"^.*$", Type.TUnion<[Type.TString, Type.TNumber]>>>;
|
|
52
|
+
paragraphs: Type.TOptional<Type.TArray<Type.TString>>;
|
|
53
|
+
heading: Type.TOptional<Type.TString>;
|
|
54
|
+
sheet: Type.TOptional<Type.TString>;
|
|
55
|
+
cells: Type.TOptional<Type.TArray<Type.TObject<{
|
|
56
|
+
ref: Type.TOptional<Type.TString>;
|
|
57
|
+
row: Type.TOptional<Type.TInteger>;
|
|
58
|
+
col: Type.TOptional<Type.TInteger>;
|
|
59
|
+
value: Type.TUnion<[Type.TString, Type.TNumber, Type.TObject<{
|
|
60
|
+
formula: Type.TString;
|
|
61
|
+
numFmt: Type.TOptional<Type.TString>;
|
|
62
|
+
}>]>;
|
|
63
|
+
numFmt: Type.TOptional<Type.TString>;
|
|
64
|
+
}>>>;
|
|
65
|
+
rows: Type.TOptional<Type.TArray<Type.TArray<Type.TUnion<[Type.TString, Type.TNumber, Type.TObject<{
|
|
66
|
+
formula: Type.TString;
|
|
67
|
+
numFmt: Type.TOptional<Type.TString>;
|
|
68
|
+
}>]>>>>;
|
|
69
|
+
fields: Type.TOptional<Type.TRecord<"^.*$", Type.TUnion<[Type.TString, Type.TNumber, Type.TBoolean]>>>;
|
|
70
|
+
pdfs: Type.TOptional<Type.TArray<Type.TString>>;
|
|
71
|
+
pages: Type.TOptional<Type.TString>;
|
|
72
|
+
text: Type.TOptional<Type.TString>;
|
|
73
|
+
}>;
|
|
74
|
+
export interface EditDocumentDetails {
|
|
75
|
+
ok: boolean;
|
|
76
|
+
action: string;
|
|
77
|
+
format: DocFormat;
|
|
78
|
+
path?: string;
|
|
79
|
+
paths?: string[];
|
|
80
|
+
bytes?: number;
|
|
81
|
+
pages?: number;
|
|
82
|
+
replacements?: number;
|
|
83
|
+
cellsSet?: number;
|
|
84
|
+
rowsAppended?: number;
|
|
85
|
+
fieldsSet?: number;
|
|
86
|
+
tokensFilled?: string[];
|
|
87
|
+
tokensNotFound?: string[];
|
|
88
|
+
warning?: string;
|
|
89
|
+
message?: string;
|
|
90
|
+
}
|
|
91
|
+
export interface MakeEditDocumentToolOptions {
|
|
92
|
+
workspaceDir?: string;
|
|
93
|
+
cwd?: string;
|
|
94
|
+
agentId?: string;
|
|
95
|
+
}
|
|
96
|
+
export declare function makeEditDocumentTool(opts?: MakeEditDocumentToolOptions): BrigadeTool<typeof EditDocumentParams, EditDocumentDetails>;
|
|
97
|
+
/**
|
|
98
|
+
* Apply one or more find→replace pairs to the run text of every paragraph in an
|
|
99
|
+
* OOXML part, matching ACROSS run boundaries. Word/PowerPoint frequently split a
|
|
100
|
+
* single visible word into several `<w:t>`/`<a:t>` runs (spell-check, rsid,
|
|
101
|
+
* proofing marks); matching only within one run misses those. This joins the
|
|
102
|
+
* decoded text of each paragraph's runs, plans replacements over the joined
|
|
103
|
+
* string, writes each replacement into the run that owns the match start, blanks
|
|
104
|
+
* the rest of the matched span, and leaves untouched runs (and all styling,
|
|
105
|
+
* attributes and non-text tags) exactly as they were.
|
|
106
|
+
*/
|
|
107
|
+
export declare function replaceAcrossRuns(xml: string, pairs: Array<{
|
|
108
|
+
find: string;
|
|
109
|
+
replace: string;
|
|
110
|
+
}>): {
|
|
111
|
+
xml: string;
|
|
112
|
+
count: number;
|
|
113
|
+
};
|
|
114
|
+
/**
|
|
115
|
+
* Replace `find` with `replace` inside the TEXT of OOXML runs, matching ACROSS
|
|
116
|
+
* run boundaries (Word/PowerPoint split words into multiple `<w:t>`/`<a:t>`
|
|
117
|
+
* runs). All tags, attributes, styling, images and relationships are preserved;
|
|
118
|
+
* only run text changes and the replacement is re-escaped. Backed by
|
|
119
|
+
* {@link replaceAcrossRuns}; kept as the single-pair entry point used by
|
|
120
|
+
* `replace_text` and (per token) `fill_template`.
|
|
121
|
+
*/
|
|
122
|
+
export declare function replaceInRunText(xml: string, find: string, replace: string): {
|
|
123
|
+
xml: string;
|
|
124
|
+
count: number;
|
|
125
|
+
};
|
|
126
|
+
/**
|
|
127
|
+
* Parse a 1-indexed page list like "1-3,5,8-" into a sorted, de-duped array of
|
|
128
|
+
* page numbers within [1, total]. Invalid fragments are skipped (never throws).
|
|
129
|
+
* Exported for tests.
|
|
130
|
+
*/
|
|
131
|
+
export declare function parsePageList(spec: string, total: number): number[];
|
|
132
|
+
export {};
|
|
133
|
+
//# sourceMappingURL=edit-document-tool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"edit-document-tool.d.ts","sourceRoot":"","sources":["../../../src/agents/tools/edit-document-tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAIH,OAAO,EAAE,IAAI,EAAe,MAAM,SAAS,CAAC;AAG5C,OAAO,KAAK,EAAmB,WAAW,EAAE,MAAM,YAAY,CAAC;AAC/D,OAAO,EAUN,KAAK,SAAS,EAEd,MAAM,iBAAiB,CAAC;AAuBzB,QAAA,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAgEtB,CAAC;AAEH,MAAM,WAAW,mBAAmB;IACnC,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,SAAS,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAID,MAAM,WAAW,2BAA2B;IAC3C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,oBAAoB,CACnC,IAAI,GAAE,2BAAgC,GACpC,WAAW,CAAC,OAAO,kBAAkB,EAAE,mBAAmB,CAAC,CA6D7D;AA6iBD;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAChC,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,GAC7C;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CA6BhC;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC/B,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,GACb;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAGhC;AAoFD;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAkBnE"}
|