refactor(office): remove command launchers and shell compatibility changes
This commit is contained in:
1 parent
88f5ed353e
commit
bfcc6d50d0
95 files changed
+329
-988
No files matched your search
+2
-2
@@ -9,8 +9,8 @@
|
||||
en: a9984a594cdac98d
|
||||
zh: 38768e7699bc8d39
|
||||
/agent-note-progressive-office-skills-with-ordinary-shell-execution/decision:
|
||||
en: b4572697def440af
|
||||
zh: d0c16ab71a1c3aaf
|
||||
en: d057c558d6b9803c
|
||||
zh: acf3fdbc4cd7cee3
|
||||
/agent-note-progressive-office-skills-with-ordinary-shell-execution/alternatives-considered:
|
||||
en: 8bca955255e6d982
|
||||
zh: bc313a4bcab3f6f9
|
||||
|
||||
@@ -11,9 +11,9 @@ Combined authoring and rendering instructions spend context on operations unrela
|
||||
## Decision
|
||||
|
||||
|
||||
The [Office provider](../../../../packages/skill/skill-office/README.md) lists a compact router and six format-specific authoring or operation skills. The model loads full instructions by name and selects rendering for appearance-focused changes unless the user explicitly skips it. Rendering uses a private, randomly named temporary directory inside the task workspace and removes it after inspection. Skills invoke `office-check` and `dsoffice` through ordinary Bash or PowerShell. SDK and Desktop own their Office composition separately; ordinary Web and the shared base do not mount these plugins.
|
||||
The [Office provider](../../../../packages/skill/skill-office/README.md) lists a compact router and six format-specific authoring or operation skills. The model loads full instructions by name and selects rendering for appearance-focused changes unless the user explicitly skips it. Rendering uses a private, randomly named temporary directory inside the task workspace and removes it after inspection. Skills invoke the shared Python checker and configured LibreOffice Kit CLI through ordinary Bash or PowerShell. SDK and Desktop own their Office composition separately; ordinary Web and the shared base do not mount these plugins.
|
||||
|
||||
The command plugin contributes local launchers through [shell-env](../../../../packages/shell/shell-env/README.md) to each shell call's `PATH`. Carriers own interpreter and resource locations; those paths stay outside skill instructions. Loading skills and registering commands do not prepare engines or authoring payloads. Standalone rendering, PDF export, and recalculation require only their operation skill. This keeps instruction loading independent of installed runtime layout while shell execution retains its existing permissions and process management.
|
||||
Carriers own interpreter and resource locations. Operation skills append the configured Node and CLI paths only when their bodies are loaded; authoring skills use the selected Python and shared checker resource. Loading instructions does not prepare engines or authoring payloads. Ordinary shell execution retains its existing permissions and process management.
|
||||
|
||||
Office dependency ranges allow patch updates; the root lock records the resolved adapter and engine versions.
|
||||
|
||||
|
||||
@@ -11,9 +11,9 @@ Status: implemented
|
||||
## 决策
|
||||
|
||||
|
||||
[Office 提供者](../../../../packages/skill/skill-office/README.zh.md) 列出精简路由和六个各格式创作或操作技能。模型按名称加载完整说明;以外观为目标的修改会选择渲染,除非用户明确要求跳过。渲染使用任务工作区内随机命名的私有临时目录,并在检查后删除。技能通过普通 Bash 或 PowerShell 调用 `office-check` 和 `dsoffice`。SDK 和 Desktop 分别拥有 Office 组合;普通 Web 和共享 base 不挂载这些插件。
|
||||
[Office 提供者](../../../../packages/skill/skill-office/README.zh.md) 列出精简路由和六个各格式创作或操作技能。模型按名称加载完整说明;以外观为目标的修改会选择渲染,除非用户明确要求跳过。渲染使用任务工作区内随机命名的私有临时目录,并在检查后删除。技能通过普通 Bash 或 PowerShell 调用共享 Python 检查器和配置的 LibreOffice Kit CLI。SDK 和 Desktop 分别拥有 Office 组合;普通 Web 和共享 base 不挂载这些插件。
|
||||
|
||||
命令插件通过 [shell-env](../../../../packages/shell/shell-env/README.zh.md) 将本地启动器加入每次 shell 调用的 `PATH`。载体负责解释器和资源位置;这些路径不进入技能说明。加载技能和注册命令不准备引擎或创作 payload。独立渲染、PDF 导出和重算只需对应操作技能。这使说明加载独立于已安装运行时的布局,同时 shell 执行保留现有权限和进程管理。
|
||||
载体负责解释器和资源位置。操作技能仅在加载正文时附加配置的 Node 与 CLI 路径;创作技能使用选定的 Python 和共享检查器资源。加载说明不准备引擎或创作 payload。普通 shell 执行保留现有权限和进程管理。
|
||||
|
||||
Office 依赖范围允许补丁版本更新;根锁文件记录实际解析的适配器与引擎版本。
|
||||
|
||||
|
||||
@@ -462,7 +462,7 @@ it.each(['unset', 'empty', 'bundled', 'full', 'python-only', 'python-only-no-cli
|
||||
if (address === null || typeof address === 'string') throw new Error('model fixture did not bind')
|
||||
const home = join(root, 'home')
|
||||
const cliPatch = join(root, 'cli.patch.yml')
|
||||
await writeFile(cliPatch, JSON.stringify(mode === 'python-only-no-cli' ? [{ id: 'skill-office', config: { assetRoot: join(root, 'resources', 'office-skills') } }, { id: 'office-commands', config: { command: false } }] : []))
|
||||
await writeFile(cliPatch, JSON.stringify(mode === 'python-only-no-cli' ? [{ id: 'skill-office', config: { assetRoot: join(root, 'resources', 'office-skills'), cli: false } }] : []))
|
||||
const officeLaunch = resolveExampleLaunch({
|
||||
srcBin: fileURLToPath(new URL('../../../src/bin.ts', import.meta.url)), mode: 'lib',
|
||||
configArgs: ['--profile', 'sdk', '--patch', cliPatch],
|
||||
@@ -498,7 +498,7 @@ it.each(['unset', 'empty', 'bundled', 'full', 'python-only', 'python-only-no-cli
|
||||
expect(names).not.toContain('office_tools')
|
||||
expect(names).not.toContain('render_document')
|
||||
for (const name of ['office-docx', 'office-pptx', 'office-xlsx']) {
|
||||
expect(JSON.stringify(requests[0]!.messages).includes(name)).toBe(false)
|
||||
expect(JSON.stringify(requests[0]!.messages).includes(name)).toBe(enabled && mode !== 'missing-assets')
|
||||
}
|
||||
if (mode === 'wrong-type') {
|
||||
expect(requests).toHaveLength(2)
|
||||
|
||||
@@ -35,16 +35,7 @@ it.skipIf(!process.env.DEEPSEEK_API_KEY || process.platform === 'win32')(`agent
|
||||
...(process.env.DSH_OFFICE_TEST_API === 'openai-completions' ? [{ id: 'llm-deepseek', disabled: true }, { id: 'llm-pi-ai', config: { providers: { 'office-test': { api: 'openai-completions', apiKeyEnv: 'DEEPSEEK_API_KEY', baseURL: process.env.DEEPSEEK_BASE_URL, compat: { thinkingFormat: 'deepseek' }, models: [{ id: process.env.MODEL_NAME ?? 'deepseek-v4-flash', contextWindow: 128000, maxTokens: 8000 }] } } } }] : []),
|
||||
{ id: 'session-persistence-jsonl', config: { root: join(root, 'sessions'), compression: 'none' } },
|
||||
{ id: 'skill-office', disabled: false },
|
||||
{ id: 'office-commands', disabled: false },
|
||||
...assetRoot === undefined ? [] : [{ id: 'skill-office', config: { assetRoot } }],
|
||||
...node === undefined && cli === undefined && assetRoot === undefined ? [] : [{
|
||||
id: 'office-commands', config: {
|
||||
...node === undefined && cli === undefined ? {} : {
|
||||
command: [node ?? process.execPath, cli ?? fileURLToPath(import.meta.resolve('@deepseek-ai/libreoffice-kit/cli'))],
|
||||
},
|
||||
...assetRoot === undefined ? {} : { assetRoot },
|
||||
},
|
||||
}],
|
||||
{ id: 'skill-office', config: { ...assetRoot === undefined ? {} : { assetRoot }, ...node === undefined ? {} : { node }, ...cli === undefined ? {} : { cli } } },
|
||||
]))
|
||||
// A private POSIX tool directory also excludes /usr/bin/node on Linux.
|
||||
const path = join(root, 'bin')
|
||||
@@ -113,7 +104,7 @@ it.skipIf(!process.env.DEEPSEEK_API_KEY || process.platform === 'win32')(`agent
|
||||
if (typeof call.arguments !== 'string') throw new Error('Shell tool call did not contain serialized arguments')
|
||||
return (JSON.parse(call.arguments) as { command: string }).command
|
||||
}).join('\n')
|
||||
for (const operation of ['capabilities', 'convert']) expect(commandText, diagnostic).toMatch(new RegExp(`\\bdsoffice["']?\\s+${operation}\\b`, 'u'))
|
||||
for (const operation of ['capabilities', 'convert']) expect(commandText, diagnostic).toMatch(new RegExp(`\\s${operation}\\b`, 'u'))
|
||||
expect(existsSync(decoyMarker), 'the agent must not invoke system Office when the bundled CLI is supplied').toBe(false)
|
||||
const capabilities = JSON.parse(await readFile(join(root, 'capabilities.json'), 'utf8')) as { runtime: { version: string; cliPath: string } }
|
||||
expect(capabilities.runtime.version).toBe('0.1.5')
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
"devDependencies": {
|
||||
"@deepseek-ai/cordis-plugin-loader": "workspace:~",
|
||||
"@deepseek-ai/cordis-plugin-include": "workspace:~",
|
||||
"@deepseek-ai/dsh-skill": "workspace:*",
|
||||
"@deepseek-ai/dsh-shell-env": "workspace:*"
|
||||
"@deepseek-ai/dsh-skill": "workspace:*"
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,6 @@ import { fileURLToPath } from 'node:url'
|
||||
import { runtimeArchivePath } from './office-engine.ts'
|
||||
import type { Context } from '@deepseek-ai/cordis'
|
||||
import * as officeSkills from '@deepseek-ai/dsh-skill-office'
|
||||
import * as officeCommands from '@deepseek-ai/dsh-skill-office/commands'
|
||||
import * as workspaceDependencies from '@deepseek-ai/dsh-tool-workspace-dependencies'
|
||||
|
||||
/** Loader identity for the application-owned Office composition. */
|
||||
@@ -33,10 +32,7 @@ export async function apply(ctx: Context, config: Config): Promise<void> {
|
||||
const packageRoot = dirname(archive === undefined ? manifest : join(`${archive}.unpacked`, relative(archive, manifest)))
|
||||
await ctx.plugin(officeSkills, {
|
||||
assetRoot: join(dirname(config.source), 'office-skills'),
|
||||
})
|
||||
await ctx.plugin(officeCommands, {
|
||||
assetRoot: join(dirname(config.source), 'office-skills'),
|
||||
command: [join(config.source, 'dependencies', 'node', 'bin', process.platform === 'win32' ? 'node.exe' : 'node'), join(packageRoot, 'lib', 'cli.js')],
|
||||
checkCommand: [join(config.source, 'dependencies', 'python', process.platform === 'win32' ? 'python.exe' : 'bin/python3'), join(dirname(config.source), 'office-skills', 'scripts', 'check_office.py')],
|
||||
node: join(config.source, 'dependencies', 'node', 'bin', process.platform === 'win32' ? 'node.exe' : 'node'),
|
||||
cli: join(packageRoot, 'lib', 'cli.js'),
|
||||
})
|
||||
}
|
||||
@@ -8,9 +8,7 @@ import Include from '@deepseek-ai/cordis-plugin-include'
|
||||
import AgentRegistry from '@deepseek-ai/dsh-agent'
|
||||
import SystemPrompt from '@deepseek-ai/dsh-system-prompt'
|
||||
import SkillRegistry from '@deepseek-ai/dsh-skill'
|
||||
import ToolRuntime, { type ToolExecution } from '@deepseek-ai/dsh-tools'
|
||||
import { ToolCallId } from '@deepseek-ai/dsh-llm'
|
||||
import * as ShellEnv from '@deepseek-ai/dsh-shell-env'
|
||||
import ToolRuntime from '@deepseek-ai/dsh-tools'
|
||||
import { expect, it, vi } from 'vitest'
|
||||
import * as desktopOffice from '../src/office.ts'
|
||||
|
||||
@@ -18,8 +16,7 @@ it('loads Desktop Office CLI paths and removes them on disposal', async () => {
|
||||
const root = await mkdtemp(join(tmpdir(), 'desktop-office-'))
|
||||
vi.stubEnv('DSH_HOME', root)
|
||||
const ctx = new Context()
|
||||
const execution: ToolExecution = { signal: new AbortController().signal, token: Symbol('office') as ToolExecution['token'],
|
||||
callId: ToolCallId('office'), rootCallId: ToolCallId('office'), name: 'bash', arguments: {} }
|
||||
|
||||
try {
|
||||
const assets = join(root, 'runtime', 'office-skills')
|
||||
await cp(new URL('../../../packages/skill/skill-office/assets/', import.meta.url), assets, { recursive: true })
|
||||
@@ -33,7 +30,7 @@ it('loads Desktop Office CLI paths and removes them on disposal', async () => {
|
||||
expect(ctx.loader.unwrapExports(desktopOffice)).toBe(desktopOffice)
|
||||
const modules = new Map<string, unknown>([
|
||||
['agents', AgentRegistry], ['systemPrompt', SystemPrompt], ['tools', ToolRuntime],
|
||||
['skills', SkillRegistry], ['shellEnv', ShellEnv], ['office', desktopOffice],
|
||||
['skills', SkillRegistry], ['office', desktopOffice],
|
||||
])
|
||||
ctx.loader.internal = {
|
||||
version: 'v2',
|
||||
@@ -44,7 +41,7 @@ it('loads Desktop Office CLI paths and removes them on disposal', async () => {
|
||||
} as unknown as NonNullable<typeof ctx.loader.internal>
|
||||
const config = join(root, 'cordis.yml')
|
||||
await writeFile(config, [
|
||||
'- name: agents', '- name: systemPrompt', '- name: tools', '- name: skills', '- name: shellEnv', '- name: office',
|
||||
'- name: agents', '- name: systemPrompt', '- name: tools', '- name: skills', '- name: office',
|
||||
' config:', ` source: ${JSON.stringify(join(root, 'runtime', 'primary-runtime'))}`,
|
||||
` root: ${JSON.stringify(join(root, 'installed'))}`,
|
||||
` runtimeDir: ${JSON.stringify(join(root, 'dsh'))}`, '',
|
||||
@@ -56,14 +53,12 @@ it('loads Desktop Office CLI paths and removes them on disposal', async () => {
|
||||
expect((await ctx.skills.get('office-pptx'))?.resourceBase).toEqual({ kind: 'directory', path: join(assets, 'office-pptx') })
|
||||
expect((await ctx.skills.get('office-pptx'))?.content).toContain('office-render')
|
||||
expect((await ctx.skills.get('office-pptx'))?.content).not.toContain(nodeDirectory)
|
||||
expect(ctx.shellEnv.collect(execution).PATH).toContain(join(root, 'commands'))
|
||||
expect(ctx.tools.schemas().map(tool => tool.name)).toEqual(['load_workspace_dependencies'])
|
||||
const entry = [...ctx.loader.entries()].find(entry => entry.options.name === 'office')
|
||||
expect(entry).toBeDefined()
|
||||
await entry?.fiber?.dispose()
|
||||
expect(await ctx.skills.list()).toEqual([])
|
||||
expect(ctx.tools.schemas()).toEqual([])
|
||||
expect(ctx.shellEnv.collect(execution)).not.toHaveProperty('PATH')
|
||||
} finally {
|
||||
try { await ctx.fiber.dispose() }
|
||||
finally {
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
en: 069fdfd72d2ea26a
|
||||
zh: 76ae549d43c99bb4
|
||||
/deepseek-harness-desktop/key-technical-decisions/bundled-workspace-dependencies:
|
||||
en: 31051ec14e651ce0
|
||||
zh: 698a441dd3de95b0
|
||||
en: cc2d4a2d5aecfaa0
|
||||
zh: 2a1d612560f6d95d
|
||||
/deepseek-harness-desktop/bundled-command-runtime:
|
||||
en: 09f0b75af9f0ed14
|
||||
zh: 60bbc2e67d5e87a8
|
||||
@@ -51,8 +51,8 @@
|
||||
en: 5f05072ec82cc62d
|
||||
zh: a3d63b58d1ef2db7
|
||||
/deepseek-harness-desktop/package/runtime-file-selection:
|
||||
en: 26cec76343af3d33
|
||||
zh: 93a39b6dd4a79b38
|
||||
en: 8b4cca1467f0bea6
|
||||
zh: fa3487fc56a53fc4
|
||||
/deepseek-harness-desktop/package/upload-updates:
|
||||
en: f48baa680e841b0d
|
||||
zh: 25ded1aeaac6dad1
|
||||
|
||||
@@ -64,7 +64,7 @@ Signed Windows packaging scans the primary runtime and application production de
|
||||
|
||||
Desktop carries independent Python, Node.js and pnpm distributions. Python includes numpy, pandas, python-docx, python-pptx, openpyxl, Pillow, lxml and XlsxWriter with their complete dependencies. The `load_workspace_dependencies` tool installs this payload offline on first use under `$DSH_HOME/dsh-runtimes/dsh-primary-runtime` (normally `~/.dsh/dsh-runtimes/dsh-primary-runtime`) and returns absolute interpreter, pnpm script and library paths plus `pythonDistributions`, the bundled distribution names and versions. The version report excludes user-installed additions. Office tasks prefer these libraries unless user or workspace instructions select another environment. Execute the pnpm script with the returned Node executable. The returned Node library directory is reserved for bundled libraries, not pnpm's global installation directory.
|
||||
|
||||
Desktop exposes the compact `office` router and named authoring/operation subskills. Authoring uses bundled Python libraries and the shared structural checker; operation skills invoke the stable `dsoffice` command. Skills live in `runtime/office-skills` outside ASAR so Python can read resources. See the [Office skill package](../../packages/skill/skill-office/README.md) for progressive loading and limitations.
|
||||
Desktop exposes the compact `office` router and named authoring/operation subskills. Authoring uses bundled Python libraries and the shared structural checker; operation skills invoke the configured Node and CLI paths. Skills live in `runtime/office-skills` outside ASAR so Python can read resources. See the [Office skill package](../../packages/skill/skill-office/README.md) for progressive loading and limitations.
|
||||
|
||||
The payload follows the Desktop release. `runtime.json` records the Desktop version, target, top-level interpreter/package-manager versions and the Python distribution map, and a digest of the selected target’s locked payload inputs and assembly format. Distribution names use PEP 503 normalization; duplicate normalized names reject the manifest. Legacy `components` manifests remain readable through normalization, with their existing library-version consistency checks. Matching installations are reused; a dependency or archive change replaces the directory after a complete staged copy even when the Desktop version stays unchanged. Older manifests without a digest are replaced on their next installation. User-added Python packages remain only while the payload identity matches. A failed directory replacement retains the previous installation; Windows may refuse replacement while an interpreter is still running.
|
||||
|
||||
@@ -280,7 +280,7 @@ The [Electron shell file list](scripts/electron-builder-config.mjs) excludes rec
|
||||
|
||||
The [Office conversion provider](../../packages/document/office-to-pdf/README.md) carries the target’s declared native engine, or WASM when the kit declares no matching native target. Preparation rejects a missing target engine before packaging. The complete Office dependencies, including CLI, JavaScript libraries, and the selected engine’s executables, data, licenses, and notices, are unpacked under `resources/app.asar.unpacked/dsh/node_modules/`. The Desktop Host resolves engine manifests to these physical directories and supplies the Office command provider with absolute standalone Node and unpacked CLI paths. Node lives in `resources/runtime/primary-runtime/dependencies/node/bin/`; the CLI is the unpacked `@deepseek-ai/libreoffice-kit/lib/cli.js`. On macOS, the native helper receives the JIT entitlement required by [LibreOffice’s UNO bridge](https://github.com/LibreOffice/core/blob/master/sysui/desktop/macosx/hardened_runtime.xcent.in).
|
||||
|
||||
The packaged application runs compiled JavaScript and pre-generated Typert metadata; it does not compile TypeScript plugins. Source-level debugger navigation and editor declarations remain available in development packages. [Copy-policy tests](tests/runtime-file-policy.spec.ts) cover exclusions and retained assets; The [payload smoke](tests/fixtures/runtime-payload-smoke.mjs) runs under Electron RunAsNode before the Host smoke and final inventory verification. The payload smoke resolves the search tool’s ripgrep executable and verifies text search and file enumeration. Signed Windows builds run these checks after dependency signing; other builds run them during `prepare:dsh`. The [Host smoke](scripts/smoke-runtime.ts) creates DOCX, XLSX, and PPTX inputs with bundled Python, converts each through the real Office provider, and checks PDF output. Every assembled application, including directory and unsigned builds, repeats the payload and Host checks against ASAR. Archive integrity checks compare the complete archived descriptor with preparation, file bytes and membership in both archive and unpacked trees, recorded executable flags for archived files, and physical permissions for unpacked files. The Host smoke also runs `dsoffice` capabilities and DOCX conversion through the registered shell environment with an empty caller PATH. Conversion failures stop packaging before a release record is written; macOS DMG/ZIP builds run these checks before notarization.
|
||||
The packaged application runs compiled JavaScript and pre-generated Typert metadata; it does not compile TypeScript plugins. Source-level debugger navigation and editor declarations remain available in development packages. [Copy-policy tests](tests/runtime-file-policy.spec.ts) cover exclusions and retained assets; The [payload smoke](tests/fixtures/runtime-payload-smoke.mjs) runs under Electron RunAsNode before the Host smoke and final inventory verification. The payload smoke resolves the search tool’s ripgrep executable and verifies text search and file enumeration. Signed Windows builds run these checks after dependency signing; other builds run them during `prepare:dsh`. The [Host smoke](scripts/smoke-runtime.ts) creates DOCX, XLSX, and PPTX inputs with bundled Python, converts each through the real Office provider, and checks PDF output. Every assembled application, including directory and unsigned builds, repeats the payload and Host checks against ASAR. Archive integrity checks compare the complete archived descriptor with preparation, file bytes and membership in both archive and unpacked trees, recorded executable flags for archived files, and physical permissions for unpacked files. The Host smoke also runs CLI capabilities and DOCX conversion using paths supplied by the operation skill with an empty caller PATH. Conversion failures stop packaging before a release record is written; macOS DMG/ZIP builds run these checks before notarization.
|
||||
|
||||
Windows release qualification also runs [directory and replacement checks](scripts/smoke-windows.ps1) manually after the Desktop build. Set `$Makensis`, `$SevenZip`, and `$PluginDir` to the pinned builder’s NSIS compiler, 7-Zip executable, and x86-unicode NSIS plugin directory; pass the prepared `window-frame.dll` as `-FrameLibrary` to exercise the native extraction path and its failure report as well. From the repository root, run the command below. It verifies directory replacement and rollback, and both locked-file replacement modes; it is not part of the unit-test lane.
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ Windows 签名打包按 PE 文件内容扫描第一方运行时和应用生产
|
||||
|
||||
Desktop 携带独立的 Python、Node.js 和 pnpm 分发包。Python 包含 numpy、pandas、python-docx、python-pptx、openpyxl、Pillow、lxml、XlsxWriter 及其完整依赖。`load_workspace_dependencies` 工具首次使用时,将该产物离线安装到 `$DSH_HOME/dsh-runtimes/dsh-primary-runtime`(通常为 `~/.dsh/dsh-runtimes/dsh-primary-runtime`),并返回解释器、pnpm 脚本和库目录的绝对路径,以及记录内置分发包名称与版本的 `pythonDistributions`。版本报告不包含用户自行安装的包。Office 任务默认使用这些库,用户或工作区指令指定其他环境时遵循其要求。pnpm 脚本通过返回的 Node 可执行文件运行。返回的 Node 库目录为随包交付的库预留,不是 pnpm 的全局安装目录。
|
||||
|
||||
Desktop 展示精简的 `office` 路由及可具名调用的创作/操作子技能。创作使用内置 Python 库和共享结构检查器;操作技能调用稳定的 `dsoffice` 命令。技能位于 ASAR 外的 `runtime/office-skills`,便于 Python 读取资源。渐进加载与限制见 [Office 技能包](../../packages/skill/skill-office/README.zh.md)。
|
||||
Desktop 展示精简的 `office` 路由及可具名调用的创作/操作子技能。创作使用内置 Python 库和共享结构检查器;操作技能调用配置的 Node 和 CLI 路径。技能位于 ASAR 外的 `runtime/office-skills`,便于 Python 读取资源。渐进加载与限制见 [Office 技能包](../../packages/skill/skill-office/README.zh.md)。
|
||||
|
||||
该产物随 Desktop 版本发布。`runtime.json` 记录 Desktop 版本、目标平台、顶层解释器和包管理器版本及 Python 分发包版本表,以及所选目标的锁定产物输入与组装格式的摘要。分发包名称按 PEP 503 归一化;名称归一化后重复时,清单会被拒绝。旧 `components` 清单通过归一化继续可读,并保留其原有库版本一致性校验。匹配的安装会被复用;依赖或压缩包变化后,即使 Desktop 版本不变,也会在完整暂存副本完成后替换目录。不含摘要的旧清单会在下次安装时被替换。用户自行添加的 Python 包仅在产物身份一致时保留。目录替换失败时保留之前的安装;解释器仍在运行时,Windows 可能拒绝替换。
|
||||
|
||||
@@ -282,7 +282,7 @@ Desktop 在本地打包工作区包,并通过目标捆绑的 Node 和 pnpm 安
|
||||
|
||||
[Office 转换提供方](../../packages/document/office-to-pdf/README.zh.md)携带目标已声明的原生引擎;kit 未声明匹配原生目标时携带 WASM 引擎。准备阶段在打包前拒绝缺少目标引擎的情况。完整 Office 依赖(CLI、JavaScript 库和选定引擎的可执行文件、数据、许可证及 notices)解包到 `resources/app.asar.unpacked/dsh/node_modules/` 下。Desktop Host 将引擎清单解析到这些物理目录,并向 Office 命令提供方提供独立 Node 和解包后 CLI 的绝对路径。Node 位于 `resources/runtime/primary-runtime/dependencies/node/bin/`;CLI 位于解包后的 `@deepseek-ai/libreoffice-kit/lib/cli.js`。macOS 上的原生辅助程序获得 [LibreOffice UNO 桥](https://github.com/LibreOffice/core/blob/master/sysui/desktop/macosx/hardened_runtime.xcent.in)所需的 JIT entitlement。
|
||||
|
||||
打包应用运行编译后的 JavaScript 和预生成的 Typert 元数据,不编译 TypeScript 插件。源码级调试导航和编辑器声明仍可从开发包中获取。[复制规则测试](tests/runtime-file-policy.spec.ts)覆盖排除项和保留资源;[产物 smoke](tests/fixtures/runtime-payload-smoke.mjs) 在 Host smoke 和最终清单验证之前,使用 Electron RunAsNode 执行。产物 smoke 解析搜索工具使用的 ripgrep 可执行文件,并验证文本搜索和文件枚举。Windows 签名构建在依赖签名后运行这些检查;其他构建在 `prepare:dsh` 中运行。[Host smoke](scripts/smoke-runtime.ts) 使用捆绑的 Python 创建 DOCX、XLSX 和 PPTX 输入,通过真实 Office 提供方逐一转换并检查 PDF 输出。每个组装后的应用(包括目录包和未签名构建)都会针对 ASAR 重复产物和 Host 检查。归档完整性检查将归档内完整描述符与准备结果比对,并核对归档和解包目录中的文件内容与清单、归档内文件记录的执行标志,以及解包文件的物理权限。Host smoke 还在调用方 PATH 为空时,通过已注册的 shell 环境运行 `dsoffice` 的 capabilities 和 DOCX 转换。转换失败会在写入发布记录前终止打包;macOS DMG/ZIP 构建在公证前执行这些检查。
|
||||
打包应用运行编译后的 JavaScript 和预生成的 Typert 元数据,不编译 TypeScript 插件。源码级调试导航和编辑器声明仍可从开发包中获取。[复制规则测试](tests/runtime-file-policy.spec.ts)覆盖排除项和保留资源;[产物 smoke](tests/fixtures/runtime-payload-smoke.mjs) 在 Host smoke 和最终清单验证之前,使用 Electron RunAsNode 执行。产物 smoke 解析搜索工具使用的 ripgrep 可执行文件,并验证文本搜索和文件枚举。Windows 签名构建在依赖签名后运行这些检查;其他构建在 `prepare:dsh` 中运行。[Host smoke](scripts/smoke-runtime.ts) 使用捆绑的 Python 创建 DOCX、XLSX 和 PPTX 输入,通过真实 Office 提供方逐一转换并检查 PDF 输出。每个组装后的应用(包括目录包和未签名构建)都会针对 ASAR 重复产物和 Host 检查。归档完整性检查将归档内完整描述符与准备结果比对,并核对归档和解包目录中的文件内容与清单、归档内文件记录的执行标志,以及解包文件的物理权限。Host smoke 还使用操作技能提供的路径执行 CLI 能力查询和 DOCX 转换,并清空调用方 PATH。转换失败会在写入发布记录前终止打包;macOS DMG/ZIP 构建在公证前执行这些检查。
|
||||
|
||||
Windows 发布验收还需在 Desktop 构建后手动运行[目录和替换检查](scripts/smoke-windows.ps1)。将 `$Makensis`、`$SevenZip` 和 `$PluginDir` 分别设为锁定版本构建器的 NSIS 编译器、7-Zip 可执行文件和 x86-unicode NSIS 插件目录;通过 `-FrameLibrary` 传入已准备好的 `window-frame.dll`,即可同时覆盖原生解压路径及其失败报告。从仓库根目录运行以下命令。它验证 目录替换与回滚和两种文件占用替换方式;不属于单元测试通道。
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/** Boot the materialized target runtime without access to a user's Harness profile. */
|
||||
|
||||
import { appendFileSync, cpSync, existsSync, mkdirSync, mkdtempSync, readFileSync, symlinkSync, writeFileSync } from 'node:fs'
|
||||
import { appendFileSync, cpSync, existsSync, mkdirSync, mkdtempSync, readFileSync, writeFileSync } from 'node:fs'
|
||||
import { rm } from 'node:fs/promises'
|
||||
import { tmpdir } from 'node:os'
|
||||
import { join } from 'node:path'
|
||||
@@ -40,7 +40,6 @@ export async function smokeDesktopRuntime(
|
||||
let timer: ReturnType<typeof setTimeout> | undefined
|
||||
try {
|
||||
writeFileSync(join(home, 'npmrc'), '')
|
||||
if (process.platform !== 'win32') symlinkSync('/bin/bash', join(home, 'bash'))
|
||||
createPluginProfile(profile)
|
||||
const pluginName = 'desktop-runtime-smoke-plugin'
|
||||
const plugin = join(home, pluginName)
|
||||
@@ -86,7 +85,8 @@ export function apply(ctx) {
|
||||
}))
|
||||
writeFileSync(join(plugin, 'index.js'), `
|
||||
import { Context } from '@deepseek-ai/cordis'
|
||||
import { inspect } from 'node:util'
|
||||
import { inspect, promisify } from 'node:util'
|
||||
import { execFile } from 'node:child_process'
|
||||
import { readFile } from 'node:fs/promises'
|
||||
export function apply(ctx) {
|
||||
if (!(ctx instanceof Context)) throw new Error('desktop runtime: external plugin loaded another Cordis instance')
|
||||
@@ -105,26 +105,14 @@ export function apply(ctx) {
|
||||
async handler(_request, response) {
|
||||
try {
|
||||
const skill = await ctx.skills.get('office-export-pdf')
|
||||
if (!skill?.content.includes('dsoffice convert')) throw new Error('Office skill did not supply the direct command')
|
||||
const managed = ctx.shellEnv.collect({})
|
||||
const delimiter = process.platform === 'win32' ? ';' : ':'
|
||||
const dshEnv = { ...managed, PATH: [managed.PATH.split(delimiter)[0], ${JSON.stringify(home)}].join(delimiter) }
|
||||
const json = skill?.content.match(/\\n(\\{\\n[\\s\\S]+)$/u)?.[1]
|
||||
if (json === undefined) throw new Error('Office skill did not supply CLI paths')
|
||||
const { libreofficeKit: { node, cli } } = JSON.parse(json)
|
||||
const options = { cwd: ${JSON.stringify(home)}, env: { ...process.env, PATH: '' }, timeout: 120_000 }
|
||||
const capabilities = await promisify(execFile)(node, [cli, 'capabilities'], options)
|
||||
const output = ${JSON.stringify(join(home, 'cli.pdf'))}
|
||||
async function run(command) {
|
||||
const execution = await ctx.shell.execute(ctx.shell.resolve({ command,
|
||||
workdir: ${JSON.stringify(home)}, timeoutMs: 120_000, dshEnv,
|
||||
sandboxPolicy: { mode: 'workspace-write', workspaceRoot: ${JSON.stringify(home)} },
|
||||
env: { PATH: '', OFFICE_SMOKE_INPUT: ${JSON.stringify(join(home, 'input.docx'))}, OFFICE_SMOKE_OUTPUT: output },
|
||||
}))
|
||||
const result = await execution.result()
|
||||
if (result.exitCode !== 0 || result.timedOut || result.aborted) throw new Error(JSON.stringify(result))
|
||||
return result.stdout.text
|
||||
}
|
||||
const capabilities = await run('dsoffice capabilities')
|
||||
await run(process.platform === 'win32'
|
||||
? 'dsoffice convert --input "$env:OFFICE_SMOKE_INPUT" --output "$env:OFFICE_SMOKE_OUTPUT"'
|
||||
: 'dsoffice convert --input "$OFFICE_SMOKE_INPUT" --output "$OFFICE_SMOKE_OUTPUT"')
|
||||
response.end(JSON.stringify({ capabilities: JSON.parse(capabilities), pdf: (await readFile(output)).toString('base64') }))
|
||||
await promisify(execFile)(node, [cli, 'convert', '--input', ${JSON.stringify(join(home, 'input.docx'))}, '--output', output], options)
|
||||
response.end(JSON.stringify({ capabilities: JSON.parse(capabilities.stdout), pdf: (await readFile(output)).toString('base64') }))
|
||||
} catch (error) {
|
||||
response.statusCode = 500
|
||||
response.end(inspect(error, { depth: 5 }))
|
||||
@@ -147,7 +135,7 @@ export function apply(ctx) {
|
||||
}
|
||||
}
|
||||
`)
|
||||
writeFileSync(join(plugin, 'bundle.yml'), '- insert:\n - id: desktop-runtime-smoke-plugin\n name: desktop-runtime-smoke-plugin\n inject: [webServer, officeToPdf, skills, shellEnv, shell, pluginManager]\n')
|
||||
writeFileSync(join(plugin, 'bundle.yml'), '- insert:\n - id: desktop-runtime-smoke-plugin\n name: desktop-runtime-smoke-plugin\n inject: [webServer, officeToPdf, skills, pluginManager]\n')
|
||||
cpSync(plugin, join(profile, 'node_modules', pluginName), { recursive: true })
|
||||
const manifest = JSON.parse(readFileSync(join(profile, 'package.json'), 'utf8')) as {
|
||||
dependencies?: Record<string, string>
|
||||
|
||||
@@ -107,8 +107,6 @@ describe('web e2e: lifecycle & chrome (workspace flow / reload / dark mode)', ()
|
||||
await writeComposerDraft(page, input, '/cpt')
|
||||
await expect.poll(() => menu.getByRole('option').allTextContents()).toEqual([
|
||||
'CompactCompact older conversation history',
|
||||
'office-pptxCreate, read, edit, and validate PowerPoint presentations (.pptx).',
|
||||
'office-export-pdfConvert an Office document to a requested PDF with LibreOffice Kit.',
|
||||
])
|
||||
const fuzzySnapshot = await captureStableAria(page, '[role="listbox"]', scaffold.workspaceCwd)
|
||||
await compareOrRefreshGolden(FUZZY_COMMAND_MENU_EXPECTED, fuzzySnapshot, MODE)
|
||||
|
||||
@@ -2983,7 +2983,7 @@ export interface Config extends SessionTitleLlmConfig {
|
||||
|
||||
## `@deepseek-ai/dsh-shell-env`
|
||||
|
||||
- `source`: [`packages/shell/shell-env/src/index.ts:31`](../packages/shell/shell-env/src/index.ts)
|
||||
- `source`: [`packages/shell/shell-env/src/index.ts:30`](../packages/shell/shell-env/src/index.ts)
|
||||
|
||||
```ts config-catalog
|
||||
/** Plugin config (all optional — the built-in facts resolve without defaults). */
|
||||
@@ -3055,13 +3055,17 @@ export interface Config {
|
||||
## `@deepseek-ai/dsh-skill-office`
|
||||
|
||||
- `inject`: `skills`
|
||||
- `source`: [`packages/skill/skill-office/src/index.ts:15`](../packages/skill/skill-office/src/index.ts)
|
||||
- `source`: [`packages/skill/skill-office/src/index.ts:16`](../packages/skill/skill-office/src/index.ts)
|
||||
|
||||
```ts config-catalog
|
||||
/** Office skill resource location. */
|
||||
export interface Config {
|
||||
/** Absolute assets directory containing skill folders and shared scripts; defaults to carrier resources or packaged assets. */
|
||||
/** Absolute assets directory containing skill folders and shared scripts; defaults to packaged assets. */
|
||||
assetRoot?: string
|
||||
/** Standalone Node executable; defaults to the current executable outside Electron and SEA. */
|
||||
node?: string
|
||||
/** Absolute LibreOffice Kit CLI entry; false explicitly disables CLI access. */
|
||||
cli?: string | false
|
||||
}
|
||||
```
|
||||
<!-- END GENERATED config-catalog:@deepseek-ai/dsh-skill-office -->
|
||||
|
||||
@@ -2985,7 +2985,7 @@ export interface Config extends SessionTitleLlmConfig {
|
||||
|
||||
## `@deepseek-ai/dsh-shell-env`
|
||||
|
||||
- `source`: [`packages/shell/shell-env/src/index.ts:31`](../packages/shell/shell-env/src/index.ts)
|
||||
- `source`: [`packages/shell/shell-env/src/index.ts:30`](../packages/shell/shell-env/src/index.ts)
|
||||
|
||||
```ts config-catalog
|
||||
/** Plugin config (all optional — the built-in facts resolve without defaults). */
|
||||
@@ -3057,13 +3057,17 @@ export interface Config {
|
||||
## `@deepseek-ai/dsh-skill-office`
|
||||
|
||||
- `inject`: `skills`
|
||||
- `source`: [`packages/skill/skill-office/src/index.ts:15`](../packages/skill/skill-office/src/index.ts)
|
||||
- `source`: [`packages/skill/skill-office/src/index.ts:16`](../packages/skill/skill-office/src/index.ts)
|
||||
|
||||
```ts config-catalog
|
||||
/** Office skill resource location. */
|
||||
export interface Config {
|
||||
/** Absolute assets directory containing skill folders and shared scripts; defaults to carrier resources or packaged assets. */
|
||||
/** Absolute assets directory containing skill folders and shared scripts; defaults to packaged assets. */
|
||||
assetRoot?: string
|
||||
/** Standalone Node executable; defaults to the current executable outside Electron and SEA. */
|
||||
node?: string
|
||||
/** Absolute LibreOffice Kit CLI entry; false explicitly disables CLI access. */
|
||||
cli?: string | false
|
||||
}
|
||||
```
|
||||
<!-- END GENERATED config-catalog:@deepseek-ai/dsh-skill-office -->
|
||||
|
||||
@@ -469,6 +469,7 @@ flowchart TD
|
||||
pkg_subprocess --> pkg_http_proxy
|
||||
pkg_remote_mock --> pkg_typert_protocol
|
||||
pkg_typert_loader --> pkg_typert_registry
|
||||
pkg_skill_office --> pkg_skill
|
||||
pkg_web_fetch_http --> pkg_http_proxy
|
||||
pkg_web_fetch_http --> pkg_timeout
|
||||
pkg_web_fetch_http --> pkg_web
|
||||
@@ -1029,9 +1030,6 @@ flowchart TD
|
||||
pkg_token_meter --> pkg_llm_retry
|
||||
pkg_token_meter --> pkg_session
|
||||
pkg_token_meter --> pkg_session_projection
|
||||
pkg_skill_office --> pkg_home_paths
|
||||
pkg_skill_office --> pkg_shell_env
|
||||
pkg_skill_office --> pkg_skill
|
||||
pkg_session_query --> pkg_brand
|
||||
pkg_session_query --> pkg_llm
|
||||
pkg_session_query --> pkg_session
|
||||
@@ -1576,6 +1574,7 @@ flowchart TD
|
||||
| [`subprocess`](../packages/subprocess/subprocess) | `subprocess` | [`http-proxy`](../packages/util/http-proxy) |
|
||||
| [`remote-mock`](../packages/test-support/remote-mock) | `test-support` | [`typert-protocol`](../packages/typert/protocol) |
|
||||
| [`typert-loader`](../packages/typert/loader) | `typert` | [`typert-registry`](../packages/typert/registry) |
|
||||
| [`skill-office`](../packages/skill/skill-office) | `skill` | [`skill`](../packages/skill/skill) |
|
||||
| [`web-fetch-http`](../packages/web/web-fetch-http) | `web` | [`http-proxy`](../packages/util/http-proxy), [`timeout`](../packages/util/timeout), [`web`](../packages/web/web) |
|
||||
| [`web-search-exa`](../packages/web/web-search-exa) | `web` | [`launch-environment`](../packages/util/launch-environment), [`web`](../packages/web/web) |
|
||||
| [`web-search-perplexity`](../packages/web/web-search-perplexity) | `web` | [`launch-environment`](../packages/util/launch-environment), [`web`](../packages/web/web) |
|
||||
@@ -1713,7 +1712,6 @@ flowchart TD
|
||||
| [`tool-workflow`](../packages/workflow/tool-workflow) | `workflow` | [`agent`](../packages/core/agent), [`jobs`](../packages/jobs/jobs), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools), [`workflow`](../packages/workflow/workflow) |
|
||||
| [`plugin-package-inventory-deepseek`](../packages/llm/plugin-package-inventory-deepseek) | `llm` | [`agent`](../packages/core/agent), [`agent-preset-registry`](../packages/preset/agent-preset-registry), [`deepseek-llm-api-extensions`](../packages/llm/deepseek-llm-api-extensions), [`session`](../packages/core/session) |
|
||||
| [`token-meter`](../packages/llm/token-meter) | `llm` | [`compaction`](../packages/compaction/compaction), [`compaction-image-offload`](../packages/compaction/compaction-image-offload), [`llm`](../packages/llm/llm), [`llm-retry`](../packages/llm/llm-retry), [`session`](../packages/core/session), [`session-projection`](../packages/session/session-projection) |
|
||||
| [`skill-office`](../packages/skill/skill-office) | `skill` | [`home-paths`](../packages/util/home-paths), [`shell-env`](../packages/shell/shell-env), [`skill`](../packages/skill/skill) |
|
||||
| [`session-query`](../packages/session-query/session-query) | `session-query` | [`brand`](../packages/util/brand), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`session-projection`](../packages/session/session-projection), [`session-projection-cache`](../packages/session/session-projection-cache), [`session-title`](../packages/session/session-title), [`tool-todo`](../packages/todo/tool-todo) |
|
||||
| [`api-settings-controller`](../packages/api/settings-controller) | `api` | [`agent-preset-registry`](../packages/preset/agent-preset-registry), [`credentials`](../packages/credentials/credentials), [`native-command`](../packages/util/native-command), [`session`](../packages/core/session), [`settings`](../packages/settings/settings), [`typert-protocol`](../packages/typert/protocol) |
|
||||
| [`web-app`](../packages/bundle/web-app) | `bundle` | [`shell-env`](../packages/shell/shell-env), [`system-prompt`](../packages/core/system-prompt) |
|
||||
|
||||
@@ -471,6 +471,7 @@ flowchart TD
|
||||
pkg_subprocess --> pkg_http_proxy
|
||||
pkg_remote_mock --> pkg_typert_protocol
|
||||
pkg_typert_loader --> pkg_typert_registry
|
||||
pkg_skill_office --> pkg_skill
|
||||
pkg_web_fetch_http --> pkg_http_proxy
|
||||
pkg_web_fetch_http --> pkg_timeout
|
||||
pkg_web_fetch_http --> pkg_web
|
||||
@@ -1031,9 +1032,6 @@ flowchart TD
|
||||
pkg_token_meter --> pkg_llm_retry
|
||||
pkg_token_meter --> pkg_session
|
||||
pkg_token_meter --> pkg_session_projection
|
||||
pkg_skill_office --> pkg_home_paths
|
||||
pkg_skill_office --> pkg_shell_env
|
||||
pkg_skill_office --> pkg_skill
|
||||
pkg_session_query --> pkg_brand
|
||||
pkg_session_query --> pkg_llm
|
||||
pkg_session_query --> pkg_session
|
||||
@@ -1578,6 +1576,7 @@ flowchart TD
|
||||
| [`subprocess`](../packages/subprocess/subprocess) | `subprocess` | [`http-proxy`](../packages/util/http-proxy) |
|
||||
| [`remote-mock`](../packages/test-support/remote-mock) | `test-support` | [`typert-protocol`](../packages/typert/protocol) |
|
||||
| [`typert-loader`](../packages/typert/loader) | `typert` | [`typert-registry`](../packages/typert/registry) |
|
||||
| [`skill-office`](../packages/skill/skill-office) | `skill` | [`skill`](../packages/skill/skill) |
|
||||
| [`web-fetch-http`](../packages/web/web-fetch-http) | `web` | [`http-proxy`](../packages/util/http-proxy), [`timeout`](../packages/util/timeout), [`web`](../packages/web/web) |
|
||||
| [`web-search-exa`](../packages/web/web-search-exa) | `web` | [`launch-environment`](../packages/util/launch-environment), [`web`](../packages/web/web) |
|
||||
| [`web-search-perplexity`](../packages/web/web-search-perplexity) | `web` | [`launch-environment`](../packages/util/launch-environment), [`web`](../packages/web/web) |
|
||||
@@ -1715,7 +1714,6 @@ flowchart TD
|
||||
| [`tool-workflow`](../packages/workflow/tool-workflow) | `workflow` | [`agent`](../packages/core/agent), [`jobs`](../packages/jobs/jobs), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools), [`workflow`](../packages/workflow/workflow) |
|
||||
| [`plugin-package-inventory-deepseek`](../packages/llm/plugin-package-inventory-deepseek) | `llm` | [`agent`](../packages/core/agent), [`agent-preset-registry`](../packages/preset/agent-preset-registry), [`deepseek-llm-api-extensions`](../packages/llm/deepseek-llm-api-extensions), [`session`](../packages/core/session) |
|
||||
| [`token-meter`](../packages/llm/token-meter) | `llm` | [`compaction`](../packages/compaction/compaction), [`compaction-image-offload`](../packages/compaction/compaction-image-offload), [`llm`](../packages/llm/llm), [`llm-retry`](../packages/llm/llm-retry), [`session`](../packages/core/session), [`session-projection`](../packages/session/session-projection) |
|
||||
| [`skill-office`](../packages/skill/skill-office) | `skill` | [`home-paths`](../packages/util/home-paths), [`shell-env`](../packages/shell/shell-env), [`skill`](../packages/skill/skill) |
|
||||
| [`session-query`](../packages/session-query/session-query) | `session-query` | [`brand`](../packages/util/brand), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`session-projection`](../packages/session/session-projection), [`session-projection-cache`](../packages/session/session-projection-cache), [`session-title`](../packages/session/session-title), [`tool-todo`](../packages/todo/tool-todo) |
|
||||
| [`api-settings-controller`](../packages/api/settings-controller) | `api` | [`agent-preset-registry`](../packages/preset/agent-preset-registry), [`credentials`](../packages/credentials/credentials), [`native-command`](../packages/util/native-command), [`session`](../packages/core/session), [`settings`](../packages/settings/settings), [`typert-protocol`](../packages/typert/protocol) |
|
||||
| [`web-app`](../packages/bundle/web-app) | `bundle` | [`shell-env`](../packages/shell/shell-env), [`system-prompt`](../packages/core/system-prompt) |
|
||||
|
||||
@@ -20,8 +20,8 @@ type DshEnvironmentKey = `${typeof DSH_ENV_PREFIX}${string}`
|
||||
```
|
||||
|
||||
```ts type-equiv
|
||||
/** Trusted Harness variables and optional local command PATH for one child-process execution. */
|
||||
type DshEnvironment = Readonly<Record<DshEnvironmentKey, string> & { PATH?: string }>
|
||||
/** Trusted DeepSeek Harness variables for one child-process execution. */
|
||||
type DshEnvironment = Readonly<Record<DshEnvironmentKey, string>>
|
||||
```
|
||||
|
||||
```ts type-equiv
|
||||
|
||||
@@ -20,8 +20,8 @@ type DshEnvironmentKey = `${typeof DSH_ENV_PREFIX}${string}`
|
||||
```
|
||||
|
||||
```ts type-equiv
|
||||
/** Trusted Harness variables and optional local command PATH for one child-process execution. */
|
||||
type DshEnvironment = Readonly<Record<DshEnvironmentKey, string> & { PATH?: string }>
|
||||
/** Trusted DeepSeek Harness variables for one child-process execution. */
|
||||
type DshEnvironment = Readonly<Record<DshEnvironmentKey, string>>
|
||||
```
|
||||
|
||||
```ts type-equiv
|
||||
|
||||
@@ -32,7 +32,5 @@
|
||||
disabled: !!js "!(process.env.DSH_PRIMARY_RUNTIME ?? process.env.DSH_BUNDLED_PRIMARY_RUNTIME) && !process.env.DSH_BUNDLED_OFFICE_CLI"
|
||||
config:
|
||||
assetRoot: !!js "process.env.DSH_BUNDLED_OFFICE_SKILLS ?? process.getBuiltinModule('node:path').resolve(process.env.DSH_PRIMARY_RUNTIME ?? process.env.DSH_BUNDLED_PRIMARY_RUNTIME ?? '', '..', 'office-skills')"
|
||||
|
||||
- id: office-commands
|
||||
name: '@deepseek-ai/dsh-skill-office/commands'
|
||||
disabled: !!js "!(process.env.DSH_PRIMARY_RUNTIME ?? process.env.DSH_BUNDLED_PRIMARY_RUNTIME) && !process.env.DSH_BUNDLED_OFFICE_CLI"
|
||||
cli: !!js "process.env.DSH_BUNDLED_OFFICE_CLI === '' ? false : process.env.DSH_BUNDLED_OFFICE_CLI"
|
||||
node: !!js "process.env.DSH_BUNDLED_OFFICE_NODE ?? process.getBuiltinModule('node:path').resolve(process.env.DSH_PRIMARY_RUNTIME ?? process.env.DSH_BUNDLED_PRIMARY_RUNTIME ?? '', 'dependencies', 'node', 'bin', process.platform === 'win32' ? 'node.exe' : 'node')"
|
||||
@@ -4827,7 +4827,7 @@ export const TYPE_API: readonly TypeApiEntry[] = [
|
||||
},
|
||||
{
|
||||
name: 'BashEnvContributor',
|
||||
declaration: 'export interface BashEnvContributor {\n name: string;\n commandDirectories?: readonly string[];\n variables: Readonly<Record<DshEnvironmentKey, BashEnvVariable>>;\n resolve(execution: ToolExecution): Readonly<Partial<Record<DshEnvironmentKey, string>>>;\n}',
|
||||
declaration: 'export interface BashEnvContributor {\n name: string;\n variables: Readonly<Record<DshEnvironmentKey, BashEnvVariable>>;\n resolve(execution: ToolExecution): Readonly<Partial<Record<DshEnvironmentKey, string>>>;\n}',
|
||||
},
|
||||
{
|
||||
name: 'BashEnvVariable',
|
||||
@@ -5291,7 +5291,7 @@ export const TYPE_API: readonly TypeApiEntry[] = [
|
||||
},
|
||||
{
|
||||
name: 'DshEnvironment',
|
||||
declaration: 'export type DshEnvironment = Readonly<Record<DshEnvironmentKey, string> & {\n PATH?: string;\n}>;',
|
||||
declaration: 'export type DshEnvironment = Readonly<Record<DshEnvironmentKey, string>>;',
|
||||
},
|
||||
{
|
||||
name: 'DshEnvironmentKey',
|
||||
|
||||
@@ -24,8 +24,8 @@
|
||||
en: 47119e8b4e884a5d
|
||||
zh: f9dfb155f06c4b73
|
||||
/deepseek-ai-dsh-pwsh-local/use-this-package/running-commands:
|
||||
en: 6659d1bbc7af561d
|
||||
zh: 8ccb16ceb39d67f2
|
||||
en: d0efd217ca8ce07d
|
||||
zh: 76eda93aa7300f87
|
||||
/deepseek-ai-dsh-pwsh-local/use-this-package/background-processes:
|
||||
en: 3c580842cc8452af
|
||||
zh: 5a156670a7cacc2a
|
||||
@@ -36,14 +36,14 @@
|
||||
en: 05e2abe4a25886fd
|
||||
zh: 3f7f1326dc3c1d3f
|
||||
/deepseek-ai-dsh-pwsh-local/understand-the-implementation/design-concept:
|
||||
en: 09017c5641b0a5ec
|
||||
zh: 944ddfb922cf72f3
|
||||
en: d065be99a0cea908
|
||||
zh: 50eee843e3b6860c
|
||||
/deepseek-ai-dsh-pwsh-local/understand-the-implementation/source-map:
|
||||
en: aa160f9ec57ff627
|
||||
zh: 048d3292dddf1d8b
|
||||
/deepseek-ai-dsh-pwsh-local/understand-the-implementation/main-flow:
|
||||
en: d7ea7ad3e310aaeb
|
||||
zh: 8af73c715f5c56df
|
||||
en: 1cb78cfddb484576
|
||||
zh: 94e16b60c9cd458b
|
||||
/deepseek-ai-dsh-pwsh-local/understand-the-implementation/invariants-and-ownership:
|
||||
en: db6d1d14205d38ed
|
||||
zh: 148b3764daee54e8
|
||||
|
||||
@@ -59,8 +59,6 @@ The generated [configuration catalog](../../../docs/config-catalog.md#deepseek-a
|
||||
|
||||
Run a command by awaiting the execution's `result()` projection; a nonzero exit, a timeout, or a cancellation resolves descriptively, and only infrastructure failures reject. The command string rides as one argument to `-Command`: PowerShell parses the text itself and no intermediate shell exists, so there is no shell-quoting layer to escape and native Win32 paths pass through unchanged. Every command pins UTF-8 output first, so non-ASCII output is not garbled even on the Windows PowerShell 5.1 fallback. The environment is model-friendly: `NO_COLOR=1 PAGER=cat GIT_PAGER=cat` (no `TERM=dumb` — a POSIX concept), with explicit caller-provided entries still winning.
|
||||
|
||||
Each child process selects `ExecutionPolicy Bypass` so host-generated scripts can run without changing the user's persistent policy. Machine and user Group Policy still take precedence.
|
||||
|
||||
```text
|
||||
const execution = await ctx.shell.execute(ctx.shell.resolve({ command: 'Get-ChildItem' }))
|
||||
const result = await execution.result()
|
||||
@@ -88,7 +86,7 @@ This section explains the design of the executor and points at the code that rea
|
||||
|
||||
### Design concept
|
||||
|
||||
The executor is the PowerShell Service Provider for the `ctx.shell` seam built on the subprocess capability: it owns everything pwsh-shaped — executable resolution, command defaulting and caps, deadline fusion and cause classification, UTF-8 output pinning, the model-friendly terminal environment, and the background read merge — while managed-range mechanics (bounded spill-backed output, credential scrub, termination escalation, quiescence, and disposal) belong to the subprocess service. Every call spawns a fresh non-interactive `pwsh -Command` with `-NoLogo -NoProfile -NonInteractive -ExecutionPolicy Bypass`, so commands are deterministic and profile state never leaks between calls.
|
||||
The executor is the PowerShell Service Provider for the `ctx.shell` seam built on the subprocess capability: it owns everything pwsh-shaped — executable resolution, command defaulting and caps, deadline fusion and cause classification, UTF-8 output pinning, the model-friendly terminal environment, and the background read merge — while managed-range mechanics (bounded spill-backed output, credential scrub, termination escalation, quiescence, and disposal) belong to the subprocess service. Every call spawns a fresh non-interactive `pwsh -Command` with `-NoLogo -NoProfile -NonInteractive`, so commands are deterministic and profile state never leaks between calls.
|
||||
|
||||
### Source map
|
||||
|
||||
@@ -100,7 +98,7 @@ The executor is the PowerShell Service Provider for the `ctx.shell` seam built o
|
||||
|
||||
### Main flow
|
||||
|
||||
A call runs through three steps: `resolve()` fills `workdir`/`timeoutMs`/`stdoutMaxBytes` from config (capping the per-call `timeoutMs` override); the executor builds the pwsh argv — `pwsh -NoLogo -NoProfile -NonInteractive -ExecutionPolicy Bypass -Command <encoding preamble + command>` — fuses the config-clamped timeout with the caller's abort signal into one deadline, and spawns through `ctx.subprocess` with explicit byte caps and the `graceMs`; the settled outcome is classified and projected into a `ShellRunResult`. Windows reports forced termination as exit 1 without a signal, so signal-stamped facts are POSIX-only there; the timeout/abort classification is platform-independent.
|
||||
A call runs through three steps: `resolve()` fills `workdir`/`timeoutMs`/`stdoutMaxBytes` from config (capping the per-call `timeoutMs` override); the executor builds the pwsh argv — `pwsh -NoLogo -NoProfile -NonInteractive -Command <encoding preamble + command>` — fuses the config-clamped timeout with the caller's abort signal into one deadline, and spawns through `ctx.subprocess` with explicit byte caps and the `graceMs`; the settled outcome is classified and projected into a `ShellRunResult`. Windows reports forced termination as exit 1 without a signal, so signal-stamped facts are POSIX-only there; the timeout/abort classification is platform-independent.
|
||||
|
||||
The foreground deadline starts before argv preparation and retains the same signal and remaining budget through execution. Preparation timeout returns empty output, `timedOut: true`, and null `exitCode` and `signal`; caller cancellation before process publication still rejects. Late preparation success or failure cannot trigger a spawn.
|
||||
|
||||
|
||||
@@ -59,8 +59,6 @@ kind: "package-reference"
|
||||
|
||||
通过等待执行句柄的 `result()` 投影来运行命令;非零退出、超时或取消都会返回描述性结果,只有基础设施失败才会导致调用被拒绝。命令字符串作为单个参数传给 `-Command`:由 PowerShell 自己解析文本,不存在中间 shell,因此没有需要转义的 shell 引号层,原生 Win32 路径也原样通过。每条命令都先固定 UTF-8 输出,因此即使在 Windows PowerShell 5.1 兜底上,非 ASCII 输出也不会乱码。环境默认面向模型:`NO_COLOR=1 PAGER=cat GIT_PAGER=cat`(没有 `TERM=dumb`——那是 POSIX 概念),调用方显式提供的条目仍然优先。
|
||||
|
||||
每个子进程使用 `ExecutionPolicy Bypass`,使主机生成的脚本可以运行,而不修改用户的持久策略。计算机和用户组策略仍然优先。
|
||||
|
||||
```text
|
||||
const execution = await ctx.shell.execute(ctx.shell.resolve({ command: 'Get-ChildItem' }))
|
||||
const result = await execution.result()
|
||||
@@ -88,7 +86,7 @@ if (result.timedOut) console.log('timed out after', result.timeoutMs)
|
||||
|
||||
### 设计概念
|
||||
|
||||
本执行器是基于 subprocess 能力的 `ctx.shell` seam 的 PowerShell Service Provider:它负责所有 pwsh 层职责——可执行文件解析、命令默认化与上限、deadline 融合与原因分类、UTF-8 输出固定、面向模型的终端环境,以及后台读取合并——而 managed-range 机制(有界 spill 输出、凭据清除、终止升级、完全停稳与 dispose(资源释放))属于 subprocess 服务。每次调用都 spawn 全新的非交互 `pwsh -Command`,并带 `-NoLogo -NoProfile -NonInteractive -ExecutionPolicy Bypass`,因此命令是确定性的,profile 状态绝不会在调用之间泄漏。
|
||||
本执行器是基于 subprocess 能力的 `ctx.shell` seam 的 PowerShell Service Provider:它负责所有 pwsh 层职责——可执行文件解析、命令默认化与上限、deadline 融合与原因分类、UTF-8 输出固定、面向模型的终端环境,以及后台读取合并——而 managed-range 机制(有界 spill 输出、凭据清除、终止升级、完全停稳与 dispose(资源释放))属于 subprocess 服务。每次调用都 spawn 全新的非交互 `pwsh -Command`,并带 `-NoLogo -NoProfile -NonInteractive`,因此命令是确定性的,profile 状态绝不会在调用之间泄漏。
|
||||
|
||||
### 源码地图
|
||||
|
||||
@@ -100,7 +98,7 @@ if (result.timedOut) console.log('timed out after', result.timeoutMs)
|
||||
|
||||
### 主要流程
|
||||
|
||||
一次调用分三步:`resolve()` 从配置填充 `workdir`/`timeoutMs`/`stdoutMaxBytes`(并限制每次调用的 `timeoutMs` 覆盖值);执行器构建 pwsh argv——`pwsh -NoLogo -NoProfile -NonInteractive -ExecutionPolicy Bypass -Command <编码 preamble + 命令>`——把按配置钳位的超时与调用方的中止信号融合为一个 deadline,再以显式字节上限与 `graceMs` 通过 `ctx.subprocess` spawn;结算的结果被分类并投影为 `ShellRunResult`。Windows 把强制终止报告为退出码 1 且无信号,因此带信号标记的事实在那里仅限 POSIX;超时/取消分类则与平台无关。
|
||||
一次调用分三步:`resolve()` 从配置填充 `workdir`/`timeoutMs`/`stdoutMaxBytes`(并限制每次调用的 `timeoutMs` 覆盖值);执行器构建 pwsh argv——`pwsh -NoLogo -NoProfile -NonInteractive -Command <编码 preamble + 命令>`——把按配置钳位的超时与调用方的中止信号融合为一个 deadline,再以显式字节上限与 `graceMs` 通过 `ctx.subprocess` spawn;结算的结果被分类并投影为 `ShellRunResult`。Windows 把强制终止报告为退出码 1 且无信号,因此带信号标记的事实在那里仅限 POSIX;超时/取消分类则与平台无关。
|
||||
|
||||
前台 deadline 从 argv 准备开始,并在准备与执行之间保持同一信号和剩余预算。准备阶段超时返回空输出、`timedOut: true`,且 `exitCode` 和 `signal` 均为 `null`;调用方在发布进程前取消仍会拒绝调用。准备晚到的成功或失败不会触发 spawn。
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Local PowerShell Service Provider for the bash capability seam. Each command runs
|
||||
* as `pwsh -NoLogo -NoProfile -NonInteractive -ExecutionPolicy Bypass -Command <command>` in a managed
|
||||
* as `pwsh -NoLogo -NoProfile -NonInteractive -Command <command>` in a managed
|
||||
* process spawned through `ctx.subprocess`; the executor owns command
|
||||
* defaulting, deadlines and cause classification, the model-friendly terminal
|
||||
* environment, and the model-facing stdout/stderr merge for background reads.
|
||||
@@ -191,8 +191,7 @@ export class PwshLocalExecutor extends ShellExecutor {
|
||||
* `@deepseek-ai/dsh-pwsh-sandbox`).
|
||||
*/
|
||||
protected argv(spec: ShellExecSpec): string[] {
|
||||
return [this.pwshPath, '-NoLogo', '-NoProfile', '-NonInteractive', '-ExecutionPolicy', 'Bypass', '-Command',
|
||||
`${ENCODING_PREAMBLE}${spec.command}`]
|
||||
return [this.pwshPath, '-NoLogo', '-NoProfile', '-NonInteractive', '-Command', `${ENCODING_PREAMBLE}${spec.command}`]
|
||||
}
|
||||
|
||||
/** Map one resolved spec plus its argv onto a fully-specified subprocess spawn. */
|
||||
|
||||
@@ -237,10 +237,8 @@ describe('spawn construction (pure, every platform)', () => {
|
||||
await run(ctx.shell, ctx.shell.resolve({ command: 'Write-Output 你好' }))
|
||||
expect(subprocess.specs).toHaveLength(1)
|
||||
const { argv } = subprocess.specs[0]!
|
||||
expect(argv.slice(0, 7)).toEqual([
|
||||
expect.any(String), '-NoLogo', '-NoProfile', '-NonInteractive', '-ExecutionPolicy', 'Bypass', '-Command',
|
||||
])
|
||||
expect(argv[7]).toBe(`${ENCODING_PREAMBLE}Write-Output 你好`)
|
||||
expect(argv.slice(0, 5)).toEqual([expect.any(String), '-NoLogo', '-NoProfile', '-NonInteractive', '-Command'])
|
||||
expect(argv[5]).toBe(`${ENCODING_PREAMBLE}Write-Output 你好`)
|
||||
expect(ENCODING_PREAMBLE).toContain('[Console]::OutputEncoding')
|
||||
expect(ENCODING_PREAMBLE).toContain('$OutputEncoding')
|
||||
})
|
||||
|
||||
@@ -3,14 +3,14 @@
|
||||
# After editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write packages/shell/shell-env/README.md
|
||||
/:
|
||||
en: 03aa15ebe8f97a43
|
||||
zh: b606e28eb19c933e
|
||||
en: c54342d0151b089c
|
||||
zh: 9ad6284f24c5e3f6
|
||||
/deepseek-ai-dsh-shell-env:
|
||||
en: d26b77029fa722ab
|
||||
zh: 8e6bed763372b561
|
||||
/deepseek-ai-dsh-shell-env/summary:
|
||||
en: f27f8c4cdea7bcd4
|
||||
zh: 33cf3b28330bdf0f
|
||||
en: 021be213f32988e1
|
||||
zh: f3ce1ef82377b4f4
|
||||
/deepseek-ai-dsh-shell-env/table-of-contents:
|
||||
en: d152484eb41ac6b4
|
||||
zh: 09388d293f9be9cb
|
||||
@@ -19,16 +19,16 @@
|
||||
zh: 7753b97c91743901
|
||||
/deepseek-ai-dsh-shell-env/use-this-package/what-every-shell-call-receives:
|
||||
en: eae86664fefc6690
|
||||
zh: b8829aae034599c1
|
||||
zh: 05a4e5946c8d2b87
|
||||
/deepseek-ai-dsh-shell-env/use-this-package/adding-your-own-environment-facts:
|
||||
en: 8e3813746d322857
|
||||
zh: 91f10c71a21d8e80
|
||||
en: 21ef223626e35905
|
||||
zh: 5c468055099b0135
|
||||
/deepseek-ai-dsh-shell-env/use-this-package/choosing-the-harness-home:
|
||||
en: 0041438f2b7f7e4f
|
||||
zh: 93fa165b07adcdf4
|
||||
/deepseek-ai-dsh-shell-env/use-this-package/what-can-go-wrong:
|
||||
en: bf8db851cc8d373d
|
||||
zh: 27e046770564c60c
|
||||
en: 42c75945b581b7e6
|
||||
zh: 6b5c487cfa28b206
|
||||
/deepseek-ai-dsh-shell-env/understand-the-implementation:
|
||||
en: f782557ca8da3138
|
||||
zh: e8f0082b9692cacc
|
||||
@@ -39,20 +39,20 @@
|
||||
en: 72eba3bfadcfa581
|
||||
zh: dcd83e02a1910f27
|
||||
/deepseek-ai-dsh-shell-env/understand-the-implementation/collection:
|
||||
en: 24b540add25646f3
|
||||
zh: ba759ae3164cb1a3
|
||||
en: 0c2d7d5b2131630f
|
||||
zh: b44d4f0ddf89421b
|
||||
/deepseek-ai-dsh-shell-env/further-exploration:
|
||||
en: 6a4175df7b7341c7
|
||||
zh: 7885831274008502
|
||||
/deepseek-ai-dsh-shell-env/model-experience:
|
||||
en: 6e1e1b75c1fc4e94
|
||||
zh: a8cb0c273e040975
|
||||
en: 8acf3cd9aeef5f55
|
||||
zh: 69725e78f73c2f16
|
||||
/deepseek-ai-dsh-shell-env/model-experience/kv-cache-effect:
|
||||
en: e95e649f0410fa75
|
||||
zh: b3d64877420b4c0d
|
||||
/deepseek-ai-dsh-shell-env/known-limitations-and-deferred-work:
|
||||
en: 2a4da893f45fa8c4
|
||||
zh: a06bd59769c78e53
|
||||
en: be9888161315f026
|
||||
zh: 97d1d05c1c322596
|
||||
/deepseek-ai-dsh-shell-env/known-limitations-and-deferred-work/dev-note:
|
||||
en: e67f633dc6fe7773
|
||||
zh: 3bb0c20c93f16f98
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
description: "Configure per-call Harness shell variables and directories for deployment-supplied commands."
|
||||
description: "The managed DSH_* shell environment for users and maintainers choosing, configuring, or extending the environment every model shell call runs with."
|
||||
kind: "package-reference"
|
||||
---
|
||||
|
||||
@@ -9,7 +9,7 @@ English | [中文](README.zh.md)
|
||||
|
||||
## Summary
|
||||
|
||||
`dsh-shell-env` gives Bash and PowerShell tool calls current Harness home, session, and profile variables. Plugins can contribute declared `DSH_*` values and directories for deployment-supplied commands. Each call receives the current registrations without changing `process.env` or the user's shell configuration. Duplicate variable ownership and undeclared values fail loudly. Registrations follow plugin lifetimes; the shell tools retain their schemas and prompts.
|
||||
`dsh-shell-env` provides the trusted `DSH_*` environment that every model shell call — bash or pwsh — runs with: built-in facts such as `DSH_HOME`, `DSH_SHELL=1`, the agent's `DSH_SESSION_ID`, and the launched profile's `DSH_PROFILE` and `DSH_PROFILE_DIR`. Plugin authors can register their own facts with declared keys, collected per execution and disposed with their plugin; duplicate ownership or undeclared runtime keys fail loudly instead of silently overwriting. The registry changes nothing else the model sees — the shell tools own their own schemas and prompts. Choose it in any composition that mounts a model shell tool; configuration only picks the Harness home directory.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
@@ -52,8 +52,6 @@ export function apply(ctx: Context): void {
|
||||
|
||||
Contributors must declare every key they return; returning an undeclared or non-string value fails the call. Registration is disposed with the registering plugin, so hot-reloading a plugin removes its facts.
|
||||
|
||||
Contributors may also declare absolute `commandDirectories`. The registry prepends these directories to the local shell's `PATH` in contributor-name order, preserving each contributor's directory order and removing repeated directories. The inherited `PATH` follows them. With no command directories, it leaves `PATH` unchanged. Directory registration does not install commands or verify their contents; the contributing plugin owns those files and their lifetime. The [Office commands plugin](../../skill/skill-office/README.md) supplies `dsoffice` and `office-check` this way.
|
||||
|
||||
### Choosing the Harness home
|
||||
|
||||
The single config field picks the home directory exposed as `DSH_HOME`; the default resolution order is the `dshHome` config, then ambient `$DSH_HOME`, then `~/.dsh`.
|
||||
@@ -66,7 +64,7 @@ The generated [configuration catalog](../../../docs/config-catalog.md#deepseek-a
|
||||
|
||||
### What can go wrong
|
||||
|
||||
Two contributors declaring the same key, or a contributor claiming a reserved built-in (`DSH_HOME`, `DSH_SHELL`, `DSH_SESSION_ID`, `DSH_PROFILE`, `DSH_PROFILE_DIR`), fails plugin load loudly. A `DSH_*` key must be all-caps with underscores (for example `DSH_REGION`), and a missing description fails registration. Relative command directories also fail registration.
|
||||
Two contributors declaring the same key, or a contributor claiming a reserved built-in (`DSH_HOME`, `DSH_SHELL`, `DSH_SESSION_ID`, `DSH_PROFILE`, `DSH_PROFILE_DIR`), fails plugin load loudly. A `DSH_*` key must be all-caps with underscores (for example `DSH_REGION`), and a missing description fails registration.
|
||||
|
||||
-----
|
||||
|
||||
@@ -92,7 +90,7 @@ This section explains the design decisions behind the registry and points at the
|
||||
|
||||
### Collection
|
||||
|
||||
`collect(execution)` combines built-in facts, contributor values, and any command-directory `PATH` into a frozen snapshot passed through `ShellExecRequest.dshEnv`. This trusted snapshot takes precedence over ordinary caller environment entries. `list()` enumerates variable declarations without running resolvers; it does not include command directories or execution-dependent values.
|
||||
`collect(execution)` starts from the built-ins, adds the session id when the execution carries an agent, then merges each registered contributor's resolved values sorted by contributor name. The result is a frozen, key-sorted snapshot passed through `ShellExecRequest.dshEnv`. `list()` enumerates declarations without running resolvers, so it cannot reflect execution-dependent values.
|
||||
|
||||
</details>
|
||||
|
||||
@@ -115,7 +113,7 @@ Read these pages when the package-level contract is not enough. They move from t
|
||||
<a id="model-experience"></a>
|
||||
## Model Experience
|
||||
|
||||
Indirectly, through the shell tools (`dsh-tool-bash`, `dsh-tool-pwsh`), which expose this registry's managed `DSH_*` facts and command lookup paths in every shell-tool call.
|
||||
Indirectly, through the shell tools (`dsh-tool-bash`, `dsh-tool-pwsh`), which expose this registry's managed `DSH_*` facts in every shell-tool call.
|
||||
|
||||
#### KV Cache effect
|
||||
|
||||
@@ -129,7 +127,6 @@ The managed environment never enters the request prefix, so it does not invalida
|
||||
These limits define when the registry is a poor fit or needs care. They are current package constraints, not a task backlog.
|
||||
|
||||
- **`list()` enumerates plugin-contributed variables only** — registry-owned built-ins (`DSH_HOME`, `DSH_SHELL`, `DSH_SESSION_ID`, `DSH_PROFILE`, `DSH_PROFILE_DIR`) are not included, so diagnostics, prompt, or UI code must not treat `list()` as an exhaustive environment catalog.
|
||||
- **Command directories belong to the local host.** A remote execution provider needs commands installed and configured in its own execution environment; local directory contributions do not provision the remote host.
|
||||
|
||||
<a id="dev-note"></a>
|
||||
### Dev Note
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
description: "配置每次 Harness shell 调用的变量,以及部署提供的命令目录。"
|
||||
description: "受管 DSH_* shell 环境,供选择、配置或扩展每次模型 shell 调用所运行环境的使用者与维护者阅读。"
|
||||
kind: "package-reference"
|
||||
---
|
||||
|
||||
@@ -9,7 +9,7 @@ kind: "package-reference"
|
||||
|
||||
## 概述
|
||||
|
||||
`dsh-shell-env` 为 Bash 和 PowerShell 工具调用提供当前的 Harness 主目录、会话与 profile 变量。插件可以贡献已声明的 `DSH_*` 值,以及部署提供的命令目录。每次调用都会收到当前注册内容,不修改 `process.env` 或用户 shell 配置。变量所有权重复或返回未声明的值会明确报错。注册项随插件生命周期释放;shell 工具保留各自的 schema 与提示词。
|
||||
`dsh-shell-env` 提供每次模型 shell 调用——bash 或 pwsh——所运行的受信 `DSH_*` 环境:内置事实如 `DSH_HOME`、`DSH_SHELL=1`、agent(智能体)的 `DSH_SESSION_ID`,以及所启动 profile 的 `DSH_PROFILE` 与 `DSH_PROFILE_DIR`。插件作者可以注册自己的事实,带声明键、按每次执行收集,并随插件释放;重复所有权或未声明的运行时键会明确报错,而不是静默覆盖。注册表不会改变模型看到的其他任何内容——shell 工具拥有各自的 schema 与提示词。任何挂载了模型 shell 工具的组合都适合选择它;配置只决定 Harness 主目录。
|
||||
|
||||
## 目录
|
||||
|
||||
@@ -29,7 +29,7 @@ kind: "package-reference"
|
||||
|
||||
### 每次 shell 调用都会收到什么
|
||||
|
||||
每次调用都会收到 `DSH_HOME`(Harness 主目录的绝对路径)、`DSH_SHELL=1`,agent(智能体)调用还会收到 `DSH_SESSION_ID`(调用方会话的 id)。启动器提供了 profile 上下文时,每次调用还会收到 `DSH_PROFILE`(profile 名)与 `DSH_PROFILE_DIR`(其绝对目录;其 `node_modules` 只存放 profile 自行安装的包,harness 自带的组合包从 dsh 安装目录解析);不带 profile 启动的组合则两者都没有。
|
||||
每次调用都会收到 `DSH_HOME`(Harness 主目录的绝对路径)、`DSH_SHELL=1`,agent 调用还会收到 `DSH_SESSION_ID`(调用方会话的 id)。启动器提供了 profile 上下文时,每次调用还会收到 `DSH_PROFILE`(profile 名)与 `DSH_PROFILE_DIR`(其绝对目录;其 `node_modules` 只存放 profile 自行安装的包,harness 自带的组合包从 dsh 安装目录解析);不带 profile 启动的组合则两者都没有。
|
||||
|
||||
### 添加你自己的环境事实
|
||||
|
||||
@@ -52,8 +52,6 @@ export function apply(ctx: Context): void {
|
||||
|
||||
contributor 必须声明它返回的每个键;返回未声明或非字符串的值会让该次调用失败。注册随注册插件的释放而释放,因此热重载插件会移除它的事实。
|
||||
|
||||
contributor 还可以声明绝对路径的 `commandDirectories`。注册表按 contributor 名称顺序将这些目录前置到本地 shell 的 `PATH`,保留各 contributor 内的目录顺序并去除重复目录,随后接上继承的 `PATH`。没有命令目录时,`PATH` 保持不变。目录注册不安装命令或验证其内容;贡献插件负责这些文件及其生命周期。[Office 命令插件](../../skill/skill-office/README.zh.md) 通过这种方式提供 `dsoffice` 和 `office-check`。
|
||||
|
||||
### 选择 Harness 主目录
|
||||
|
||||
唯一配置字段决定暴露为 `DSH_HOME` 的主目录;默认解析顺序为 `dshHome` 配置、环境变量 `$DSH_HOME`,然后是 `~/.dsh`。
|
||||
@@ -66,7 +64,7 @@ contributor 还可以声明绝对路径的 `commandDirectories`。注册表按 c
|
||||
|
||||
### 可能出什么问题
|
||||
|
||||
两个 contributor 声明同一个键,或 contributor 声称拥有保留内置键(`DSH_HOME`、`DSH_SHELL`、`DSH_SESSION_ID`、`DSH_PROFILE`、`DSH_PROFILE_DIR`),都会导致插件加载时明确报错。`DSH_*` 键必须全大写并带下划线(例如 `DSH_REGION`),缺少描述也会让注册失败。相对命令目录也会导致注册失败。
|
||||
两个 contributor 声明同一个键,或 contributor 声称拥有保留内置键(`DSH_HOME`、`DSH_SHELL`、`DSH_SESSION_ID`、`DSH_PROFILE`、`DSH_PROFILE_DIR`),都会导致插件加载时明确报错。`DSH_*` 键必须全大写并带下划线(例如 `DSH_REGION`),缺少描述也会让注册失败。
|
||||
|
||||
-----
|
||||
|
||||
@@ -92,7 +90,7 @@ contributor 还可以声明绝对路径的 `commandDirectories`。注册表按 c
|
||||
|
||||
### 收集
|
||||
|
||||
`collect(execution)` 将内置事实、contributor 值和命令目录的 `PATH` 合并为冻结快照,通过 `ShellExecRequest.dshEnv` 传递。该受信快照优先于普通调用方环境项。`list()` 枚举变量声明而不运行 resolver;不包含命令目录或依赖执行的值。
|
||||
`collect(execution)` 从内置键出发,当执行携带 agent 时加入会话 id,再按 contributor 名称排序合并每个已注册 contributor 解析出的值。结果是一个冻结、按键排序的快照,通过 `ShellExecRequest.dshEnv` 传递。`list()` 枚举声明而不运行 resolver,因此无法反映依赖执行的值。
|
||||
|
||||
</details>
|
||||
|
||||
@@ -115,7 +113,7 @@ contributor 还可以声明绝对路径的 `commandDirectories`。注册表按 c
|
||||
<a id="model-experience"></a>
|
||||
## 模型体验
|
||||
|
||||
通过 shell 工具(`dsh-tool-bash`、`dsh-tool-pwsh`)间接产生影响;这些工具在每次调用中提供本注册表的受管 `DSH_*` 事实和命令查找路径。
|
||||
通过 shell 工具(`dsh-tool-bash`、`dsh-tool-pwsh`)间接产生影响;这些工具把本注册表的受管 `DSH_*` 事实暴露在每次 shell 工具调用中。
|
||||
|
||||
#### KV Cache 影响
|
||||
|
||||
@@ -129,7 +127,6 @@ contributor 还可以声明绝对路径的 `commandDirectories`。注册表按 c
|
||||
这些限制说明注册表何时不合适或需要小心使用。它们是当前包约束,不是任务积压。
|
||||
|
||||
- **`list()` 只枚举插件贡献的变量**——注册表自有的内置键(`DSH_HOME`、`DSH_SHELL`、`DSH_SESSION_ID`、`DSH_PROFILE`、`DSH_PROFILE_DIR`)不包含在内,因此诊断、提示词或 UI 代码不得把 `list()` 当作完整的环境目录。
|
||||
- **命令目录属于本地主机。** 远程执行提供方需要在自己的执行环境中安装和配置命令;本地目录贡献不会为远程主机准备资源。
|
||||
|
||||
<a id="dev-note"></a>
|
||||
### 开发备注
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
*/
|
||||
|
||||
import { Service, type Context } from '@deepseek-ai/cordis'
|
||||
import { delimiter, isAbsolute } from 'node:path'
|
||||
import z from '@deepseek-ai/schemastery'
|
||||
import { DSH_ENV_PREFIX } from '@deepseek-ai/dsh-shell'
|
||||
import type { DshEnvironment, DshEnvironmentKey } from '@deepseek-ai/dsh-shell'
|
||||
@@ -52,8 +51,6 @@ export interface BashEnvVariable {
|
||||
export interface BashEnvContributor {
|
||||
/** Stable contributor name used in diagnostics and duplicate detection. */
|
||||
name: string
|
||||
/** Absolute command directories prepended to the local shell PATH; no process-global environment is changed. */
|
||||
commandDirectories?: readonly string[]
|
||||
/** Complete set of `DSH_*` keys this contributor may return. */
|
||||
variables: Readonly<Record<DshEnvironmentKey, BashEnvVariable>>
|
||||
/**
|
||||
@@ -122,9 +119,6 @@ export class ShellEnvRegistry extends Service {
|
||||
if (this.contributors.has(contributor.name)) {
|
||||
throw new Error(`bash env contributor "${contributor.name}" is already registered`)
|
||||
}
|
||||
if (contributor.commandDirectories?.some(directory => !isAbsolute(directory))) {
|
||||
throw new Error(`bash env contributor "${contributor.name}" requires absolute command directories`)
|
||||
}
|
||||
|
||||
const variables = Object.entries(contributor.variables) as [DshEnvironmentKey, BashEnvVariable][]
|
||||
for (const [key, variable] of variables) {
|
||||
@@ -187,14 +181,7 @@ export class ShellEnvRegistry extends Service {
|
||||
}
|
||||
}
|
||||
|
||||
const directories = [...this.contributors.values()].sort((left, right) => left.name.localeCompare(right.name))
|
||||
.flatMap(contributor => contributor.commandDirectories ?? [])
|
||||
return Object.freeze({
|
||||
...Object.fromEntries(Object.entries(values).sort(([left], [right]) => left.localeCompare(right))),
|
||||
...(directories.length === 0 ? {} : {
|
||||
PATH: [...new Set(directories), ...(process.env.PATH ? [process.env.PATH] : [])].join(delimiter),
|
||||
}),
|
||||
})
|
||||
return Object.freeze(Object.fromEntries(Object.entries(values).sort(([left], [right]) => left.localeCompare(right))))
|
||||
}
|
||||
|
||||
// TODO(bash-env-list-builtins): Include registry-owned built-ins before diagnostics,
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
import { homedir } from 'node:os'
|
||||
import { delimiter, join, resolve } from 'node:path'
|
||||
import { join, resolve } from 'node:path'
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest'
|
||||
import { Context } from '@deepseek-ai/cordis'
|
||||
import { ToolCallId } from '@deepseek-ai/dsh-llm'
|
||||
@@ -164,39 +164,6 @@ describe('ShellEnvRegistry', () => {
|
||||
variables: { DSH_BLANK_DESCRIPTION: { description: ' ' } },
|
||||
resolve: () => ({}),
|
||||
})).toThrow(/must describe/)
|
||||
expect(() => registry.register({
|
||||
name: 'relative-command-directory', commandDirectories: ['relative/bin'], variables: {}, resolve: () => ({}),
|
||||
})).toThrow(/absolute command directories/)
|
||||
})
|
||||
|
||||
it('prepends unique command directories in contributor order without changing the process PATH', async () => {
|
||||
const ambient = resolve('ambient-bin'), first = resolve('first-bin'), second = resolve('second-bin')
|
||||
vi.stubEnv('PATH', ambient)
|
||||
const ctx = new Context()
|
||||
try {
|
||||
const registry = new ShellEnvRegistry(ctx, { dshHome: './test-dsh-home' })
|
||||
registry.register({ name: 'b', commandDirectories: [second, first], variables: {}, resolve: () => ({}) })
|
||||
const dispose = registry.register({ name: 'a', commandDirectories: [first], variables: {}, resolve: () => ({}) })
|
||||
expect(registry.collect(execution()).PATH).toBe([first, second, ambient].join(delimiter))
|
||||
expect(process.env.PATH).toBe(ambient)
|
||||
dispose()
|
||||
expect(registry.collect(execution()).PATH).toBe([second, first, ambient].join(delimiter))
|
||||
} finally {
|
||||
await ctx.fiber.dispose()
|
||||
}
|
||||
})
|
||||
|
||||
it('exposes only contributed directories when the inherited PATH is empty', async () => {
|
||||
vi.stubEnv('PATH', '')
|
||||
const ctx = new Context()
|
||||
try {
|
||||
const registry = new ShellEnvRegistry(ctx, { dshHome: './test-dsh-home' }), bin = resolve('command-bin')
|
||||
registry.register({ name: 'local-command', commandDirectories: [bin], variables: {}, resolve: () => ({}) })
|
||||
expect(registry.collect(execution()).PATH).toBe(bin)
|
||||
expect(process.env.PATH).toBe('')
|
||||
} finally {
|
||||
await ctx.fiber.dispose()
|
||||
}
|
||||
})
|
||||
|
||||
it('rejects undeclared variables returned by a contributor', () => {
|
||||
|
||||
@@ -9,26 +9,26 @@
|
||||
en: f855ac5e12b4e604
|
||||
zh: b2e875d31d56cb2e
|
||||
/deepseek-ai-dsh-skill-office/summary:
|
||||
en: 6203c381070b96f6
|
||||
zh: 4ff7a778f7c43b89
|
||||
en: 42234b5ae272eba3
|
||||
zh: 9df9a2a3ea9a9697
|
||||
/deepseek-ai-dsh-skill-office/table-of-contents:
|
||||
en: c361195a73cf5755
|
||||
zh: 745b04e7be0be369
|
||||
/deepseek-ai-dsh-skill-office/use-this-package:
|
||||
en: f9dfa0282f0aacfd
|
||||
zh: 989a91e5f63b757f
|
||||
en: 8bfffcb6f69eb597
|
||||
zh: a859a1ed72b43fde
|
||||
/deepseek-ai-dsh-skill-office/use-this-package/progressive-loading:
|
||||
en: fd13620d7ddda0a6
|
||||
zh: 08ad6f76b0a56f47
|
||||
/deepseek-ai-dsh-skill-office/use-this-package/structural-checks:
|
||||
en: 81efb4310276e7a9
|
||||
zh: 7c7a0fa8f2512c08
|
||||
en: 2c1f1fa964a3901f
|
||||
zh: 43436136362d4158
|
||||
/deepseek-ai-dsh-skill-office/understand-the-implementation:
|
||||
en: a06162bae16bddad
|
||||
zh: 40c3f73993b2fe7d
|
||||
en: 81eafcae9e11965e
|
||||
zh: 082123177625b3d8
|
||||
/deepseek-ai-dsh-skill-office/further-exploration:
|
||||
en: a93f275e608a6bab
|
||||
zh: 191e8d36c433e8a2
|
||||
en: 23830c100287ffb8
|
||||
zh: 7a4100e87057bc20
|
||||
/deepseek-ai-dsh-skill-office/model-experience:
|
||||
en: bbd979fd20e7b308
|
||||
zh: 7e6b6e04f2aedb02
|
||||
|
||||
@@ -9,7 +9,7 @@ English | [中文](README.zh.md)
|
||||
|
||||
## Summary
|
||||
|
||||
The catalog lists the Office router and six authoring or operation skills. Full instructions load on demand. Skills use `office-check` and `dsoffice` through existing shell tools without exposing interpreter or package paths. SDK and Desktop each mount the skill provider, command plugin, and dependency query; ordinary Web does not mount them by default.
|
||||
The catalog lists the Office router and six authoring or operation skills. Full instructions load on demand. Authoring skills use the selected Python and shared checker script; operation skills supply the configured Node and LibreOffice Kit CLI paths. SDK and Desktop mount the skill provider and dependency query separately.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
@@ -26,30 +26,20 @@ The catalog lists the Office router and six authoring or operation skills. Full
|
||||
<a id="use-this-package"></a>
|
||||
## Use this package
|
||||
|
||||
Mount the skill provider beside the skill registry and `dsh-tool-skill`, and the command plugin beside `dsh-shell-env`. The provider supplies instructions and checker resources; the command plugin makes `dsoffice` and `office-check` available to local Bash and PowerShell tool calls.
|
||||
Mount the skill provider beside the skill registry and `dsh-tool-skill`. The provider supplies instructions and checker resources; operation skills append absolute interpreter and CLI paths when loaded.
|
||||
|
||||
```yaml
|
||||
- name: '@deepseek-ai/dsh-skill-office'
|
||||
- name: '@deepseek-ai/dsh-skill-office/commands'
|
||||
|
||||
```
|
||||
|
||||
| Field | Default | Meaning |
|
||||
|---|---|---|
|
||||
| `assetRoot` | Carrier resources or packaged `assets/` | Absolute directory containing the seven skill folders and shared `scripts/`. |
|
||||
| `node` | Host Node.js | Standalone Node executable for operation skills; packaged carriers supply it explicitly. |
|
||||
| `cli` | Installed Kit CLI | Absolute CLI entry; `false` disables operation execution. |
|
||||
|
||||
Invalid skill assets reject registration. Loading instructions does not resolve interpreters or prepare engines. Bash or PowerShell owns approvals, sandboxing, cancellation, and output management. Resources and execution tools must refer to the same host.
|
||||
|
||||
The command plugin accepts separate configuration:
|
||||
|
||||
| Field | Default | Meaning |
|
||||
|---|---|---|
|
||||
| `command` | Carrier or installed Kit | Executable and fixed arguments for `dsoffice`; `false` omits that command. |
|
||||
| `checkCommand` | Configured Python checker | Executable and fixed arguments for `office-check`; `false` omits that command. |
|
||||
| `assetRoot` | Carrier resources or packaged `assets/` | Directory containing the shared checker and skills. |
|
||||
|
||||
Command overrides require an absolute executable as their first argument. Launchers receive the caller's remaining arguments unchanged and live only while the command plugin is mounted. Windows launchers preserve empty arguments, embedded quotes, trailing backslashes, and Unicode paths on Windows PowerShell 5.1 and PowerShell 7; PowerShell arrays supplied as one argument become comma-separated text. Launchers accept input file paths and do not forward pipeline input. A missing executable returns a nonzero exit code. The shell environment prepends their private directory to each tool call's `PATH`; it does not change the process or user's shell configuration. Disabling a command does not prevent skill loading. `office-check` directly runs the Python checker with the selected carrier interpreter or explicit `checkCommand`; it is omitted when neither is supplied. The checker uses only Python standard-library modules. Command registration and execution neither prepare nor copy a runtime. The general `load_workspace_dependencies` tool supplies authoring interpreters and libraries independently.
|
||||
|
||||
`DSH_PRIMARY_RUNTIME` selects authoring and checker resources. Kit commands use the carrier's Node.js when supplied, otherwise the host Node.js, so Python-only authoring payloads are supported.
|
||||
Invalid skill assets reject registration. Authoring instructions do not resolve renderer paths; loading operation instructions validates existing interpreter and CLI files without preparing engines. Bash or PowerShell owns approvals, sandboxing, cancellation, and output management. Resources and execution tools must refer to the same host.
|
||||
|
||||
<a id="progressive-loading"></a>
|
||||
### Progressive loading
|
||||
@@ -89,7 +79,7 @@ New files and content, data, or formula edits do not require rendering solely be
|
||||
|
||||
### Structural checks
|
||||
|
||||
`office-check <file> --out <report.json>` reads DOCX, PPTX, and XLSX without changing the source. The shared Python checker validates ZIP/XML and internal relationships, summarizes document structure, and optionally checks required text or slide/sheet counts. It requires only the Python standard library. Invalid files and report-write failures return a JSON failure report. Structural success does not establish appearance, feature preservation, or calculated formula values.
|
||||
`"<python>" "<skill-directory>/../scripts/check_office.py" <file> --out <report.json>` reads DOCX, PPTX, and XLSX without changing the source. The shared Python checker validates ZIP/XML and internal relationships, summarizes document structure, and optionally checks required text or slide/sheet counts. It requires only the Python standard library. Invalid files and report-write failures return a JSON failure report. Structural success does not establish appearance, feature preservation, or calculated formula values.
|
||||
|
||||
-----
|
||||
|
||||
@@ -101,12 +91,12 @@ New files and content, data, or formula edits do not require rendering solely be
|
||||
|
||||
The provider reads descriptions at registration and bodies on demand. Registry precedence, scope, and invocation permissions apply to every skill. Each loaded skill includes its resource directory for relative references. Disposal unregisters all candidates.
|
||||
|
||||
The provider registers no tools or activation projection. Loaded skill results remain logged through the generic skill loader. Resume and fork use existing session history and tool declaration reconciliation. The command plugin hides carrier-specific executable paths behind local launchers and registers their directory with the shell environment; disposal removes both the contribution and the directory. Windows launcher directories support long `DSH_HOME` paths; `PATH` entries use ordinary absolute paths. When an executable path exceeds the Windows process launch limit, the plugin temporarily links its parent directory through a short path under the system temporary directory and removes that link on disposal.
|
||||
The provider registers no tools or activation projection. Loaded skill results remain logged through the generic skill loader. Resume and fork use existing session history and tool declaration reconciliation. Interpreter and CLI paths are resolved only when an operation skill is loaded.
|
||||
|
||||
| File | Responsibility |
|
||||
|---|---|
|
||||
| [`src/index.ts`](src/index.ts) | Resource registration and unchanged skill bodies. |
|
||||
| [`src/commands.ts`](src/commands.ts) | Local launchers, carrier selection, and shell environment contribution. |
|
||||
|
||||
| [`assets/`](assets/) | Router, six subskills, and read-only OOXML checker. |
|
||||
|
||||
</details>
|
||||
@@ -118,7 +108,6 @@ The provider registers no tools or activation projection. Loaded skill results r
|
||||
|
||||
- [Skill registry](../skill/README.md) — discovery and precedence.
|
||||
- [Skill tool](../tool-skill/README.md) — model catalogs and loaded bodies.
|
||||
- [Shell environment](../../shell/shell-env/README.md) — command directories and managed variables.
|
||||
- [File delivery](../../deliverables/tool-present/README.md) — current source-path delivery.
|
||||
|
||||
-----
|
||||
|
||||
@@ -9,7 +9,7 @@ kind: "package-reference"
|
||||
|
||||
## 概述
|
||||
|
||||
目录列出 Office 路由及六个创作或操作技能,完整说明按需加载。技能通过现有 shell 工具使用 `office-check` 和 `dsoffice`,不暴露解释器或包路径。SDK 和 Desktop 分别挂载技能提供者、命令插件及依赖查询;普通 Web 默认不挂载它们。
|
||||
目录列出 Office 路由及六个创作或操作技能,完整说明按需加载。创作技能使用选定的 Python 和共享检查脚本;操作技能提供配置的 Node 与 LibreOffice Kit CLI 路径。SDK 和 Desktop 分别挂载技能提供者和依赖查询。
|
||||
|
||||
## 目录
|
||||
|
||||
@@ -26,30 +26,20 @@ kind: "package-reference"
|
||||
<a id="use-this-package"></a>
|
||||
## 使用本包
|
||||
|
||||
在技能注册表和 `dsh-tool-skill` 旁挂载技能提供者,在 `dsh-shell-env` 旁挂载命令插件。提供者负责说明和检查器资源;命令插件让本地 Bash 和 PowerShell 工具调用可以使用 `dsoffice` 与 `office-check`。
|
||||
在技能注册表和 `dsh-tool-skill` 旁挂载技能提供者。提供者负责说明和检查器资源;操作技能在加载时附加解释器和 CLI 的绝对路径。
|
||||
|
||||
```yaml
|
||||
- name: '@deepseek-ai/dsh-skill-office'
|
||||
- name: '@deepseek-ai/dsh-skill-office/commands'
|
||||
|
||||
```
|
||||
|
||||
| 字段 | 默认值 | 含义 |
|
||||
|---|---|---|
|
||||
| `assetRoot` | 载体资源或包内 `assets/` | 包含七个技能目录及共享 `scripts/` 的绝对路径。 |
|
||||
| `node` | 宿主 Node.js | 操作技能使用的独立 Node 可执行程序;打包载体显式提供。 |
|
||||
| `cli` | 已安装 Kit CLI | CLI 入口的绝对路径;`false` 禁用操作执行。 |
|
||||
|
||||
无效技能资源会阻止注册。加载说明不解析解释器或准备引擎。Bash 或 PowerShell 负责审批、沙箱、取消和输出管理。资源与执行工具必须位于同一主机。
|
||||
|
||||
命令插件接受独立配置:
|
||||
|
||||
| 字段 | 默认值 | 含义 |
|
||||
|---|---|---|
|
||||
| `command` | 载体或已安装 Kit | `dsoffice` 的可执行程序及固定参数;`false` 不提供该命令。 |
|
||||
| `checkCommand` | 配置的 Python 检查器 | `office-check` 的可执行程序及固定参数;`false` 不提供该命令。 |
|
||||
| `assetRoot` | 载体资源或包内 `assets/` | 包含共享检查器和技能的目录。 |
|
||||
|
||||
命令覆盖的首个参数必须是可执行程序的绝对路径。启动器原样接收调用方的其余参数,仅在命令插件挂载期间存在。Windows 启动器在 Windows PowerShell 5.1 和 PowerShell 7 下保留空参数、内嵌引号、末尾反斜杠和 Unicode 路径;作为单个参数传入的 PowerShell 数组会转为逗号分隔文本。启动器通过文件路径接收输入,不转发管道输入。可执行程序不存在时,命令返回非零退出码。shell 环境将启动器的私有目录前置到每次工具调用的 `PATH`;不修改进程或用户 shell 配置。禁用命令不阻止技能加载。`office-check` 使用所选载体解释器或显式 `checkCommand` 直接运行 Python 检查器;两者均未提供时不注册该命令。检查器只使用 Python 标准库。命令注册和执行均不准备或复制运行时。通用 `load_workspace_dependencies` 工具独立提供创作解释器和库。
|
||||
|
||||
`DSH_PRIMARY_RUNTIME` 选择创作和检查器资源。Kit 命令使用载体提供的 Node.js,否则使用宿主 Node.js,因此支持仅含 Python 的创作载荷。
|
||||
无效技能资源会阻止注册。创作说明不解析渲染器路径;操作说明加载时校验现有解释器和 CLI 文件,不准备引擎。Bash 或 PowerShell 负责审批、沙箱、取消和输出管理。资源与执行工具必须位于同一主机。
|
||||
|
||||
<a id="progressive-loading"></a>
|
||||
### 渐进加载
|
||||
@@ -89,7 +79,7 @@ flowchart TD
|
||||
|
||||
### 结构检查
|
||||
|
||||
`office-check <file> --out <report.json>` 读取 DOCX、PPTX 和 XLSX,不修改源文件。共享 Python 检查器验证 ZIP/XML 和内部关系、汇总文档结构,并可检查必需文本或幻灯片/工作表数量。它仅依赖 Python 标准库。无效文件和报告写入失败会返回 JSON 失败报告。结构检查成功不代表外观、功能保留或公式计算值通过验证。
|
||||
`"<python>" "<skill-directory>/../scripts/check_office.py" <file> --out <report.json>` 读取 DOCX、PPTX 和 XLSX,不修改源文件。共享 Python 检查器验证 ZIP/XML 和内部关系、汇总文档结构,并可检查必需文本或幻灯片/工作表数量。它仅依赖 Python 标准库。无效文件和报告写入失败会返回 JSON 失败报告。结构检查成功不代表外观、功能保留或公式计算值通过验证。
|
||||
|
||||
-----
|
||||
|
||||
@@ -101,12 +91,12 @@ flowchart TD
|
||||
|
||||
提供者在注册时读取摘要,按需读取正文。注册表优先级、作用域和调用权限适用于全部技能。加载结果包含用于解析相对引用的资源目录。卸载提供者会移除全部候选技能。
|
||||
|
||||
提供者不注册工具或激活投影。通用技能加载器记录已加载技能的结果。恢复和 fork 使用现有会话历史及工具声明更新机制。命令插件用本地启动器封装载体专属可执行路径,并将其目录注册到 shell 环境;释放时移除该贡献与目录。Windows 启动器目录支持较长的 `DSH_HOME` 路径;`PATH` 条目使用普通绝对路径。可执行程序路径超过 Windows 进程启动长度限制时,插件在系统临时目录下建立通往其父目录的短路径链接,并在释放时移除该链接。
|
||||
提供者不注册工具或激活投影。通用技能加载器记录已加载技能的结果。恢复和 fork 使用现有会话历史及工具声明更新机制。解释器和 CLI 路径仅在加载操作技能时解析。
|
||||
|
||||
| 文件 | 职责 |
|
||||
|---|---|
|
||||
| [`src/index.ts`](src/index.ts) | 注册资源并返回原始技能正文。 |
|
||||
| [`src/commands.ts`](src/commands.ts) | 本地启动器、载体选择和 shell 环境贡献。 |
|
||||
|
||||
| [`assets/`](assets/) | 路由、六个子技能与只读 OOXML 检查器。 |
|
||||
|
||||
</details>
|
||||
@@ -118,7 +108,6 @@ flowchart TD
|
||||
|
||||
- [技能注册表](../skill/README.zh.md) — 发现和优先级。
|
||||
- [技能工具](../tool-skill/README.zh.md) — 模型目录和加载正文。
|
||||
- [Shell 环境](../../shell/shell-env/README.zh.md) — 命令目录和受管变量。
|
||||
- [文件交付](../../deliverables/tool-present/README.zh.md) — 当前源文件路径交付。
|
||||
|
||||
-----
|
||||
|
||||
@@ -33,14 +33,16 @@ python-docx does not paginate or render documents. Do not represent ordinary rep
|
||||
|
||||
Run the shared structural checker when `office-check` is available:
|
||||
|
||||
In PowerShell, prefix the quoted Python executable with `&`. Resolve the checker path relative to this skill directory.
|
||||
|
||||
```text
|
||||
office-check <document.docx> --out <checks.json>
|
||||
"<python>" "<skill-directory>/../scripts/check_office.py" <document.docx> --out <checks.json>
|
||||
```
|
||||
|
||||
It checks ZIP/XML integrity and internal relationships, and reports paragraphs, logical table dimensions, and sections. Optional `--contains TEXT` arguments assert required text. A successful structural check does not verify pagination, clipping, fonts, or visual appearance. Compare the summary and reopened document with the user's request, including unchanged content that matters to an edit.
|
||||
|
||||
If `office-check` is unavailable, use an already configured environment to check the ZIP/XML package and internal relationships. Report the missing environment if those checks cannot run; do not claim structural validation.
|
||||
If the Python checker cannot run, use an already configured environment to check the ZIP/XML package and internal relationships. Report the missing environment if those checks cannot run; do not claim structural validation.
|
||||
|
||||
Deliver after the requested content and structural checks pass. Creating a file or changing content with incidental basic formatting does not require additional operations. Load `office-render` for requested images or visual inspection and for appearance-focused styling, spacing, sizing, or alignment changes unless the user explicitly skips rendering. For PDF output load `office-export-pdf`.
|
||||
Deliver after the requested content and structural checks pass. Creating a file or changing content with incidental basic formatting does not require additional operations. Load `office-render` for requested images or visual inspection. When styling, font color, spacing, sizing, or text alignment is the requested edit, load `office-render` and inspect the changed page even without a separate visual-check request, unless the user explicitly skips rendering. For PDF output load `office-export-pdf`.
|
||||
|
||||
Call `present({"files":[{"path":"report.docx"}]})` with the actual final DOCX path. It exposes the current source file without copying or preserving its bytes, so keep that file in place and do not present temporary QA reports unless requested. If `present` is unavailable, provide the final workspace path using the session's supported file delivery method.
|
||||
@@ -5,12 +5,12 @@ description: Convert an Office document to a requested PDF with LibreOffice Kit.
|
||||
|
||||
# Export an Office document to PDF
|
||||
|
||||
Use the installed LibreOffice Kit CLI through the shell with `dsoffice`. Prefer bundled LibreOffice unless the user requests another installation. If the Office sidecar is missing, follow [sidecar setup](../office/references/sidecar.md): ask whether the user wants to download it and install only after they agree. Do not invoke system soffice, use npx, or install a replacement to work around a failed conversion with an installed sidecar.
|
||||
Use the installed LibreOffice Kit CLI through the shell with the absolute Node and CLI paths supplied below. In Bash, invoke `"<node>" "<cli>"`; in PowerShell, invoke `& "<node>" "<cli>"`. Prefer bundled LibreOffice unless the user requests another installation. If the Office sidecar is missing, follow [sidecar setup](../office/references/sidecar.md): ask whether the user wants to download it and install only after they agree. Do not invoke system soffice, use npx, or install a replacement to work around a failed conversion with an installed sidecar.
|
||||
|
||||
Convert the final saved Office file to a new PDF in the task workspace. Preserve the source. Quote each input and output path.
|
||||
|
||||
```text
|
||||
dsoffice convert --input <final-office-file> --output <new-file.pdf>
|
||||
"<node>" "<cli>" convert --input <final-office-file> --output <new-file.pdf>
|
||||
```
|
||||
|
||||
Check the command result, nonempty output, and `%PDF-` file signature. If a PDF reader library is already available, compare page count and extractable text with the requested content. If it is unavailable, report the extent of validation; do not generate images or install extra tools to validate a conversion. Spreadsheet PDF pages follow workbook print settings; change those settings only when requested. Conversion may differ from the native application's pagination or fonts.
|
||||
|
||||
@@ -57,13 +57,15 @@ Check that text and images fit the slide dimensions, titles form a useful sequen
|
||||
|
||||
Run the shared structural checker when `office-check` is available:
|
||||
|
||||
In PowerShell, prefix the quoted Python executable with `&`. Resolve the checker path relative to this skill directory.
|
||||
|
||||
```text
|
||||
office-check <presentation.pptx> --out <checks.json>
|
||||
"<python>" "<skill-directory>/../scripts/check_office.py" <presentation.pptx> --out <checks.json>
|
||||
```
|
||||
|
||||
It checks ZIP/XML integrity and internal relationships and reports slide count and extracted text. Use repeated `--contains TEXT` arguments for required slide text and `--count N` for a requested slide count; `--contains` excludes chart text and speaker notes. Reopen the file to check the requested edits, chart data, and notes. Structural success does not establish text fit, alignment, readable contrast, or rendering fidelity.
|
||||
|
||||
If `office-check` is unavailable, use an already configured environment to check the ZIP/XML package and internal relationships. Report the missing environment if those checks cannot run; do not claim structural validation.
|
||||
If the Python checker cannot run, use an already configured environment to check the ZIP/XML package and internal relationships. Report the missing environment if those checks cannot run; do not claim structural validation.
|
||||
|
||||
Deliver after the requested content and structural checks pass. Creating a file or changing content with incidental basic formatting does not require additional operations. Load `office-render` for requested images or visual inspection and for appearance-focused styling, spacing, sizing, or alignment changes unless the user explicitly skips rendering. For PDF output load `office-export-pdf`.
|
||||
|
||||
|
||||
@@ -5,12 +5,12 @@ description: Refresh spreadsheet formula caches and verify calculated values wit
|
||||
|
||||
# Recalculate spreadsheet formulas
|
||||
|
||||
Use the installed LibreOffice Kit CLI through the shell with `dsoffice`. Prefer bundled LibreOffice unless the user requests another installation. If the Office sidecar is missing, follow [sidecar setup](../office/references/sidecar.md): ask whether the user wants to download it and install only after they agree. Do not invoke system soffice, use npx, or install a replacement to work around a failed recalculation with an installed sidecar.
|
||||
Use the installed LibreOffice Kit CLI through the shell with the absolute Node and CLI paths supplied below. In Bash, invoke `"<node>" "<cli>"`; in PowerShell, invoke `& "<node>" "<cli>"`. Prefer bundled LibreOffice unless the user requests another installation. If the Office sidecar is missing, follow [sidecar setup](../office/references/sidecar.md): ask whether the user wants to download it and install only after they agree. Do not invoke system soffice, use npx, or install a replacement to work around a failed recalculation with an installed sidecar.
|
||||
|
||||
Keep the original workbook and write a new file in the task workspace. Quote each input and output path.
|
||||
|
||||
```text
|
||||
dsoffice recalculate --input <workbook.xlsx> --output <recalculated.xlsx>
|
||||
"<node>" "<cli>" recalculate --input <workbook.xlsx> --output <recalculated.xlsx>
|
||||
```
|
||||
|
||||
Verify the saved result with openpyxl, using `load_workspace_dependencies` for the Python path unless a project environment is required. Open it with both `data_only=False` and `data_only=True`. Check that formulas survive and cached results match the requested logic, expected totals, and cell types. Check required unchanged sheets, styles, and data. Recalculation does not validate business logic or guarantee Excel-specific feature compatibility.
|
||||
|
||||
@@ -5,7 +5,7 @@ description: Render requested document images or inspect visual layout with Libr
|
||||
|
||||
# Document images and visual inspection
|
||||
|
||||
Use the installed LibreOffice Kit CLI through the shell with `dsoffice`. Prefer bundled LibreOffice unless the user requests another installation. If the Office sidecar is missing, follow [sidecar setup](../office/references/sidecar.md): ask whether the user wants to download it and install only after they agree. Do not invoke system soffice, use npx, install a replacement renderer, or build an alternative rendering pipeline to work around a failed render with an installed sidecar.
|
||||
Use the installed LibreOffice Kit CLI through the shell with the absolute Node and CLI paths supplied below. In Bash, invoke `"<node>" "<cli>"`; in PowerShell, invoke `& "<node>" "<cli>"`. Prefer bundled LibreOffice unless the user requests another installation. If the Office sidecar is missing, follow [sidecar setup](../office/references/sidecar.md): ask whether the user wants to download it and install only after they agree. Do not invoke system soffice, use npx, install a replacement renderer, or build an alternative rendering pipeline to work around a failed render with an installed sidecar.
|
||||
|
||||
Before generating images only for inspection, establish that the current model accepts images. Otherwise finish the applicable content and structure checks and report the requested visual check as unavailable. Do not generate unreadable previews, retry image reads, or choose a second model. Requested image exports can still be delivered.
|
||||
|
||||
@@ -14,8 +14,8 @@ Before generating images only for inspection, establish that the current model a
|
||||
Keep the saved deliverable in the task workspace. For requested image exports, use the requested output directory and retain the images. For inspection-only previews, create a private, uniquely named temporary parent inside that workspace and pass a child path that does not yet exist as `--output-dir`; the CLI creates that child. On POSIX, use `preview_root=$(mktemp -d "./.dsh-office.XXXXXXXX")` (owner-only permissions) and `--output-dir "$preview_root/render"`. On PowerShell, create a parent named `.dsh-office-` plus `[guid]::NewGuid().ToString('N')` under the task workspace and pass an uncreated `render` child; it inherits the workspace ACL. Quote each input and output path. Retain the parent until image inspection finishes, then remove only that parent, including after a failed render. Never use a fixed directory name or remove the workspace itself.
|
||||
|
||||
```text
|
||||
dsoffice render --input <final-file> --output-dir <new-directory> --pages "1,3,4"
|
||||
dsoffice render --input <final-workbook.xlsx> --output-dir <new-directory> --sheet <exact-name> --range <A1-range>
|
||||
"<node>" "<cli>" render --input <final-file> --output-dir <new-directory> --pages "1,3,4"
|
||||
"<node>" "<cli>" render --input <final-workbook.xlsx> --output-dir <new-directory> --sheet <exact-name> --range <A1-range>
|
||||
```
|
||||
|
||||
For DOCX, PPTX, or PDF, batch requested pages/slides in one call. In PowerShell, quote comma-separated `--pages` values so they remain one argument. Inspect all pages only for a requested whole-document review. For worksheets, choose the exact affected range, including chart/drawing regions; worksheet numbers are not PDF page numbers. Inspect the final saved file, reuse existing images for an unchanged source, and rerender only after requested source changes or for previously unrendered regions. Change print areas or scaling only when the user requests print layout.
|
||||
|
||||
@@ -43,13 +43,15 @@ Do not rename `.xls`, `.xlsb`, encrypted files, or macro-enabled files to `.xlsx
|
||||
|
||||
Run the shared structural checker when `office-check` is available:
|
||||
|
||||
In PowerShell, prefix the quoted Python executable with `&`. Resolve the checker path relative to this skill directory.
|
||||
|
||||
```text
|
||||
office-check <workbook.xlsx> --out <checks.json>
|
||||
"<python>" "<skill-directory>/../scripts/check_office.py" <workbook.xlsx> --out <checks.json>
|
||||
```
|
||||
|
||||
It checks ZIP/XML integrity and internal relationships, and reports sheet names, populated-cell counts, and formula counts. Repeated `--contains TEXT` arguments check string cells and sheet names, and `--count N` checks sheet count. `--contains` excludes numeric cells and does not validate formula results; verify those separately with openpyxl. The checker does not calculate formulas or judge workbook appearance. Compare relevant values, types, formulas, styles, and totals with the task's source data.
|
||||
|
||||
If `office-check` is unavailable, use an already configured environment to check the ZIP/XML package and internal relationships. Report the missing environment if those checks cannot run; do not claim structural validation.
|
||||
If the Python checker cannot run, use an already configured environment to check the ZIP/XML package and internal relationships. Report the missing environment if those checks cannot run; do not claim structural validation.
|
||||
|
||||
Load `office-render` for requested images or visual inspection and whenever the user's primary task targets appearance, including cell fill colors, text alignment, spacing, or sizing. These appearance changes require rendering even without a separate visual-check request, unless the user explicitly skips it. New workbooks and data or formula edits do not require rendering solely because they include incidental basic formatting. In particular, bold headers and number formats accompanying data edits do not require loading `office-render` or running its commands.
|
||||
|
||||
|
||||
@@ -18,34 +18,23 @@
|
||||
"types": "./lib/types/index.d.ts",
|
||||
"default": "./lib/index.js"
|
||||
},
|
||||
"./package.json": "./package.json",
|
||||
"./commands": {
|
||||
"types": "./lib/types/commands.d.ts",
|
||||
"default": "./lib/commands.js"
|
||||
}
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
"files": [
|
||||
"lib/index.js",
|
||||
"lib/commands.js",
|
||||
"assets",
|
||||
"lib/types/**/*.d.ts"
|
||||
],
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@deepseek-ai/dsh-skill": "workspace:*",
|
||||
"@deepseek-ai/cordis": "workspace:~",
|
||||
"@deepseek-ai/dsh-shell-env": "workspace:*",
|
||||
"@deepseek-ai/dsh-home-paths": "workspace:*"
|
||||
"@deepseek-ai/cordis": "workspace:~"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@deepseek-ai/dsh-pwsh-local": "workspace:*",
|
||||
"@deepseek-ai/dsh-subprocess-local": "workspace:*",
|
||||
"@deepseek-ai/dsh-skill": "workspace:*",
|
||||
"@deepseek-ai/cordis": "workspace:~",
|
||||
"@deepseek-ai/cordis-plugin-loader": "workspace:~",
|
||||
"@deepseek-ai/cordis-plugin-include": "workspace:~",
|
||||
"@deepseek-ai/dsh-shell-env": "workspace:*",
|
||||
"@deepseek-ai/dsh-home-paths": "workspace:*"
|
||||
"@deepseek-ai/cordis-plugin-include": "workspace:~"
|
||||
},
|
||||
"dependencies": {
|
||||
"@deepseek-ai/libreoffice-kit": "^0.1.5",
|
||||
|
||||
@@ -1,104 +0,0 @@
|
||||
/** Local Office command launchers contributed to model shell calls. */
|
||||
import { chmodSync, existsSync, mkdirSync, mkdtempSync, rmSync, symlinkSync, writeFileSync } from 'node:fs'
|
||||
import { tmpdir } from 'node:os'
|
||||
import { basename, dirname, isAbsolute, join, toNamespacedPath } from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import type { Context } from '@deepseek-ai/cordis'
|
||||
import z from '@deepseek-ai/schemastery'
|
||||
import { resolveDshHome } from '@deepseek-ai/dsh-home-paths'
|
||||
import type {} from '@deepseek-ai/dsh-shell-env'
|
||||
|
||||
/** Local interpreter and resource selection; commands execute in the same host as these resources. */
|
||||
export interface Config {
|
||||
/** dsoffice argv; defaults to the carrier or installed Kit. False disables dsoffice. */
|
||||
command?: string[] | false
|
||||
/** Python checker command argv; defaults to the supplied runtime; absent without a runtime. */
|
||||
checkCommand?: string[] | false
|
||||
/** Directory containing the shared scripts/ and Office skills. */
|
||||
assetRoot?: string
|
||||
}
|
||||
|
||||
/** Validate local command configuration. */
|
||||
export const Config: z<Config> = z.object({
|
||||
command: z.union([z.array(z.string()).min(1), z.const(false)]),
|
||||
checkCommand: z.union([z.array(z.string()).min(1), z.const(false)]),
|
||||
assetRoot: z.string().min(1),
|
||||
})
|
||||
|
||||
/** Cordis plugin identity. */
|
||||
export const name = 'office-commands'
|
||||
/** Registry that publishes the launcher directory for each shell execution. */
|
||||
export const inject = ['shellEnv']
|
||||
|
||||
function quote(value: string): string { return `'${value.replaceAll("'", "'\\''")}'` }
|
||||
|
||||
function writeLauncher(directory: string, name: string, command: readonly string[]): void {
|
||||
const executable = command[0]
|
||||
if (executable === undefined || !isAbsolute(executable)) throw new Error(`office-commands: ${name} requires an absolute executable`)
|
||||
if (command.some(argument => /[\0\r\n]/u.test(argument))) throw new Error('office-commands: command arguments must not contain NUL or newlines')
|
||||
const script = join(directory, name)
|
||||
writeFileSync(script, `#!/bin/sh\nexec ${command.map(quote).join(' ')} "$@"\n`, { mode: 0o700, flag: 'wx' })
|
||||
chmodSync(script, 0o700)
|
||||
if (process.platform === 'win32') {
|
||||
const literal = (value: string): string => `'${value.replaceAll("'", "''")}'`
|
||||
const args = command.slice(1).map(literal).join(', ')
|
||||
// Windows PowerShell counts escaped quotes when deciding whether to wrap an argument; doubled quotes keep each value enclosed.
|
||||
const nativeArguments = String.raw`$quoteReplacement = if ($PSVersionTable.PSVersion.Major -le 5) { '$1$1""' } else { '$1$1\"' }
|
||||
$nativeArgs = @(foreach ($argument in $commandArgs) {
|
||||
$value = if ($argument -is [array]) { $argument -join ',' } else { [string]$argument }
|
||||
'"' + ($value -replace '(\\*)"', $quoteReplacement -replace '(\\+)$', '$1$1') + '"'
|
||||
})`
|
||||
writeFileSync(`${script}.ps1`, '\ufeff$PSNativeCommandArgumentPassing = \'Legacy\'\n'
|
||||
+ '$OutputEncoding = [System.Text.UTF8Encoding]::new($false)\n'
|
||||
+ `$commandArgs = @(${args}) + $args\n${nativeArguments}\n$global:LASTEXITCODE = 127\n`
|
||||
+ `& ${literal(executable)} @nativeArgs\n`
|
||||
+ 'exit $LASTEXITCODE\n', { flag: 'wx' })
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Publish stable Office commands without preparing interpreters or engines at activation.
|
||||
* @param ctx - Local shell environment.
|
||||
* @param config - Command overrides and interpreter resources.
|
||||
*/
|
||||
export function apply(ctx: Context, config: Config = {}): void {
|
||||
const bundled = process.env.DSH_PRIMARY_RUNTIME ?? process.env.DSH_BUNDLED_PRIMARY_RUNTIME
|
||||
const carrierRuntime = process.env.DSH_BUNDLED_PRIMARY_RUNTIME
|
||||
const node = process.env.DSH_BUNDLED_OFFICE_NODE ?? (carrierRuntime ? join(carrierRuntime, 'dependencies/node/bin', process.platform === 'win32' ? 'node.exe' : 'node') : process.execPath)
|
||||
const assetRoot = config.assetRoot ?? process.env.DSH_BUNDLED_OFFICE_SKILLS ?? (bundled ? join(dirname(bundled), 'office-skills') : fileURLToPath(new URL('../assets/', import.meta.url)))
|
||||
if (!isAbsolute(assetRoot)) throw new Error('office-commands: assetRoot must be an absolute directory')
|
||||
const kit = config.command ?? (process.env.DSH_BUNDLED_OFFICE_CLI === '' ? false : [node, process.env.DSH_BUNDLED_OFFICE_CLI
|
||||
?? join(dirname(fileURLToPath(import.meta.resolve('@deepseek-ai/libreoffice-kit/package.json'))), 'lib/cli.js')])
|
||||
const checker = join(assetRoot, 'scripts/check_office.py')
|
||||
const check = config.checkCommand ?? (bundled
|
||||
? [join(bundled, 'dependencies/python', process.platform === 'win32' ? 'python.exe' : 'bin/python3'), checker]
|
||||
: false)
|
||||
const parent = join(resolveDshHome(), 'commands')
|
||||
mkdirSync(parent, { recursive: true, mode: 0o700 })
|
||||
// Windows mkdtemp needs extended paths; shell PATH keeps ordinary absolute directories.
|
||||
const directory = join(parent, basename(mkdtempSync(toNamespacedPath(join(parent, 'office-')))))
|
||||
const shortcutDirectories: string[] = []
|
||||
const shortCommand = (command: readonly string[]): readonly string[] => {
|
||||
const executable = command[0]
|
||||
if (process.platform !== 'win32' || executable === undefined || executable.length < 260
|
||||
|| !isAbsolute(executable) || !existsSync(toNamespacedPath(dirname(executable)))) return command
|
||||
const shortcutDirectory = mkdtempSync(join(tmpdir(), 'dsh-office-exe-'))
|
||||
shortcutDirectories.push(shortcutDirectory)
|
||||
const junction = join(shortcutDirectory, 'bin')
|
||||
symlinkSync(toNamespacedPath(dirname(executable)), junction, 'junction')
|
||||
return [join(junction, basename(executable)), ...command.slice(1)]
|
||||
}
|
||||
const removeDirectories = () => {
|
||||
rmSync(directory, { recursive: true, force: true })
|
||||
for (const shortcutDirectory of shortcutDirectories) rmSync(shortcutDirectory, { recursive: true, force: true })
|
||||
}
|
||||
try {
|
||||
if (kit !== false) writeLauncher(directory, 'dsoffice', shortCommand(kit))
|
||||
if (check !== false) writeLauncher(directory, 'office-check', shortCommand(check))
|
||||
ctx.effect(() => () => { removeDirectories() })
|
||||
ctx.shellEnv.register({ name, commandDirectories: [directory], variables: {}, resolve: () => ({}) })
|
||||
} catch (error) {
|
||||
removeDirectories()
|
||||
throw error
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
import { readFileSync, statSync } from 'node:fs'
|
||||
import { readFile } from 'node:fs/promises'
|
||||
import { dirname, isAbsolute, join, sep } from 'node:path'
|
||||
import { isSea } from 'node:sea'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import type { Context } from '@deepseek-ai/cordis'
|
||||
import z from '@deepseek-ai/schemastery'
|
||||
@@ -13,13 +14,19 @@ const SKILL_NAMES = ['office', 'office-docx', 'office-pptx', 'office-xlsx', 'off
|
||||
|
||||
/** Office skill resource location. */
|
||||
export interface Config {
|
||||
/** Absolute assets directory containing skill folders and shared scripts; defaults to carrier resources or packaged assets. */
|
||||
/** Absolute assets directory containing skill folders and shared scripts; defaults to packaged assets. */
|
||||
assetRoot?: string
|
||||
/** Standalone Node executable; defaults to the current executable outside Electron and SEA. */
|
||||
node?: string
|
||||
/** Absolute LibreOffice Kit CLI entry; false explicitly disables CLI access. */
|
||||
cli?: string | false
|
||||
}
|
||||
|
||||
/** Validated resource configuration. */
|
||||
export const Config: z<Config> = z.object({
|
||||
assetRoot: z.string().min(1),
|
||||
node: z.string().min(1),
|
||||
cli: z.union([z.string().min(1), z.const(false)]),
|
||||
})
|
||||
|
||||
/** Cordis plugin identity. */
|
||||
@@ -37,18 +44,30 @@ function parseSkill(raw: string, path: string): { description: string; content:
|
||||
return { description, content: raw.slice(frontmatter[0].length).trim() }
|
||||
}
|
||||
|
||||
function resolveAssetRoot(config: Config): string {
|
||||
const bundled = process.env.DSH_PRIMARY_RUNTIME ?? process.env.DSH_BUNDLED_PRIMARY_RUNTIME
|
||||
return config.assetRoot ?? process.env.DSH_BUNDLED_OFFICE_SKILLS ?? (bundled ? join(dirname(bundled), 'office-skills') : fileURLToPath(new URL('../assets/', import.meta.url)))
|
||||
function officeRuntime(config: Config): string {
|
||||
if (config.cli === false) return '\n\nLibreOffice Kit is disabled in this deployment.'
|
||||
if (config.node === undefined && (isSea() || process.versions.electron !== undefined)) {
|
||||
throw new Error('skill-office: packaged applications must supply a standalone Node executable')
|
||||
}
|
||||
const node = config.node ?? process.execPath
|
||||
let cli = config.cli
|
||||
if (cli === undefined) {
|
||||
const manifestPath = fileURLToPath(import.meta.resolve('@deepseek-ai/libreoffice-kit/package.json'))
|
||||
cli = join(dirname(manifestPath), 'lib', 'cli.js')
|
||||
}
|
||||
for (const path of [node, cli]) {
|
||||
if (!isAbsolute(path) || !statSync(path).isFile()) throw new Error(`skill-office: expected an absolute executable file: ${path}`)
|
||||
}
|
||||
return `\n\n## Installed LibreOffice Kit\n\nUse these absolute paths for every LibreOffice Kit command. Pass the CLI entry as the first argument to Node.\n\n${JSON.stringify({ libreofficeKit: { node, cli } }, undefined, 2)}`
|
||||
}
|
||||
|
||||
/**
|
||||
* Register Office skills with resources readable by the script interpreter.
|
||||
* @param ctx - Context carrying the skill registry.
|
||||
* @param input - Optional packaged resource override.
|
||||
* @param config - Optional external assets directory for packaged applications.
|
||||
*/
|
||||
export function apply(ctx: Context, input: Config = {}): void {
|
||||
const assetRoot = resolveAssetRoot(input)
|
||||
export function apply(ctx: Context, config: Config = {}): void {
|
||||
const assetRoot = config.assetRoot ?? fileURLToPath(new URL('../assets/', import.meta.url))
|
||||
if (!isAbsolute(assetRoot)) throw new Error('skill-office: assetRoot must be an absolute directory')
|
||||
if (!statSync(join(assetRoot, 'scripts', 'check_office.py')).isFile()) {
|
||||
throw new Error('skill-office: assets must contain scripts/check_office.py')
|
||||
@@ -71,6 +90,7 @@ export function apply(ctx: Context, input: Config = {}): void {
|
||||
const { rank: _rank, locator, ...summary } = candidate
|
||||
const raw = await readFile(locator as string, { encoding: 'utf8', signal: options.signal })
|
||||
const content = parseSkill(raw, locator as string).content
|
||||
+ (['office-render', 'office-recalculate', 'office-export-pdf'].includes(candidate.name) ? officeRuntime(config) : '')
|
||||
return { ...summary, content }
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
/** Published direct checker launcher smoke; CI supplies built package exports before this keyless lane. */
|
||||
import { existsSync } from 'node:fs'
|
||||
import { copyFile, mkdir, mkdtemp, rm, symlink, writeFile } from 'node:fs/promises'
|
||||
import { tmpdir } from 'node:os'
|
||||
import { dirname, join } from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { execa } from 'execa'
|
||||
import { expect, it } from 'vitest'
|
||||
|
||||
const packageRoot = fileURLToPath(new URL('..', import.meta.url))
|
||||
const built = existsSync(join(packageRoot, 'lib/commands.js'))
|
||||
|
||||
it.skipIf(!built)('runs the emitted direct checker launcher and preserves its arguments and exit status', async () => {
|
||||
const root = await mkdtemp(join(tmpdir(), 'dsh-built-office-'))
|
||||
try {
|
||||
const runtime = join(root, 'runtime'), assets = join(root, 'assets')
|
||||
const python = join(runtime, 'dependencies/python', process.platform === 'win32' ? 'python.exe' : 'bin/python3')
|
||||
await mkdir(dirname(python), { recursive: true })
|
||||
// The fixture executable speaks the checker's argv/exit protocol; the carrier smoke owns Python libraries.
|
||||
if (process.platform === 'win32') await copyFile(process.execPath, python)
|
||||
else await symlink(process.execPath, python)
|
||||
await mkdir(join(assets, 'scripts'), { recursive: true })
|
||||
await writeFile(join(assets, 'scripts/check_office.py'), "require('node:fs').writeFileSync(process.argv[2], JSON.stringify(process.argv.slice(3))); process.exitCode = 7;\n")
|
||||
const script = `
|
||||
import assert from 'node:assert/strict';
|
||||
import { readFile } from 'node:fs/promises';
|
||||
import { delimiter, join } from 'node:path';
|
||||
import { Context } from '@deepseek-ai/cordis';
|
||||
import * as ShellEnv from '@deepseek-ai/dsh-shell-env';
|
||||
import * as Commands from '@deepseek-ai/dsh-skill-office/commands';
|
||||
import { execa } from 'execa';
|
||||
const root = process.argv[1], ctx = new Context();
|
||||
try {
|
||||
await ctx.plugin(ShellEnv);
|
||||
await ctx.plugin(Commands, { command: false, assetRoot: join(root, 'assets') });
|
||||
const env = ctx.shellEnv.collect({ signal: new AbortController().signal, token: Symbol(), callId: 'smoke', rootCallId: 'smoke', name: 'bash', arguments: {} });
|
||||
const directory = env.PATH.split(delimiter)[0];
|
||||
const launcher = join(directory, process.platform === 'win32' ? 'office-check.ps1' : 'office-check');
|
||||
const source = await readFile(launcher, 'utf8');
|
||||
assert(source.includes('check_office.py'));
|
||||
assert(!source.includes('check.js'));
|
||||
assert(!source.includes('tsx'));
|
||||
const args = [join(root, 'arguments.json'), 'space and 中文', "apostrophe'value"];
|
||||
if (process.platform === 'win32') {
|
||||
const { LocalSubprocessRuntime } = await import('@deepseek-ai/dsh-subprocess-local');
|
||||
const { PwshLocalExecutor } = await import('@deepseek-ai/dsh-pwsh-local');
|
||||
await ctx.plugin(LocalSubprocessRuntime);
|
||||
await ctx.plugin(PwshLocalExecutor, { pwshPath: 'powershell.exe' });
|
||||
const command = 'office-check ' + args.map(value => "'" + value.replaceAll("'", "''") + "'").join(' ') + '; exit $LASTEXITCODE';
|
||||
const result = await (await ctx.shell.execute(ctx.shell.resolve({ command,
|
||||
env: { PSExecutionPolicyPreference: 'Restricted' }, dshEnv: env }))).result();
|
||||
assert.equal(result.exitCode, 7, result.stderr.text);
|
||||
} else {
|
||||
const result = await execa(launcher, args, { env, reject: false });
|
||||
assert.equal(result.exitCode, 7, result.stderr);
|
||||
}
|
||||
assert.deepEqual(JSON.parse(await readFile(args[0], 'utf8')), args.slice(1));
|
||||
process.stdout.write('built checker passed');
|
||||
} finally { await ctx.fiber.dispose(); }
|
||||
`
|
||||
const result = await execa(process.execPath, ['--input-type=module', '-e', script, root], {
|
||||
cwd: packageRoot,
|
||||
env: {
|
||||
DSH_HOME: join(root, 'home'), DSH_PRIMARY_RUNTIME: runtime, DSH_BUNDLED_PRIMARY_RUNTIME: '',
|
||||
NODE_OPTIONS: '', TSX_TSCONFIG_PATH: '',
|
||||
},
|
||||
timeout: 30_000, killSignal: 'SIGKILL', reject: false,
|
||||
})
|
||||
expect(result.timedOut, result.stderr).toBe(false)
|
||||
expect(result.signal, result.stderr).toBeUndefined()
|
||||
expect(result.exitCode, result.stderr).toBe(0)
|
||||
expect(result.stdout).toBe('built checker passed')
|
||||
} finally {
|
||||
await rm(root, { recursive: true, force: true })
|
||||
}
|
||||
})
|
||||
@@ -1,265 +0,0 @@
|
||||
/** Shell command discovery, argument preservation, and launcher ownership. */
|
||||
import { copyFile, mkdir, mkdtemp, readFile, readdir, rm, writeFile } from 'node:fs/promises'
|
||||
import { tmpdir } from 'node:os'
|
||||
import { delimiter, dirname, join, toNamespacedPath } from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { Context } from '@deepseek-ai/cordis'
|
||||
import { ToolCallId } from '@deepseek-ai/dsh-llm'
|
||||
import * as ShellEnv from '@deepseek-ai/dsh-shell-env'
|
||||
import type { ToolExecution } from '@deepseek-ai/dsh-tools'
|
||||
import { execa } from 'execa'
|
||||
import { afterEach, beforeEach, expect, it, vi } from 'vitest'
|
||||
import * as Commands from '../src/commands.ts'
|
||||
|
||||
const contexts: Context[] = []
|
||||
let root: string
|
||||
const execution: ToolExecution = {
|
||||
signal: new AbortController().signal,
|
||||
token: Symbol('office-command') as ToolExecution['token'],
|
||||
callId: ToolCallId('office-command'), rootCallId: ToolCallId('office-command'),
|
||||
name: 'bash', arguments: { command: 'dsoffice capabilities' },
|
||||
}
|
||||
|
||||
beforeEach(async () => {
|
||||
root = await mkdtemp(join(tmpdir(), 'dsh-office-commands-'))
|
||||
vi.stubEnv('DSH_HOME', root)
|
||||
for (const key of ['DSH_PRIMARY_RUNTIME', 'DSH_BUNDLED_PRIMARY_RUNTIME', 'DSH_BUNDLED_OFFICE_CLI', 'DSH_BUNDLED_OFFICE_NODE', 'DSH_BUNDLED_OFFICE_SKILLS']) vi.stubEnv(key, undefined)
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
for (const ctx of contexts.splice(0)) await ctx.fiber.dispose()
|
||||
vi.unstubAllEnvs()
|
||||
await rm(root, { recursive: true, force: true })
|
||||
})
|
||||
|
||||
async function context() {
|
||||
const ctx = new Context()
|
||||
contexts.push(ctx)
|
||||
await ctx.plugin(ShellEnv)
|
||||
return ctx
|
||||
}
|
||||
|
||||
function directory(ctx: Context): string {
|
||||
const path = ctx.shellEnv.collect(execution).PATH
|
||||
if (path === undefined) throw new Error('Missing Office command directory')
|
||||
return path.split(delimiter)[0]!
|
||||
}
|
||||
|
||||
it.skipIf(process.platform === 'win32')('executes the installed capabilities command without Node on PATH', async () => {
|
||||
vi.stubEnv('PATH', '')
|
||||
const ctx = await context()
|
||||
await ctx.plugin(Commands)
|
||||
const env = ctx.shellEnv.collect(execution)
|
||||
const result = await execa('dsoffice', ['capabilities'], { cwd: root, env, extendEnv: false })
|
||||
expect(JSON.parse(result.stdout)).toMatchObject({ runtime: {
|
||||
cliPath: fileURLToPath(import.meta.resolve('@deepseek-ai/libreoffice-kit/cli')),
|
||||
} })
|
||||
expect(process.env.PATH).toBe('')
|
||||
expect(await readdir(root)).toEqual(['commands'])
|
||||
await expect(readFile(join(directory(ctx), 'office-check'))).rejects.toMatchObject({ code: 'ENOENT' })
|
||||
})
|
||||
|
||||
it.skipIf(process.platform === 'win32')('preserves configured and forwarded shell arguments literally', async () => {
|
||||
const ctx = await context()
|
||||
const fixed = ['', "apostrophe' and space", '$(printf substituted)', '`printf substituted`', '%PATH%', 'double"quote']
|
||||
const command = [process.execPath, '-e', 'process.stdout.write(JSON.stringify(process.argv.slice(1)))', ...fixed]
|
||||
await ctx.plugin(Commands, { command, checkCommand: command })
|
||||
for (const name of ['dsoffice', 'office-check']) {
|
||||
const result = await execa(join(directory(ctx), name), ['forwarded value', ''], { env: { PATH: '' }, extendEnv: false })
|
||||
expect(JSON.parse(result.stdout)).toEqual([...fixed, 'forwarded value', ''])
|
||||
}
|
||||
})
|
||||
|
||||
it('owns separate launcher directories under a long home until each contributing context is disposed', async () => {
|
||||
const home = join(root, 'a'.repeat(120), 'b'.repeat(120))
|
||||
vi.stubEnv('DSH_HOME', home)
|
||||
expect(home.length).toBeGreaterThan(260)
|
||||
const first = await context(), second = await context()
|
||||
const [one, two] = await Promise.all([
|
||||
first.plugin(Commands, { command: false, checkCommand: false }),
|
||||
second.plugin(Commands, { command: false, checkCommand: false }),
|
||||
])
|
||||
const firstDirectory = directory(first), secondDirectory = directory(second)
|
||||
expect(firstDirectory).not.toBe(secondDirectory)
|
||||
expect(dirname(firstDirectory)).toBe(join(home, 'commands'))
|
||||
expect(dirname(secondDirectory)).toBe(join(home, 'commands'))
|
||||
await one.dispose()
|
||||
await expect(readdir(firstDirectory)).rejects.toMatchObject({ code: 'ENOENT' })
|
||||
expect(first.shellEnv.collect(execution)).not.toHaveProperty('PATH')
|
||||
expect(await readdir(secondDirectory)).toEqual([])
|
||||
await two.dispose()
|
||||
await expect(readdir(secondDirectory)).rejects.toMatchObject({ code: 'ENOENT' })
|
||||
})
|
||||
|
||||
it('defers missing executable failures to invocation and permits each command to be disabled', async () => {
|
||||
const ctx = await context()
|
||||
await ctx.plugin(Commands, { command: [join(root, 'missing-kit')], checkCommand: false })
|
||||
const files = await readdir(directory(ctx))
|
||||
expect(files.sort()).toEqual(process.platform === 'win32' ? ['dsoffice', 'dsoffice.ps1'] : ['dsoffice'])
|
||||
const disabled = await context()
|
||||
await disabled.plugin(Commands, { command: false, checkCommand: [join(root, 'missing-python')] })
|
||||
expect(await readdir(directory(disabled))).toContain('office-check')
|
||||
})
|
||||
|
||||
it.each([[], ['relative-command'], [process.execPath, 'line\nbreak'], [process.execPath, 'nul\0byte']].map(command => ({ command })))(
|
||||
'rejects an invalid command and removes its partial directory: $command', async ({ command }) => {
|
||||
const ctx = await context()
|
||||
expect(() => { Commands.apply(ctx, { command: [process.execPath], checkCommand: command }) })
|
||||
.toThrow(/absolute executable|NUL or newlines/)
|
||||
expect(await readdir(join(root, 'commands'))).toEqual([])
|
||||
expect(ctx.shellEnv.collect(execution)).not.toHaveProperty('PATH')
|
||||
},
|
||||
)
|
||||
|
||||
it('rejects relative asset roots before publishing commands', async () => {
|
||||
const ctx = await context()
|
||||
expect(() => { Commands.apply(ctx, { assetRoot: 'relative-assets' }) }).toThrow('assetRoot must be an absolute directory')
|
||||
expect(ctx.shellEnv.collect(execution)).not.toHaveProperty('PATH')
|
||||
expect(await readdir(root)).toEqual([])
|
||||
})
|
||||
|
||||
it('runs Kit with the host Node when the selected authoring environment contains only Python', async () => {
|
||||
vi.stubEnv('DSH_PRIMARY_RUNTIME', join(root, 'python-only'))
|
||||
const ctx = await context()
|
||||
await ctx.plugin(Commands)
|
||||
const result = await execa(process.execPath, [fileURLToPath(import.meta.resolve('@deepseek-ai/libreoffice-kit/cli')), 'capabilities'], {
|
||||
cwd: root, env: { ...ctx.shellEnv.collect(execution), PATH: directory(ctx) }, extendEnv: false,
|
||||
})
|
||||
expect(JSON.parse(result.stdout)).toHaveProperty('runtime.cliPath')
|
||||
expect(await readFile(join(directory(ctx), 'dsoffice'), 'utf8')).toContain(process.execPath)
|
||||
expect(await readFile(join(directory(ctx), 'office-check'), 'utf8')).toContain(join(root, 'python-only/dependencies/python'))
|
||||
})
|
||||
|
||||
it.each(['win32', 'linux'])('uses bundled interpreters and explicit resources without preparing the payload on %s', async (platformName) => {
|
||||
const platform = Object.getOwnPropertyDescriptor(process, 'platform')!
|
||||
Object.defineProperty(process, 'platform', { value: platformName })
|
||||
try {
|
||||
const bundled = join(root, 'carrier', 'primary-runtime')
|
||||
const cli = join(root, 'carrier', 'kit-cli.js'), assets = join(root, 'custom-assets')
|
||||
vi.stubEnv('DSH_BUNDLED_PRIMARY_RUNTIME', bundled)
|
||||
vi.stubEnv('DSH_BUNDLED_OFFICE_CLI', cli)
|
||||
const ctx = await context()
|
||||
await ctx.plugin(Commands, { assetRoot: assets })
|
||||
const kit = await readFile(join(directory(ctx), 'dsoffice'), 'utf8')
|
||||
expect(kit).toContain(cli)
|
||||
expect(kit).toContain(join(bundled, 'dependencies/node/bin', platformName === 'win32' ? 'node.exe' : 'node'))
|
||||
const checker = await readFile(join(directory(ctx), 'office-check'), 'utf8')
|
||||
expect(checker).toContain(join(bundled, 'dependencies/python', platformName === 'win32' ? 'python.exe' : 'bin/python3'))
|
||||
expect(checker).toContain(join(assets, 'scripts/check_office.py'))
|
||||
await expect(readdir(join(root, 'carrier'))).rejects.toMatchObject({ code: 'ENOENT' })
|
||||
} finally {
|
||||
Object.defineProperty(process, 'platform', platform)
|
||||
}
|
||||
})
|
||||
|
||||
it('writes PowerShell launchers with literal arguments and the selected checker environment', async () => {
|
||||
const ctx = await context()
|
||||
const platform = Object.getOwnPropertyDescriptor(process, 'platform')!
|
||||
Object.defineProperty(process, 'platform', { value: 'win32' })
|
||||
try {
|
||||
const bundled = join(root, 'primary-runtime')
|
||||
vi.stubEnv('DSH_BUNDLED_PRIMARY_RUNTIME', bundled)
|
||||
Commands.apply(ctx, { command: [process.execPath, 'percent%value', 'double"quote', "apostrophe'value"] })
|
||||
const launcher = await readFile(join(directory(ctx), 'dsoffice.ps1'))
|
||||
expect([...launcher.subarray(0, 3)]).toEqual([0xef, 0xbb, 0xbf])
|
||||
expect(launcher.toString('utf8')).toContain("$commandArgs = @('percent%value', 'double\"quote', 'apostrophe''value') + $args")
|
||||
expect(launcher.toString('utf8')).toContain("$PSNativeCommandArgumentPassing = 'Legacy'")
|
||||
expect(await readFile(join(directory(ctx), 'office-check.ps1'), 'utf8')).toContain('python.exe')
|
||||
} finally {
|
||||
Object.defineProperty(process, 'platform', platform)
|
||||
}
|
||||
})
|
||||
|
||||
it('removes short executable paths without removing the original interpreter', async () => {
|
||||
const platform = Object.getOwnPropertyDescriptor(process, 'platform')!
|
||||
Object.defineProperty(process, 'platform', { value: 'win32' })
|
||||
try {
|
||||
const runtime = join(root, 'a'.repeat(120), 'b'.repeat(120))
|
||||
await mkdir(toNamespacedPath(runtime), { recursive: true })
|
||||
const node = join(runtime, 'node.exe')
|
||||
expect(node.length).toBeGreaterThan(260)
|
||||
await writeFile(toNamespacedPath(node), 'fixture')
|
||||
const ctx = await context()
|
||||
const commands = await ctx.plugin(Commands, { command: [node], checkCommand: false })
|
||||
const launcher = await readFile(join(directory(ctx), 'dsoffice.ps1'), 'utf8')
|
||||
const shortNode = /& '([^']+)' @nativeArgs/u.exec(launcher)?.[1]
|
||||
if (shortNode === undefined) throw new Error('Missing executable path in the PowerShell launcher')
|
||||
expect(shortNode).not.toBe(node)
|
||||
expect(await readFile(shortNode, 'utf8')).toBe('fixture')
|
||||
await commands.dispose()
|
||||
await expect(readFile(shortNode)).rejects.toMatchObject({ code: 'ENOENT' })
|
||||
expect(await readFile(toNamespacedPath(node), 'utf8')).toBe('fixture')
|
||||
} finally {
|
||||
Object.defineProperty(process, 'platform', platform)
|
||||
}
|
||||
})
|
||||
|
||||
it.skipIf(process.platform !== 'win32').each([undefined, 'powershell.exe'])(
|
||||
'preserves native arguments through the Windows shell executor: %s', async (pwshPath) => {
|
||||
const { LocalSubprocessRuntime } = await import('@deepseek-ai/dsh-subprocess-local')
|
||||
const { PwshLocalExecutor } = await import('@deepseek-ai/dsh-pwsh-local')
|
||||
const runtime = join(root, 'runtime 中文', 'a'.repeat(220))
|
||||
await mkdir(toNamespacedPath(runtime), { recursive: true })
|
||||
const node = join(runtime, 'node.exe'), fixture = join(runtime, 'arguments.mjs')
|
||||
expect(node.length).toBeGreaterThan(260)
|
||||
await copyFile(process.execPath, toNamespacedPath(node))
|
||||
await writeFile(toNamespacedPath(fixture), "process.stdout.write(JSON.stringify({ args: process.argv.slice(2) })); process.stderr.write('fixture stderr'); process.exitCode = 7;\n")
|
||||
const argumentsToPreserve = ['', 'space and 中文', "apostrophe'value", 'double"quote', 'quote" with space',
|
||||
'slash\\" quote', 'trailing\\', 'space trailing\\', '%PATH%', '!literal!', '&<|>']
|
||||
const quoted = argumentsToPreserve.map(value => `'${value.replaceAll("'", "''")}'`).join(' ')
|
||||
if (pwshPath === undefined) vi.stubEnv('DSH_HOME', join(root, 'a'.repeat(120), 'b'.repeat(120)))
|
||||
const ctx = await context()
|
||||
await ctx.plugin(LocalSubprocessRuntime)
|
||||
await ctx.plugin(PwshLocalExecutor, pwshPath === undefined ? {} : { pwshPath })
|
||||
const commands = await ctx.plugin(Commands, { command: [node, fixture, ...argumentsToPreserve], checkCommand: false })
|
||||
const commandDirectory = directory(ctx)
|
||||
if (pwshPath === undefined) expect(commandDirectory.length).toBeGreaterThan(260)
|
||||
const result = await (await ctx.shell.execute(ctx.shell.resolve({
|
||||
command: `dsoffice ${quoted}; exit $LASTEXITCODE`,
|
||||
env: { PSExecutionPolicyPreference: 'Restricted' }, dshEnv: ctx.shellEnv.collect(execution),
|
||||
}))).result()
|
||||
expect(result.exitCode, result.stderr.text).toBe(7)
|
||||
expect(result.stderr.text).toContain('fixture stderr')
|
||||
const output = JSON.parse(result.stdout.text) as { args: string[] }
|
||||
expect(output.args).toEqual([...argumentsToPreserve, ...argumentsToPreserve])
|
||||
const pages = await (await ctx.shell.execute(ctx.shell.resolve({
|
||||
command: 'dsoffice --pages 1,3,4; exit $LASTEXITCODE',
|
||||
dshEnv: ctx.shellEnv.collect(execution),
|
||||
}))).result()
|
||||
expect(pages.exitCode, pages.stderr.text).toBe(7)
|
||||
expect((JSON.parse(pages.stdout.text) as { args: string[] }).args).toEqual([...argumentsToPreserve, '--pages', '1,3,4'])
|
||||
await commands.dispose()
|
||||
await expect(readdir(commandDirectory)).rejects.toMatchObject({ code: 'ENOENT' })
|
||||
expect(ctx.shellEnv.collect(execution)).not.toHaveProperty('PATH')
|
||||
},
|
||||
)
|
||||
|
||||
it.skipIf(process.platform !== 'win32')('reports a missing Windows executable as a failed shell command', async () => {
|
||||
const { LocalSubprocessRuntime } = await import('@deepseek-ai/dsh-subprocess-local')
|
||||
const { PwshLocalExecutor } = await import('@deepseek-ai/dsh-pwsh-local')
|
||||
const ctx = await context()
|
||||
await ctx.plugin(LocalSubprocessRuntime)
|
||||
await ctx.plugin(PwshLocalExecutor, { pwshPath: 'powershell.exe' })
|
||||
await ctx.plugin(Commands, { command: [join(root, 'missing.exe')], checkCommand: false })
|
||||
const result = await (await ctx.shell.execute(ctx.shell.resolve({
|
||||
command: 'dsoffice --pages 1,3,4; exit $LASTEXITCODE',
|
||||
dshEnv: ctx.shellEnv.collect(execution),
|
||||
}))).result()
|
||||
expect(result.exitCode).toBe(127)
|
||||
expect(result.stderr.text).toContain('missing.exe')
|
||||
})
|
||||
|
||||
it('uses the downloaded sidecar Node and disables Kit for an authoring-only carrier', async () => {
|
||||
const node = join(root, 'sidecar/node'), cli = join(root, 'sidecar/cli.js')
|
||||
vi.stubEnv('DSH_BUNDLED_OFFICE_NODE', node)
|
||||
vi.stubEnv('DSH_BUNDLED_OFFICE_CLI', cli)
|
||||
const ctx = await context()
|
||||
await ctx.plugin(Commands)
|
||||
const launcher = await readFile(join(directory(ctx), 'dsoffice'), 'utf8')
|
||||
expect(launcher).toContain(node)
|
||||
expect(launcher).toContain(cli)
|
||||
vi.stubEnv('DSH_BUNDLED_OFFICE_CLI', '')
|
||||
const disabled = await context()
|
||||
await disabled.plugin(Commands)
|
||||
expect(await readdir(directory(disabled))).toEqual([])
|
||||
})
|
||||
@@ -94,7 +94,7 @@ it.each(['office-render', 'office-recalculate', 'office-export-pdf'])('loads %s
|
||||
const { agent, adapter } = await setup('native', [name])
|
||||
await send(agent)
|
||||
const loaded = JSON.stringify(adapter.requests.at(-1))
|
||||
expect(loaded).toContain('dsoffice')
|
||||
expect(loaded).toContain('libreofficeKit')
|
||||
expect(loaded).not.toContain('Office task routing')
|
||||
expect(loaded).not.toContain('# Word documents')
|
||||
if (name !== 'office-render') expect(loaded).not.toMatch(/render --input|uniformly blank|fragment rectangles|DPI/)
|
||||
|
||||
@@ -23,7 +23,6 @@ async function prepareOffice(cwd: string) {
|
||||
await writeFile(join(cwd, 'office.patch.json'), JSON.stringify([
|
||||
...officeModelPatches(),
|
||||
{ insert: [{ id: 'skill-office', name: '@deepseek-ai/dsh-skill-office', config: { assetRoot: join(repo, 'packages/skill/skill-office/assets') } }] },
|
||||
{ insert: [{ id: 'office-commands', name: '@deepseek-ai/dsh-skill-office/commands', config: { assetRoot: join(repo, 'packages/skill/skill-office/assets') } }] },
|
||||
{ insert: [{ id: 'workspace-dependencies', name: '@deepseek-ai/dsh-tool-workspace-dependencies', config: { source: runtime! } }] },
|
||||
{ id: 'session-persistence-jsonl', config: { root: join(cwd, '.sessions'), compression: 'none' } },
|
||||
]))
|
||||
@@ -58,7 +57,7 @@ it.skipIf(!process.env.DEEPSEEK_API_KEY || !runtime).each([{ format: 'docx', mod
|
||||
const skills = calls.filter(call => call.name === 'skill').map(call => JSON.parse(call.arguments) as { name: string })
|
||||
expect(skills.some(skill => skill.name === 'office-render'), JSON.stringify(skills)).toBe(true)
|
||||
const commands = calls.filter(call => call.name === 'bash' || call.name === 'pwsh').map(call => (JSON.parse(call.arguments) as { command: string }).command).join('\n')
|
||||
expect(commands).toMatch(/\bdsoffice["']?\s+render\b/u)
|
||||
expect(commands).toMatch(/\srender\b/u)
|
||||
expect(commands).toContain('--pages')
|
||||
expect(commands).toContain('--output-dir')
|
||||
const pixels = await execa(python!, ['-c', "from pathlib import Path\nfrom PIL import Image\nfiles=list(Path('preview').glob('*.png'))\nassert files\nfor f in files:\n im=Image.open(f).convert('RGBA')\n visible=Image.alpha_composite(Image.new('RGBA',im.size,'white'),im).convert('RGB')\n print('content' if any(a!=b for a,b in visible.getextrema()) else 'blank')"], { cwd })
|
||||
@@ -67,7 +66,7 @@ it.skipIf(!process.env.DEEPSEEK_API_KEY || !runtime).each([{ format: 'docx', mod
|
||||
const authoring = calls.findIndex(call => call.name === 'skill' && /office-(docx|pptx|xlsx)/u.test(call.arguments))
|
||||
if (pixels.stdout.includes('blank')) {
|
||||
if (authoring !== -1) {
|
||||
const rendered = calls.findIndex(call => (call.name === 'bash' || call.name === 'pwsh') && /\bdsoffice["']?\s+render\b/u.test(call.arguments))
|
||||
const rendered = calls.findIndex(call => (call.name === 'bash' || call.name === 'pwsh') && /\srender\b/u.test(call.arguments))
|
||||
expect(authoring, 'content checks after a blank preview may need the format skill').toBeGreaterThan(rendered)
|
||||
}
|
||||
const final = events.filter(e => e.type === 'assistant/message').at(-1)?.data.message.content
|
||||
@@ -122,8 +121,8 @@ it.skipIf(!process.env.DEEPSEEK_API_KEY || !runtime)('exports PDF through the op
|
||||
expect(skills.some(name => ['office-docx', 'office-pptx', 'office-xlsx'].includes(name))).toBe(false)
|
||||
const commands = calls.filter(call => call.name === 'bash' || call.name === 'pwsh')
|
||||
.map(call => (JSON.parse(call.arguments) as { command: string }).command).join('\n')
|
||||
expect(commands).toMatch(/\bdsoffice["']?\s+convert\b/u)
|
||||
expect(commands).not.toMatch(/\bdsoffice["']?\s+render\b/u)
|
||||
expect(commands).toMatch(/\sconvert\b/u)
|
||||
expect(commands).not.toMatch(/\srender\b/u)
|
||||
expect((await readFile(join(cwd, 'result.pdf'))).subarray(0, 5).toString()).toBe('%PDF-')
|
||||
expect(await readFile(join(cwd, 'input.docx'))).toEqual(original)
|
||||
},
|
||||
|
||||
@@ -7,8 +7,12 @@ import Loader from '@deepseek-ai/cordis-plugin-loader'
|
||||
import Include from '@deepseek-ai/cordis-plugin-include'
|
||||
import SkillRegistry from '@deepseek-ai/dsh-skill'
|
||||
import * as SkillOffice from '@deepseek-ai/dsh-skill-office'
|
||||
import { isSea } from 'node:sea'
|
||||
import { execa } from 'execa'
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
|
||||
vi.mock('node:sea', () => ({ isSea: vi.fn(() => false) }))
|
||||
|
||||
const assets = fileURLToPath(new URL('../assets/', import.meta.url))
|
||||
const names = ['office', 'office-docx', 'office-export-pdf', 'office-pptx', 'office-recalculate', 'office-render', 'office-xlsx']
|
||||
|
||||
@@ -47,7 +51,8 @@ describe('bundled Office skills', () => {
|
||||
expect(loaded?.resourceBase).toEqual({ kind: 'directory', path: join(assets, skill.name).split(sep).join('/') })
|
||||
const raw = await readFile(join(assets, skill.name, 'SKILL.md'), 'utf8')
|
||||
const body = raw.replace(/^---\r?\n[\s\S]*?\r?\n---\r?\n/u, '').trim()
|
||||
expect(loaded?.content).toBe(body)
|
||||
expect(loaded?.content.startsWith(body)).toBe(true)
|
||||
if (!['office-render', 'office-recalculate', 'office-export-pdf'].includes(skill.name)) expect(loaded?.content).toBe(body)
|
||||
}
|
||||
await fiber.dispose()
|
||||
expect(await ctx.skills.list()).toEqual([])
|
||||
@@ -103,27 +108,6 @@ describe('bundled Office skills', () => {
|
||||
}
|
||||
})
|
||||
|
||||
it.each([false, true])('loads carrier resources without its interpreters or renderer (explicit resources: %s)', async (explicit) => {
|
||||
const root = await mkdtemp(join(tmpdir(), 'dsh-office-carrier-'))
|
||||
const ctx = new Context()
|
||||
try {
|
||||
const relocated = join(root, 'office-skills')
|
||||
await cp(assets, relocated, { recursive: true })
|
||||
vi.stubEnv('DSH_PRIMARY_RUNTIME', undefined)
|
||||
vi.stubEnv('DSH_BUNDLED_PRIMARY_RUNTIME', explicit ? undefined : join(root, 'primary-runtime'))
|
||||
vi.stubEnv('DSH_BUNDLED_OFFICE_SKILLS', explicit ? relocated : undefined)
|
||||
await ctx.plugin(SkillRegistry)
|
||||
await ctx.plugin(SkillOffice)
|
||||
for (const name of names) {
|
||||
expect((await ctx.skills.get(name))?.resourceBase).toEqual({ kind: 'directory', path: join(relocated, name).split(sep).join('/') })
|
||||
}
|
||||
} finally {
|
||||
vi.unstubAllEnvs()
|
||||
await ctx.fiber.dispose()
|
||||
await rm(root, { recursive: true, force: true })
|
||||
}
|
||||
})
|
||||
|
||||
it.each([
|
||||
['description: "Quoted: description"', '\r\n', 'Quoted: description'],
|
||||
['description: >-\n Folded\n description', '\n', 'Folded description'],
|
||||
@@ -170,3 +154,58 @@ describe('bundled Office skills', () => {
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('executes capabilities using only paths returned by the loaded skill from a separate workspace', async () => {
|
||||
const root = await mkdtemp(join(tmpdir(), 'office CLI 工作目录 '))
|
||||
const ctx = new Context()
|
||||
try {
|
||||
await ctx.plugin(SkillRegistry)
|
||||
await ctx.plugin(SkillOffice)
|
||||
const skill = await ctx.skills.get('office-render')
|
||||
const json = skill?.content.match(/\n(\{\n[\s\S]+)$/u)?.[1]
|
||||
expect(json).toBeDefined()
|
||||
const { libreofficeKit } = JSON.parse(json!) as { libreofficeKit: { node: string; cli: string } }
|
||||
const result = await execa(libreofficeKit.node, [libreofficeKit.cli, 'capabilities'], {
|
||||
cwd: root, env: { PATH: '' }, timeout: 20_000, killSignal: 'SIGKILL', reject: false,
|
||||
})
|
||||
expect(result.timedOut, result.stderr).toBe(false)
|
||||
expect(result.signal, result.stderr).toBeUndefined()
|
||||
expect(result.exitCode, result.stderr).toBe(0)
|
||||
expect(JSON.parse(result.stdout)).toMatchObject({ runtime: { version: '0.1.5', cliPath: libreofficeKit.cli } })
|
||||
} finally {
|
||||
await ctx.fiber.dispose()
|
||||
await rm(root, { recursive: true, force: true })
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
it('validates operation paths on loading while authoring remains available', async () => {
|
||||
const ctx = new Context()
|
||||
const original = Object.getOwnPropertyDescriptor(process.versions, 'electron')
|
||||
try {
|
||||
await ctx.plugin(SkillRegistry)
|
||||
for (const config of [{ node: 'node' }, { cli: 'cli.js' }, { node: assets }, { cli: assets }, { cli: join(assets, 'missing.js') }]) {
|
||||
const fiber = await ctx.plugin(SkillOffice, config)
|
||||
expect((await ctx.skills.get('office-docx'))?.content).toContain('python-docx')
|
||||
await expect(ctx.skills.get('office-render')).rejects.toThrow()
|
||||
await fiber.dispose()
|
||||
}
|
||||
const carrier = await ctx.plugin(SkillOffice)
|
||||
vi.mocked(isSea).mockReturnValue(true)
|
||||
await expect(ctx.skills.get('office-render')).rejects.toThrow('standalone Node')
|
||||
vi.mocked(isSea).mockReturnValue(false)
|
||||
Object.defineProperty(process.versions, 'electron', { value: '44.0.0', configurable: true })
|
||||
await expect(ctx.skills.get('office-render')).rejects.toThrow('standalone Node')
|
||||
await carrier.dispose()
|
||||
const disabled = await ctx.plugin(SkillOffice, { cli: false })
|
||||
expect((await ctx.skills.get('office-render'))?.content).toContain('disabled in this deployment')
|
||||
await disabled.dispose()
|
||||
await ctx.plugin(SkillOffice, { node: process.execPath })
|
||||
expect((await ctx.skills.get('office-render'))?.content).toContain(JSON.stringify(process.execPath))
|
||||
} finally {
|
||||
vi.mocked(isSea).mockReturnValue(false)
|
||||
if (original === undefined) Reflect.deleteProperty(process.versions, 'electron')
|
||||
else Object.defineProperty(process.versions, 'electron', original)
|
||||
await ctx.fiber.dispose()
|
||||
}
|
||||
})
|
||||
@@ -84,8 +84,7 @@ it.skipIf(!process.env.DEEPSEEK_API_KEY || !runtime).each(cases)('$format $kind
|
||||
const fixture = await renderCliFixture(controlRoot, python!, intent === 'blank', callLogPath)
|
||||
const testAssetRoot = process.env.DSH_OFFICE_TEST_ASSET_ROOT ?? assetRoot
|
||||
await writeFile(configPath, JSON.stringify([
|
||||
{ insert: [{ id: 'skill-office', name: '@deepseek-ai/dsh-skill-office', config: { assetRoot: testAssetRoot } }] },
|
||||
{ insert: [{ id: 'office-commands', name: '@deepseek-ai/dsh-skill-office/commands', config: { assetRoot: testAssetRoot, command: [process.execPath, fixture.cli] } }] },
|
||||
{ insert: [{ id: 'skill-office', name: '@deepseek-ai/dsh-skill-office', config: { assetRoot: testAssetRoot, node: process.execPath, cli: fixture.cli } }] },
|
||||
{ insert: [{ id: 'workspace-dependencies', name: '@deepseek-ai/dsh-tool-workspace-dependencies', config: { source: runtime! } }] },
|
||||
...officeModelPatches(),
|
||||
{ id: 'session-persistence-jsonl', config: { root: sessionRoot, compression: 'none' } },
|
||||
|
||||
@@ -99,8 +99,7 @@ describe.skipIf(!process.env.DEEPSEEK_API_KEY || !runtime).each(['native', 'ptc'
|
||||
const fixture = kind === 'blank' || kind === 'formula'
|
||||
? await renderCliFixture(controlRoot, python!, kind === 'blank') : undefined
|
||||
await writeFile(configPath, JSON.stringify([
|
||||
{ insert: [{ id: 'skill-office', name: '@deepseek-ai/dsh-skill-office', config: { assetRoot } }] },
|
||||
{ insert: [{ id: 'office-commands', name: '@deepseek-ai/dsh-skill-office/commands', config: { assetRoot, ...fixture ? { command: [process.execPath, fixture.cli] } : {} } }] },
|
||||
{ insert: [{ id: 'skill-office', name: '@deepseek-ai/dsh-skill-office', config: { assetRoot, node: process.execPath, ...fixture ? { cli: fixture.cli } : {} } }] },
|
||||
{ insert: [{ id: 'workspace-dependencies', name: '@deepseek-ai/dsh-tool-workspace-dependencies', config: { source: runtime! } }] },
|
||||
...officeModelPatches(),
|
||||
{ id: 'attachment-local', config: { dshHome: imageRoot } },
|
||||
@@ -187,16 +186,16 @@ else:
|
||||
? answer.data.message.content.flatMap(block => block.type === 'text' ? [block.text] : []).join('\n').slice(0, 800) : undefined })
|
||||
expect(loaded, diagnostic).toContain('office-xlsx')
|
||||
expect(calls.some(call => call.name === 'load_workspace_dependencies'), diagnostic).toBe(true)
|
||||
expect(commands, diagnostic).toContain('office-check')
|
||||
expect(commands, diagnostic).toContain('check_office.py')
|
||||
if (kind === 'formula') {
|
||||
expect(loaded, diagnostic).toContain('office-recalculate')
|
||||
}
|
||||
if (kind === 'layout' || kind === 'blank') {
|
||||
expect(calls.some(call => call.name === 'skill' && call.arguments.includes('office-render'))).toBe(true)
|
||||
expect(commands).toMatch(/\bdsoffice["']?\s+render\b/u)
|
||||
expect(commands).toMatch(/\srender\b/u)
|
||||
expect(commands).toContain('--sheet')
|
||||
expect(commands).toContain('--range')
|
||||
expect(commands).not.toMatch(/\bdsoffice["']?\s+convert\b/u)
|
||||
expect(commands).not.toMatch(/\sconvert\b/u)
|
||||
const reads = calls.filter(call => call.name === 'read_image')
|
||||
const results = events.flatMap(event => event.type === 'tool/result' ? [event.data.message] : [])
|
||||
if (previewHasContent) {
|
||||
|
||||
@@ -19,12 +19,6 @@
|
||||
},
|
||||
{
|
||||
"path": "../skill"
|
||||
},
|
||||
{
|
||||
"path": "../../shell/shell-env"
|
||||
},
|
||||
{
|
||||
"path": "../../util/home-paths"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
import { defineConfig } from 'tsdown'
|
||||
|
||||
export default defineConfig({
|
||||
entry: { index: 'lib/types/index.js', commands: 'lib/types/commands.js' },
|
||||
outDir: 'lib', format: ['esm'], platform: 'node', target: 'es2024',
|
||||
fixedExtension: false, dts: false, clean: false,
|
||||
})
|
||||
@@ -1,2 +0,0 @@
|
||||
/** Resolve the SDK provider from its owning package for external profile fixtures. */
|
||||
export { Config, apply, inject, name } from '@deepseek-ai/dsh-subagent-dsh-sdk'
|
||||
@@ -36,8 +36,8 @@
|
||||
en: e3631497344c2ebd
|
||||
zh: c4ebc7b08f0a316e
|
||||
/deepseek-ai-dsh-subprocess/use-this-package/environment-every-child-starts-from:
|
||||
en: ad39aefe049a3ce0
|
||||
zh: c24b6034969869fe
|
||||
en: 4d4cbb311575d071
|
||||
zh: 7be2d265adb661bc
|
||||
/deepseek-ai-dsh-subprocess/use-this-package/what-can-go-wrong:
|
||||
en: 51f2f43087a1ed18
|
||||
zh: 6d2ebb099b707df3
|
||||
|
||||
@@ -79,8 +79,6 @@ A terminal request can opt into `shellActivity`. `inspectActivity()` combines su
|
||||
|
||||
Children never inherit the harness's ambient secrets: credential-shaped names and ambient `DSH_*` facts are scrubbed, and the caller's explicit `env` merges after that scrub. A deliberately forwarded credential or a current `DSH_*` deployment fact still reaches the child; an explicit `undefined` tombstone removes an ordinary ambient entry.
|
||||
|
||||
The trusted `DshEnvironment` also permits a `PATH` selected by [shell-env](../../shell/shell-env/README.md) for deployment-supplied commands; shell consumers merge that snapshot after ordinary caller environment entries.
|
||||
|
||||
### What can go wrong
|
||||
|
||||
An executable that cannot be resolved fails loudly with a stable error. A spawn that never starts rejects `done`; there is no buffered output for a process that never ran. `waitForExit()` also rejects when the provider cannot prove its selected range is empty, and a provider fallback may not own descendants that escape its process group or observed session. When a transport owns its own spawn (the SDK client, MCP), route around the service and import `scrubbedParentEnv` directly so environment policy stays single-sourced.
|
||||
|
||||
@@ -79,8 +79,6 @@ const output = handle.collected.stdout?.readFrom(0)
|
||||
|
||||
子进程永远不会隐式继承 harness 的环境秘密:形似凭据的名称与环境中的 `DSH_*` 事实都会被清除,调用方显式的 `env` 在该清除之后合并。有意转发的凭据或当前的 `DSH_*` 部署事实仍会到达子进程;显式的 `undefined` 墓碑值则移除一个普通的环境项。
|
||||
|
||||
受信的 `DshEnvironment` 还允许 [shell-env](../../shell/shell-env/README.zh.md) 为部署提供的命令选择 `PATH`;shell 消费方在普通调用方环境项之后合并该快照。
|
||||
|
||||
### 可能出错的地方
|
||||
|
||||
无法解析可执行文件时,服务会明确报出稳定的错误。从未启动成功的 spawn 会让 `done` reject;从未运行过的进程没有任何缓冲输出。提供方无法证明所选范围为空时,`waitForExit()` 也会 reject;提供方 fallback 可能无法拥有逃离其进程组或已观察会话的后代。当传输拥有自己的 spawn(SDK 客户端、MCP)时,请绕开本服务并直接导入 `scrubbedParentEnv`,让环境策略保持单一来源。
|
||||
|
||||
@@ -15,8 +15,8 @@ export const DSH_ENV_PREFIX = 'DSH_' as const
|
||||
/** One environment key inside the managed {@link DSH_ENV_PREFIX} namespace. */
|
||||
export type DshEnvironmentKey = `${typeof DSH_ENV_PREFIX}${string}`
|
||||
|
||||
/** Trusted Harness variables and optional local command PATH for one child-process execution. */
|
||||
export type DshEnvironment = Readonly<Record<DshEnvironmentKey, string> & { PATH?: string }>
|
||||
/** Trusted DeepSeek Harness variables for one child-process execution. */
|
||||
export type DshEnvironment = Readonly<Record<DshEnvironmentKey, string>>
|
||||
|
||||
/** One captured stream: the (possibly truncated) text plus recovery info. */
|
||||
export interface CollectedOutput {
|
||||
|
||||
Generated
-15
@@ -814,9 +814,6 @@ importers:
|
||||
'@deepseek-ai/cordis-plugin-loader':
|
||||
specifier: workspace:~
|
||||
version: link:../../vendor/loader
|
||||
'@deepseek-ai/dsh-shell-env':
|
||||
specifier: workspace:*
|
||||
version: link:../../packages/shell/shell-env
|
||||
'@deepseek-ai/dsh-skill':
|
||||
specifier: workspace:*
|
||||
version: link:../../packages/skill/skill
|
||||
@@ -12955,21 +12952,9 @@ importers:
|
||||
'@deepseek-ai/cordis-plugin-loader':
|
||||
specifier: workspace:~
|
||||
version: link:../../../vendor/loader
|
||||
'@deepseek-ai/dsh-home-paths':
|
||||
specifier: workspace:*
|
||||
version: link:../../util/home-paths
|
||||
'@deepseek-ai/dsh-pwsh-local':
|
||||
specifier: workspace:*
|
||||
version: link:../../shell/pwsh-local
|
||||
'@deepseek-ai/dsh-shell-env':
|
||||
specifier: workspace:*
|
||||
version: link:../../shell/shell-env
|
||||
'@deepseek-ai/dsh-skill':
|
||||
specifier: workspace:*
|
||||
version: link:../skill
|
||||
'@deepseek-ai/dsh-subprocess-local':
|
||||
specifier: workspace:*
|
||||
version: link:../../subprocess/subprocess-local
|
||||
|
||||
packages/skill/tool-skill:
|
||||
dependencies:
|
||||
|
||||
@@ -306,7 +306,6 @@ describe('package payload constraints', () => {
|
||||
])
|
||||
})
|
||||
|
||||
|
||||
it('accepts the Agent Team icon payload and rejects its omission', () => {
|
||||
const dir = 'packages/experimental/agent-team-profile'
|
||||
const manifest = JSON.parse(readFileSync(new URL(`../${dir}/package.json`, import.meta.url), 'utf8')) as WorkspaceManifest['manifest']
|
||||
@@ -404,14 +403,12 @@ it('requires the shared Web injection entry in the published payload', () => {
|
||||
} })).toEqual([expect.stringContaining('package.json files must be')])
|
||||
})
|
||||
|
||||
it('requires Office commands, skill bodies, and helpers in the published payload', () => {
|
||||
it('requires Office skill bodies and helpers in the published payload', () => {
|
||||
const manifest = JSON.parse(readFileSync(new URL('../packages/skill/skill-office/package.json', import.meta.url), 'utf8')) as WorkspaceManifest['manifest']
|
||||
expect(checkWorkspaceManifest({ dir: 'packages/skill/skill-office', manifest })).toEqual([])
|
||||
for (const omitted of ['lib/commands.js', 'assets']) {
|
||||
expect(checkWorkspaceManifest({ dir: 'packages/skill/skill-office', manifest: {
|
||||
...manifest, files: manifest.files!.filter(file => file !== omitted),
|
||||
} })).toEqual([expect.stringContaining('package.json files must be')])
|
||||
}
|
||||
expect(checkWorkspaceManifest({ dir: 'packages/skill/skill-office', manifest: {
|
||||
...manifest, files: ['lib/index.js', 'lib/types/**/*.d.ts'],
|
||||
} })).toEqual([expect.stringContaining('package.json files must be')])
|
||||
})
|
||||
|
||||
it('requires the local speech worker and locked runtime in the published payload', () => {
|
||||
|
||||
@@ -206,7 +206,7 @@ const packageFileExtras: Readonly<Record<string, readonly string[]>> = {
|
||||
// also shares its generated FFI code through a hashed runtime chunk.
|
||||
'@deepseek-ai/dsh-sandbox-windows-acl': ['lib/runner.js', 'lib/types-*.js', 'assets'],
|
||||
'@deepseek-ai/dsh-skill-badge': ['assets'],
|
||||
'@deepseek-ai/dsh-skill-office': ['lib/commands.js', 'assets'],
|
||||
'@deepseek-ai/dsh-skill-office': ['assets'],
|
||||
'@deepseek-ai/dsh-subprocess': ['lib/control.js'],
|
||||
// SSH launches a private helper and shares wire definitions and TLS setup
|
||||
// between that helper and the connection owner.
|
||||
|
||||
@@ -1,37 +1,20 @@
|
||||
/** Exercise the wheel's Office API and model-shell commands from a shipped profile. */
|
||||
import { mkdtemp, readFile, rm, symlink, writeFile } from 'node:fs/promises'
|
||||
import { delimiter, dirname, join } from 'node:path'
|
||||
import { readFile, writeFile } from 'node:fs/promises'
|
||||
import { execFile } from 'node:child_process'
|
||||
import { promisify } from 'node:util'
|
||||
import { createConverter } from '@deepseek-ai/libreoffice-kit'
|
||||
|
||||
export const name = 'python-sdk-office-smoke'
|
||||
|
||||
export async function apply(ctx, config) {
|
||||
const environment = ctx.shellEnv.collect({})
|
||||
const commandDirectory = environment.PATH?.split(delimiter)[0]
|
||||
if (!commandDirectory) throw new Error('Office commands were not registered in the profile')
|
||||
const commandPaths = [commandDirectory]
|
||||
if (process.platform !== 'win32') {
|
||||
const shellDirectory = await mkdtemp(join(dirname(config.input), '.office-shell-'))
|
||||
ctx.effect(() => () => rm(shellDirectory, { recursive: true, force: true }))
|
||||
await symlink('/bin/bash', join(shellDirectory, 'bash'))
|
||||
commandPaths.push(shellDirectory)
|
||||
}
|
||||
const quote = value => process.platform === 'win32'
|
||||
? `'${value.replaceAll("'", "''")}'` : `'${value.replaceAll("'", "'\\''")}'`
|
||||
async function cli(args) {
|
||||
const spec = ctx.shell.resolve({
|
||||
command: ['dsoffice', ...args.map(quote)].join(' '), workdir: dirname(config.input),
|
||||
timeoutMs: 120_000, stdoutMaxBytes: 64 * 1024,
|
||||
env: { PATH: '' }, dshEnv: { ...environment, PATH: commandPaths.join(delimiter) },
|
||||
})
|
||||
const result = await (await ctx.shell.execute(spec)).result()
|
||||
if (result.timedOut || result.aborted || result.signal || result.exitCode !== 0 || result.stdout.truncated) {
|
||||
throw new Error(`Office shell command failed: ${JSON.stringify(result)}`)
|
||||
}
|
||||
return JSON.parse(result.stdout.text)
|
||||
}
|
||||
const skill = await ctx.skills.get('office-export-pdf')
|
||||
if (!skill?.content.includes('dsoffice convert')) throw new Error('Office skill did not name the installed command')
|
||||
const json = skill?.content.match(/\n(\{\n[\s\S]+)$/u)?.[1]
|
||||
if (json === undefined) throw new Error('Office skill did not supply CLI paths')
|
||||
const { libreofficeKit: { node, cli: entry } } = JSON.parse(json)
|
||||
async function cli(args) {
|
||||
const result = await promisify(execFile)(node, [entry, ...args], { timeout: 120_000, env: { ...process.env, PATH: '' } })
|
||||
return JSON.parse(result.stdout)
|
||||
}
|
||||
const capabilities = await cli(['capabilities', '--json'])
|
||||
await cli(['convert', '--input', config.input, '--output', config.output + '.cli.pdf'])
|
||||
const pdf = await readFile(config.output + '.cli.pdf')
|
||||
|
||||
@@ -93,14 +93,6 @@ describe.each([experimental, ...Object.values(EXPERIMENTAL_PACKAGE_NAME_EXCEPTIO
|
||||
expect(() => verifyInstalledProductIsolation(entry)).toThrow(experimental)
|
||||
})
|
||||
|
||||
it('finds installed packages whose names also identify Node builtins', () => {
|
||||
const root = fixture()
|
||||
const entry = writePackage(root, '@deepseek-ai/dsh', { dependencies: { fs: '1.0.0' } })
|
||||
expect(() => verifyInstalledProductIsolation(entry)).toThrow('dependency is missing: @deepseek-ai/dsh -> fs')
|
||||
writePackage(root, 'fs', {})
|
||||
expect(verifyInstalledProductIsolation(entry)).toBe(2)
|
||||
})
|
||||
|
||||
it('permits missing optional packages and optional peers but rejects missing dependencies', () => {
|
||||
const root = fixture()
|
||||
const entry = writePackage(root, '@deepseek-ai/dsh', {
|
||||
|
||||
@@ -62,10 +62,10 @@ function rejectExperimental(name: string, chain: readonly string[]): void {
|
||||
}
|
||||
}
|
||||
|
||||
/** Resolve a declared package through ancestor node_modules, including names shared with Node builtins. */
|
||||
/** Resolve a dependency directory through the installed package's ancestor node_modules. */
|
||||
function installedPackage(from: string, name: string): string | undefined {
|
||||
const resolver = createRequire(join(from, 'package.json'))
|
||||
for (const directory of resolver.resolve.paths(`${name}/package.json`) ?? []) {
|
||||
for (const directory of resolver.resolve.paths(name) ?? []) {
|
||||
const candidate = join(directory, name)
|
||||
if (existsSync(join(candidate, 'package.json'))) return candidate
|
||||
}
|
||||
|
||||
@@ -1016,7 +1016,7 @@ def smoke_sdk_office(executable: Path) -> None:
|
||||
patch = root / f"{mode}.patch.yml"
|
||||
patch.write_text(json.dumps([{"insert": [{
|
||||
"id": "python-sdk-office-smoke",
|
||||
"inject": ["skills", "shell", "shellEnv"],
|
||||
"inject": ["skills"],
|
||||
"name": plugin.as_uri(),
|
||||
"config": {"input": str(document), "output": str(output), "result": str(result_path),
|
||||
"imageInput": str(documents["pptx"]), "imageOutput": str(root / "node-pptx")},
|
||||
|
||||
@@ -68,9 +68,6 @@
|
||||
name: '@deepseek-ai/dsh-tool-skill'
|
||||
disabled: true
|
||||
|
||||
- id: workspace-dependencies
|
||||
disabled: true
|
||||
|
||||
- id: tool-jobs
|
||||
name: '@deepseek-ai/dsh-tool-jobs'
|
||||
disabled: true
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
disabled: !!js process.env.DSH_SNAPSHOT !== 'record'
|
||||
|
||||
- id: subagent-dsh-sdk
|
||||
name: '../../../packages/subagent/subagent-dsh-sdk/tests/fixtures/loader/provider.mjs'
|
||||
name: '@deepseek-ai/dsh-subagent-dsh-sdk'
|
||||
config:
|
||||
profile: sdk
|
||||
patches: !!js JSON.parse(process.env.DSH_TEST_CHILD_PATCHES ?? '[]')
|
||||
|
||||
@@ -65,9 +65,6 @@
|
||||
name: '@deepseek-ai/dsh-skill-filesystem'
|
||||
disabled: true
|
||||
|
||||
- id: skill-office
|
||||
disabled: true
|
||||
|
||||
- id: tool-skill
|
||||
name: '@deepseek-ai/dsh-tool-skill'
|
||||
disabled: true
|
||||
|
||||
@@ -57,9 +57,6 @@
|
||||
name: '@deepseek-ai/dsh-skill-filesystem'
|
||||
disabled: true
|
||||
|
||||
- id: skill-office
|
||||
disabled: true
|
||||
|
||||
- id: tool-skill
|
||||
name: '@deepseek-ai/dsh-tool-skill'
|
||||
disabled: true
|
||||
|
||||
@@ -52,6 +52,7 @@
|
||||
disabled: false
|
||||
config:
|
||||
assetRoot: !!js process.cwd() + '/office-skills'
|
||||
cli: false
|
||||
|
||||
- id: tool-bash
|
||||
disabled: true
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
disabled: false
|
||||
config:
|
||||
assetRoot: !!js process.cwd() + '/office-skills'
|
||||
cli: false
|
||||
|
||||
- id: tool-bash
|
||||
disabled: true
|
||||
|
||||
@@ -15,17 +15,17 @@
|
||||
{"type":"session/title","data":{"title":"Load the Office Word, PowerPoint,","messageSeqs":[8],"source":{"kind":"fallback"}}}
|
||||
{"type":"assistant/message","data":{"turn":1,"step":1,"message":{"role":"assistant","content":[{"type":"tool-call","id":"call_office_skill","name":"skill","arguments":"{\"name\":\"office-docx\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{message:5}}"},"stream":[{"type":"chunk","time":1790753571607,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}},{"type":"tool-call-chunks","time0":1790753571608,"index":0,"dt":[],"id":"call_office_skill","name":"skill","args":["{\"name\":\"office-docx\"}"]},{"type":"chunk","time":1790753571608,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"call_office_skill","name":"skill","arguments":"{\"name\":\"office-docx\"}"}}},{"type":"chunk","time":1790753571608,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}]},"surfaceOp":"append"}
|
||||
{"type":"tool/call","data":{"turn":1,"step":1,"callId":"call_office_skill","name":"skill","arguments":"{\"name\":\"office-docx\"}"}}
|
||||
{"type":"tool/result","data":{"turn":1,"step":1,"message":{"role":"tool","source":{"kind":"tool","callId":"call_office_skill"},"toolCallId":"call_office_skill","content":[{"type":"text","text":"<skill_content name=\"office-docx\">\n<skill_resources>\nBase directory for this skill: {{cwd}}/office-skills/office-docx\nResolve relative paths mentioned by this skill against the base directory before using them. Load referenced resources only as needed.\n</skill_resources>\n\n<skill_instructions>\n# Word documents\n\nUse `python-docx` for DOCX creation and ordinary edits. Follow an explicit user or applicable AGENTS.md requirement for a project environment or another library. Otherwise call `load_workspace_dependencies` and execute the returned Python path with its bundled libraries. Do not install packages or discover a system Python for the default workflow. If the tool is unavailable, use an already configured environment and report a missing dependency only when it prevents the requested operation.\n\nKeep source scripts, intermediate files, and final documents in the task workspace; the runtime and this skill directory are read-only resources. Use the user's requested language and preserve an existing document's design unless a redesign is requested.\n\n## Create and edit\n\nFor existing files, inspect paragraphs, runs, tables, sections, headers, and footers before changing the affected content. Save to a new file unless the user requests an in-place edit. Replacing a paragraph's `.text` destroys its run formatting; change the relevant runs when formatting must survive. Reconstructing the whole document can lose features outside python-docx's supported editing API.\n\nUse paragraph styles for headings and body text. Size tables for the section that contains them, and account for merged cells and nested tables. Chinese, Japanese, and Korean text may need an explicit `w:eastAsia` font assignment in addition to `run.font.name`; font names alone do not establish glyph availability or rendered appearance.\n\nFor a new document, use the selected Python executable:\n\n```python\nfrom docx import Document\n\ndocument = Document()\ndocument.add_heading(\"Project report\", level=0)\ndocument.add_paragraph(\"Summary\", style=\"Heading 1\")\ndocument.add_paragraph(\"The requested findings go here.\")\ndocument.save(\"report.docx\")\n```\n\npython-docx does not paginate or render documents. Do not represent ordinary replacement, colored text, or comments as tracked changes. When real revisions or unsupported OOXML features matter, preserve their package parts and verify the requested operation rather than silently discarding them.\n\n## Check and deliver\n\nRun the shared structural checker when `office-check` is available:\n\n```text\noffice-check <document.docx> --out <checks.json>\n```\n\nIt checks ZIP/XML integrity and internal relationships, and reports paragraphs, logical table dimensions, and sections. Optional `--contains TEXT` arguments assert required text. A successful structural check does not verify pagination, clipping, fonts, or visual appearance. Compare the summary and reopened document with the user's request, including unchanged content that matters to an edit.\n\nIf `office-check` is unavailable, use an already configured environment to check the ZIP/XML package and internal relationships. Report the missing environment if those checks cannot run; do not claim structural validation.\n\nDeliver after the requested content and structural checks pass. Creating a file or changing content with incidental basic formatting does not require additional operations. Load `office-render` for requested images or visual inspection and for appearance-focused styling, spacing, sizing, or alignment changes unless the user explicitly skips rendering. For PDF output load `office-export-pdf`.\n\nCall `present({\"files\":[{\"path\":\"report.docx\"}]})` with the actual final DOCX path. It exposes the current source file without copying or preserving its bytes, so keep that file in place and do not present temporary QA reports unless requested. If `present` is unavailable, provide the final workspace path using the session's supported file delivery method.\n</skill_instructions>\n</skill_content>"}],"isError":false,"id":"{{message:6}}"}},"sourceEventSeqs":[15],"surfaceOp":"append"}
|
||||
{"type":"tool/result","data":{"turn":1,"step":1,"message":{"role":"tool","source":{"kind":"tool","callId":"call_office_skill"},"toolCallId":"call_office_skill","content":[{"type":"text","text":"<skill_content name=\"office-docx\">\n<skill_resources>\nBase directory for this skill: {{cwd}}/office-skills/office-docx\nResolve relative paths mentioned by this skill against the base directory before using them. Load referenced resources only as needed.\n</skill_resources>\n\n<skill_instructions>\n# Word documents\n\nUse `python-docx` for DOCX creation and ordinary edits. Follow an explicit user or applicable AGENTS.md requirement for a project environment or another library. Otherwise call `load_workspace_dependencies` and execute the returned Python path with its bundled libraries. Do not install packages or discover a system Python for the default workflow. If the tool is unavailable, use an already configured environment and report a missing dependency only when it prevents the requested operation.\n\nKeep source scripts, intermediate files, and final documents in the task workspace; the runtime and this skill directory are read-only resources. Use the user's requested language and preserve an existing document's design unless a redesign is requested.\n\n## Create and edit\n\nFor existing files, inspect paragraphs, runs, tables, sections, headers, and footers before changing the affected content. Save to a new file unless the user requests an in-place edit. Replacing a paragraph's `.text` destroys its run formatting; change the relevant runs when formatting must survive. Reconstructing the whole document can lose features outside python-docx's supported editing API.\n\nUse paragraph styles for headings and body text. Size tables for the section that contains them, and account for merged cells and nested tables. Chinese, Japanese, and Korean text may need an explicit `w:eastAsia` font assignment in addition to `run.font.name`; font names alone do not establish glyph availability or rendered appearance.\n\nFor a new document, use the selected Python executable:\n\n```python\nfrom docx import Document\n\ndocument = Document()\ndocument.add_heading(\"Project report\", level=0)\ndocument.add_paragraph(\"Summary\", style=\"Heading 1\")\ndocument.add_paragraph(\"The requested findings go here.\")\ndocument.save(\"report.docx\")\n```\n\npython-docx does not paginate or render documents. Do not represent ordinary replacement, colored text, or comments as tracked changes. When real revisions or unsupported OOXML features matter, preserve their package parts and verify the requested operation rather than silently discarding them.\n\n## Check and deliver\n\nRun the shared structural checker when `office-check` is available:\n\nIn PowerShell, prefix the quoted Python executable with `&`. Resolve the checker path relative to this skill directory.\n\n```text\n\"<python>\" \"<skill-directory>/../scripts/check_office.py\" <document.docx> --out <checks.json>\n```\n\nIt checks ZIP/XML integrity and internal relationships, and reports paragraphs, logical table dimensions, and sections. Optional `--contains TEXT` arguments assert required text. A successful structural check does not verify pagination, clipping, fonts, or visual appearance. Compare the summary and reopened document with the user's request, including unchanged content that matters to an edit.\n\nIf the Python checker cannot run, use an already configured environment to check the ZIP/XML package and internal relationships. Report the missing environment if those checks cannot run; do not claim structural validation.\n\nDeliver after the requested content and structural checks pass. Creating a file or changing content with incidental basic formatting does not require additional operations. Load `office-render` for requested images or visual inspection. When styling, font color, spacing, sizing, or text alignment is the requested edit, load `office-render` and inspect the changed page even without a separate visual-check request, unless the user explicitly skips rendering. For PDF output load `office-export-pdf`.\n\nCall `present({\"files\":[{\"path\":\"report.docx\"}]})` with the actual final DOCX path. It exposes the current source file without copying or preserving its bytes, so keep that file in place and do not present temporary QA reports unless requested. If `present` is unavailable, provide the final workspace path using the session's supported file delivery method.\n</skill_instructions>\n</skill_content>"}],"isError":false,"id":"{{message:6}}"}},"sourceEventSeqs":[15],"surfaceOp":"append"}
|
||||
{"type":"step/end","data":{"turn":1,"step":1}}
|
||||
{"type":"step/start","data":{"turn":1,"step":2}}
|
||||
{"type":"assistant/message","data":{"turn":1,"step":2,"message":{"role":"assistant","content":[{"type":"tool-call","id":"call_office_2","name":"skill","arguments":"{\"name\":\"office-pptx\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{message:7}}"},"stream":[{"type":"chunk","time":1790753571639,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}},{"type":"tool-call-chunks","time0":1790753571639,"index":0,"dt":[],"id":"call_office_2","name":"skill","args":["{\"name\":\"office-pptx\"}"]},{"type":"chunk","time":1790753571639,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"call_office_2","name":"skill","arguments":"{\"name\":\"office-pptx\"}"}}},{"type":"chunk","time":1790753571639,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}]},"surfaceOp":"append"}
|
||||
{"type":"tool/call","data":{"turn":1,"step":2,"callId":"call_office_2","name":"skill","arguments":"{\"name\":\"office-pptx\"}"}}
|
||||
{"type":"tool/result","data":{"turn":1,"step":2,"message":{"role":"tool","source":{"kind":"tool","callId":"call_office_2"},"toolCallId":"call_office_2","content":[{"type":"text","text":"<skill_content name=\"office-pptx\">\n<skill_resources>\nBase directory for this skill: {{cwd}}/office-skills/office-pptx\nResolve relative paths mentioned by this skill against the base directory before using them. Load referenced resources only as needed.\n</skill_resources>\n\n<skill_instructions>\n# PowerPoint presentations\n\nFollow an explicit user or applicable AGENTS.md requirement for an environment or library. Otherwise call `load_workspace_dependencies` and use its Python executable and bundled presentation libraries. Do not install npm or pip packages or locate a system interpreter for the default workflow. If the tool is unavailable, use an already configured environment and report a missing dependency only when it prevents the requested operation.\n\nKeep scripts and output files in the task workspace. The runtime and skill directory contain shared read-only resources. Match the requested slide language and the supplied presentation's design when editing it.\n\n## Create and edit\n\nUse `python-pptx` to inspect or modify an existing presentation. Inspect slide layouts, text runs, images, tables, and charts before editing. Change only the requested content, preserve mixed text formatting, and save to a new file unless the user requests an in-place edit. Rebuilding slides can discard unsupported animation, SmartArt, or other extension content.\n\nFor a new deck, use `python-pptx` with editable text, tables, and charts. Use local image assets rather than network-dependent image URLs. Set slide dimensions, text sizes, and chart data explicitly.\n\nA minimal editable deck, run with the selected Python executable:\n\n```python\nfrom pptx import Presentation\nfrom pptx.chart.data import CategoryChartData\nfrom pptx.enum.chart import XL_CHART_TYPE\nfrom pptx.util import Inches, Pt\n\npresentation = Presentation()\npresentation.slide_width = Inches(13.333)\npresentation.slide_height = Inches(7.5)\nslide = presentation.slides.add_slide(presentation.slide_layouts[6])\ntitle = slide.shapes.add_textbox(Inches(0.6), Inches(0.4), Inches(12), Inches(0.8))\nrun = title.text_frame.paragraphs[0].add_run()\nrun.text = \"Quarterly report\"\nrun.font.size = Pt(30)\ndata = CategoryChartData()\ndata.categories = [\"Q1\", \"Q2\"]\ndata.add_series(\"Revenue\", [12, 18])\nslide.shapes.add_chart(XL_CHART_TYPE.COLUMN_CLUSTERED,\n Inches(0.8), Inches(1.6), Inches(11.5), Inches(4.8), data)\npresentation.save(\"report.pptx\")\n```\n\nUse `Inches` or `Cm` for positions and sizes and `Pt` for font sizes. To edit a generated title while retaining its other slides and charts:\n\n```python\nfrom pptx import Presentation\n\npresentation = Presentation(\"report.pptx\")\nfor shape in presentation.slides[0].shapes:\n if shape.has_text_frame and shape.text == \"Quarterly report\":\n shape.text_frame.paragraphs[0].runs[0].text = \"Quarterly results\"\npresentation.save(\"report-edited.pptx\")\n```\n\nCheck that text and images fit the slide dimensions, titles form a useful sequence, and chart labels agree with source values. Paragraph alignment does not move a text box: when a title must be centered on the slide, center both its paragraph and the text box against `presentation.slide_width`, then reopen to verify both. A native chart's embedded workbook is part of the deliverable and must contain the intended data. Library support for writing PPTX is not a rendering engine or a guarantee that every PowerPoint feature survives editing.\n\n## Check and deliver\n\nRun the shared structural checker when `office-check` is available:\n\n```text\noffice-check <presentation.pptx> --out <checks.json>\n```\n\nIt checks ZIP/XML integrity and internal relationships and reports slide count and extracted text. Use repeated `--contains TEXT` arguments for required slide text and `--count N` for a requested slide count; `--contains` excludes chart text and speaker notes. Reopen the file to check the requested edits, chart data, and notes. Structural success does not establish text fit, alignment, readable contrast, or rendering fidelity.\n\nIf `office-check` is unavailable, use an already configured environment to check the ZIP/XML package and internal relationships. Report the missing environment if those checks cannot run; do not claim structural validation.\n\nDeliver after the requested content and structural checks pass. Creating a file or changing content with incidental basic formatting does not require additional operations. Load `office-render` for requested images or visual inspection and for appearance-focused styling, spacing, sizing, or alignment changes unless the user explicitly skips rendering. For PDF output load `office-export-pdf`.\n\nCall `present({\"files\":[{\"path\":\"report-edited.pptx\"}]})` with the actual finalLine truncated
|
||||
{"type":"tool/result","data":{"turn":1,"step":2,"message":{"role":"tool","source":{"kind":"tool","callId":"call_office_2"},"toolCallId":"call_office_2","content":[{"type":"text","text":"<skill_content name=\"office-pptx\">\n<skill_resources>\nBase directory for this skill: {{cwd}}/office-skills/office-pptx\nResolve relative paths mentioned by this skill against the base directory before using them. Load referenced resources only as needed.\n</skill_resources>\n\n<skill_instructions>\n# PowerPoint presentations\n\nFollow an explicit user or applicable AGENTS.md requirement for an environment or library. Otherwise call `load_workspace_dependencies` and use its Python executable and bundled presentation libraries. Do not install npm or pip packages or locate a system interpreter for the default workflow. If the tool is unavailable, use an already configured environment and report a missing dependency only when it prevents the requested operation.\n\nKeep scripts and output files in the task workspace. The runtime and skill directory contain shared read-only resources. Match the requested slide language and the supplied presentation's design when editing it.\n\n## Create and edit\n\nUse `python-pptx` to inspect or modify an existing presentation. Inspect slide layouts, text runs, images, tables, and charts before editing. Change only the requested content, preserve mixed text formatting, and save to a new file unless the user requests an in-place edit. Rebuilding slides can discard unsupported animation, SmartArt, or other extension content.\n\nFor a new deck, use `python-pptx` with editable text, tables, and charts. Use local image assets rather than network-dependent image URLs. Set slide dimensions, text sizes, and chart data explicitly.\n\nA minimal editable deck, run with the selected Python executable:\n\n```python\nfrom pptx import Presentation\nfrom pptx.chart.data import CategoryChartData\nfrom pptx.enum.chart import XL_CHART_TYPE\nfrom pptx.util import Inches, Pt\n\npresentation = Presentation()\npresentation.slide_width = Inches(13.333)\npresentation.slide_height = Inches(7.5)\nslide = presentation.slides.add_slide(presentation.slide_layouts[6])\ntitle = slide.shapes.add_textbox(Inches(0.6), Inches(0.4), Inches(12), Inches(0.8))\nrun = title.text_frame.paragraphs[0].add_run()\nrun.text = \"Quarterly report\"\nrun.font.size = Pt(30)\ndata = CategoryChartData()\ndata.categories = [\"Q1\", \"Q2\"]\ndata.add_series(\"Revenue\", [12, 18])\nslide.shapes.add_chart(XL_CHART_TYPE.COLUMN_CLUSTERED,\n Inches(0.8), Inches(1.6), Inches(11.5), Inches(4.8), data)\npresentation.save(\"report.pptx\")\n```\n\nUse `Inches` or `Cm` for positions and sizes and `Pt` for font sizes. To edit a generated title while retaining its other slides and charts:\n\n```python\nfrom pptx import Presentation\n\npresentation = Presentation(\"report.pptx\")\nfor shape in presentation.slides[0].shapes:\n if shape.has_text_frame and shape.text == \"Quarterly report\":\n shape.text_frame.paragraphs[0].runs[0].text = \"Quarterly results\"\npresentation.save(\"report-edited.pptx\")\n```\n\nCheck that text and images fit the slide dimensions, titles form a useful sequence, and chart labels agree with source values. Paragraph alignment does not move a text box: when a title must be centered on the slide, center both its paragraph and the text box against `presentation.slide_width`, then reopen to verify both. A native chart's embedded workbook is part of the deliverable and must contain the intended data. Library support for writing PPTX is not a rendering engine or a guarantee that every PowerPoint feature survives editing.\n\n## Check and deliver\n\nRun the shared structural checker when `office-check` is available:\n\nIn PowerShell, prefix the quoted Python executable with `&`. Resolve the checker path relative to this skill directory.\n\n```text\n\"<python>\" \"<skill-directory>/../scripts/check_office.py\" <presentation.pptx> --out <checks.json>\n```\n\nIt checks ZIP/XML integrity and internal relationships and reports slide count and extracted text. Use repeated `--contains TEXT` arguments for required slide text and `--count N` for a requested slide count; `--contains` excludes chart text and speaker notes. Reopen the file to check the requested edits, chart data, and notes. Structural success does not establish text fit, alignment, readable contrast, or rendering fidelity.\n\nIf the Python checker cannot run, use an already configured environment to check the ZIP/XML package and internal relationships. Report the missing environment if those checks cannot run; do not claim structural validation.\n\nDeliver after the requested content and structural checks pass. Creating a file or changing content with incidental basic formatting does not require additional operations. Load `office-render` for requested images or visual inspection and for appearance-focused styling, spacing, sizing, or alignment changes uLine truncated
|
||||
{"type":"step/end","data":{"turn":1,"step":2}}
|
||||
{"type":"step/start","data":{"turn":1,"step":3}}
|
||||
{"type":"assistant/message","data":{"turn":1,"step":3,"message":{"role":"assistant","content":[{"type":"tool-call","id":"call_office_3","name":"skill","arguments":"{\"name\":\"office-xlsx\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{message:9}}"},"stream":[{"type":"chunk","time":1790753571666,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}},{"type":"tool-call-chunks","time0":1790753571666,"index":0,"dt":[],"id":"call_office_3","name":"skill","args":["{\"name\":\"office-xlsx\"}"]},{"type":"chunk","time":1790753571666,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"call_office_3","name":"skill","arguments":"{\"name\":\"office-xlsx\"}"}}},{"type":"chunk","time":1790753571666,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}]},"surfaceOp":"append"}
|
||||
{"type":"tool/call","data":{"turn":1,"step":3,"callId":"call_office_3","name":"skill","arguments":"{\"name\":\"office-xlsx\"}"}}
|
||||
{"type":"tool/result","data":{"turn":1,"step":3,"message":{"role":"tool","source":{"kind":"tool","callId":"call_office_3"},"toolCallId":"call_office_3","content":[{"type":"text","text":"<skill_content name=\"office-xlsx\">\n<skill_resources>\nBase directory for this skill: {{cwd}}/office-skills/office-xlsx\nResolve relative paths mentioned by this skill against the base directory before using them. Load referenced resources only as needed.\n</skill_resources>\n\n<skill_instructions>\n# Excel workbooks\n\nFollow an explicit user or applicable AGENTS.md requirement for an environment or library. Otherwise call `load_workspace_dependencies` and run its Python executable with bundled `openpyxl` and `pandas`. Do not install packages or search for a system Python for the default workflow. If the tool is unavailable, use an already configured environment and report a missing dependency only when it prevents the requested operation.\n\nKeep scripts, working files, and outputs in the task workspace. The runtime and skill directory are shared read-only resources. Save to a new workbook unless the user requests an in-place edit.\n\n## Read and modify\n\nUse `openpyxl` for existing XLSX workbooks and targeted cell or style changes. Load with `data_only=False` when formulas must survive. Inspect sheet names, the affected cell types, formulas, styles, merged ranges, and referenced ranges before editing. Check the saved file by reopening it, including unchanged content that the request requires preserving.\n\nUse pandas for data analysis and transformations. A DataFrame is not the workbook: exporting it over an existing file can lose sheets, formulas, charts, and formatting. Write analysis results back to the intended ranges with openpyxl. `XlsxWriter` can create new workbooks, but cannot read or modify existing ones.\n\nFor a new workbook, the selected Python environment can write editable values, styles, and formulas directly:\n\n```python\nfrom openpyxl import Workbook\nfrom openpyxl.styles import Font\n\nworkbook = Workbook()\nsheet = workbook.active\nsheet.title = \"Revenue\"\nfor row in [(\"Quarter\", \"Revenue\"), (\"Q1\", 12), (\"Q2\", 18), (\"Total\", \"=SUM(B2:B3)\")]:\n sheet.append(row)\nfor cell in sheet[1]:\n cell.font = Font(bold=True)\nsheet.column_dimensions[\"A\"].width = 18\nsheet.column_dimensions[\"B\"].width = 18\nworkbook.save(\"report.xlsx\")\n```\n\nPreserve numbers, dates, booleans, and identifiers as the intended cell types; formatting is not a type conversion. For modifications, load the existing file with `openpyxl.load_workbook(\"input.xlsx\", data_only=False)`, change the requested ranges, and save a separate result. Avoid a DataFrame round trip when workbook features must survive.\n\nWriting a formula does not calculate its result. openpyxl and XlsxWriter do not evaluate formulas; `data_only=True` returns cached values that may be absent or stale. When calculated results must be refreshed, load `office-recalculate`. Do not replace requested formulas with constants or report stale values as newly calculated results.\n\nDo not rename `.xls`, `.xlsb`, encrypted files, or macro-enabled files to `.xlsx`. They need an appropriate supported operation. `keep_vba=True` can preserve VBA package content in an XLSM workflow, but does not execute or edit macros and does not guarantee every advanced workbook feature survives. Preserve the original and verify such requirements explicitly.\n\n## Check and deliver\n\nRun the shared structural checker when `office-check` is available:\n\n```text\noffice-check <workbook.xlsx> --out <checks.json>\n```\n\nIt checks ZIP/XML integrity and internal relationships, and reports sheet names, populated-cell counts, and formula counts. Repeated `--contains TEXT` arguments check string cells and sheet names, and `--count N` checks sheet count. `--contains` excludes numeric cells and does not validate formula results; verify those separately with openpyxl. The checker does not calculate formulas or judge workbook appearance. Compare relevant values, types, formulas, styles, and totals with the task's source data.\n\nIf `office-check` is unavailable, use an already configured environment to check the ZIP/XML package and internal relationships. Report the missing environment if those checks cannot run; do not claim structural validation.\n\nLoad `office-render` for requested images or visual inspection and whenever the user's primary task targets appearance, including cell fill colors, text alignment, spacing, or sizing. These appearance changes require rendering even without a separate visual-check request, unless the user explicitly skips it. New workbooks and data or formula edits do not require rendering solely because they include incidental basic formatting. In particular, bold headers and number formats accompanying data edits do not require loading `office-render` or running its commands.\n\nLoad `office-recalculate` when refreshed calculated values are needeLine truncated
|
||||
{"type":"tool/result","data":{"turn":1,"step":3,"message":{"role":"tool","source":{"kind":"tool","callId":"call_office_3"},"toolCallId":"call_office_3","content":[{"type":"text","text":"<skill_content name=\"office-xlsx\">\n<skill_resources>\nBase directory for this skill: {{cwd}}/office-skills/office-xlsx\nResolve relative paths mentioned by this skill against the base directory before using them. Load referenced resources only as needed.\n</skill_resources>\n\n<skill_instructions>\n# Excel workbooks\n\nFollow an explicit user or applicable AGENTS.md requirement for an environment or library. Otherwise call `load_workspace_dependencies` and run its Python executable with bundled `openpyxl` and `pandas`. Do not install packages or search for a system Python for the default workflow. If the tool is unavailable, use an already configured environment and report a missing dependency only when it prevents the requested operation.\n\nKeep scripts, working files, and outputs in the task workspace. The runtime and skill directory are shared read-only resources. Save to a new workbook unless the user requests an in-place edit.\n\n## Read and modify\n\nUse `openpyxl` for existing XLSX workbooks and targeted cell or style changes. Load with `data_only=False` when formulas must survive. Inspect sheet names, the affected cell types, formulas, styles, merged ranges, and referenced ranges before editing. Check the saved file by reopening it, including unchanged content that the request requires preserving.\n\nUse pandas for data analysis and transformations. A DataFrame is not the workbook: exporting it over an existing file can lose sheets, formulas, charts, and formatting. Write analysis results back to the intended ranges with openpyxl. `XlsxWriter` can create new workbooks, but cannot read or modify existing ones.\n\nFor a new workbook, the selected Python environment can write editable values, styles, and formulas directly:\n\n```python\nfrom openpyxl import Workbook\nfrom openpyxl.styles import Font\n\nworkbook = Workbook()\nsheet = workbook.active\nsheet.title = \"Revenue\"\nfor row in [(\"Quarter\", \"Revenue\"), (\"Q1\", 12), (\"Q2\", 18), (\"Total\", \"=SUM(B2:B3)\")]:\n sheet.append(row)\nfor cell in sheet[1]:\n cell.font = Font(bold=True)\nsheet.column_dimensions[\"A\"].width = 18\nsheet.column_dimensions[\"B\"].width = 18\nworkbook.save(\"report.xlsx\")\n```\n\nPreserve numbers, dates, booleans, and identifiers as the intended cell types; formatting is not a type conversion. For modifications, load the existing file with `openpyxl.load_workbook(\"input.xlsx\", data_only=False)`, change the requested ranges, and save a separate result. Avoid a DataFrame round trip when workbook features must survive.\n\nWriting a formula does not calculate its result. openpyxl and XlsxWriter do not evaluate formulas; `data_only=True` returns cached values that may be absent or stale. When calculated results must be refreshed, load `office-recalculate`. Do not replace requested formulas with constants or report stale values as newly calculated results.\n\nDo not rename `.xls`, `.xlsb`, encrypted files, or macro-enabled files to `.xlsx`. They need an appropriate supported operation. `keep_vba=True` can preserve VBA package content in an XLSM workflow, but does not execute or edit macros and does not guarantee every advanced workbook feature survives. Preserve the original and verify such requirements explicitly.\n\n## Check and deliver\n\nRun the shared structural checker when `office-check` is available:\n\nIn PowerShell, prefix the quoted Python executable with `&`. Resolve the checker path relative to this skill directory.\n\n```text\n\"<python>\" \"<skill-directory>/../scripts/check_office.py\" <workbook.xlsx> --out <checks.json>\n```\n\nIt checks ZIP/XML integrity and internal relationships, and reports sheet names, populated-cell counts, and formula counts. Repeated `--contains TEXT` arguments check string cells and sheet names, and `--count N` checks sheet count. `--contains` excludes numeric cells and does not validate formula results; verify those separately with openpyxl. The checker does not calculate formulas or judge workbook appearance. Compare relevant values, types, formulas, styles, and totals with the task's source data.\n\nIf the Python checker cannot run, use an already configured environment to check the ZIP/XML package and internal relationships. Report the missing environment if those checks cannot run; do not claim structural validation.\n\nLoad `office-render` for requested images or visual inspection and whenever the user's primary task targets appearance, including cell fill colors, text alignment, spacing, or sizing. These appearance changes require rendering even without a separate visual-check request, unless the user explicitly skips it. New workbooks and data or formula edits do not require rendering solely because they include incidental basic formatting. In particular, bold headers and nuLine truncated
|
||||
{"type":"step/end","data":{"turn":1,"step":3}}
|
||||
{"type":"step/start","data":{"turn":1,"step":4}}
|
||||
{"type":"assistant/message","data":{"turn":1,"step":4,"message":{"role":"assistant","content":[{"type":"tool-call","id":"call_office_4","name":"read","arguments":"{\"file_path\":\"office-skills/office/references/sidecar.md\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{message:11}}"},"stream":[{"type":"chunk","time":1790753571694,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}},{"type":"tool-call-chunks","time0":1790753571694,"index":0,"dt":[],"id":"call_office_4","name":"read","args":["{\"file_path\":\"office-skills/office/references/sidecar.md\"}"]},{"type":"chunk","time":1790753571695,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"call_office_4","name":"read","arguments":"{\"file_path\":\"office-skills/office/references/sidecar.md\"}"}}},{"type":"chunk","time":1790753571695,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}]},"surfaceOp":"append"}
|
||||
|
||||
@@ -20,17 +20,17 @@
|
||||
{"type":"step/start","data":{"turn":1,"step":2}}
|
||||
{"type":"assistant/message","data":{"turn":1,"step":2,"message":{"role":"assistant","content":[{"type":"tool-call","id":"call_office_2","name":"skill","arguments":"{\"name\":\"office-xlsx\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{message:7}}"},"stream":[{"type":"chunk","time":1791559898453,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}},{"type":"tool-call-chunks","time0":1791559898453,"index":0,"dt":[],"id":"call_office_2","name":"skill","args":["{\"name\":\"office-xlsx\"}"]},{"type":"chunk","time":1791559898453,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"call_office_2","name":"skill","arguments":"{\"name\":\"office-xlsx\"}"}}},{"type":"chunk","time":1791559898453,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}]},"surfaceOp":"append"}
|
||||
{"type":"tool/call","data":{"turn":1,"step":2,"callId":"call_office_2","name":"skill","arguments":"{\"name\":\"office-xlsx\"}"}}
|
||||
{"type":"tool/result","data":{"turn":1,"step":2,"message":{"role":"tool","source":{"kind":"tool","callId":"call_office_2"},"toolCallId":"call_office_2","content":[{"type":"text","text":"<skill_content name=\"office-xlsx\">\n<skill_resources>\nBase directory for this skill: {{cwd}}/office-skills/office-xlsx\nResolve relative paths mentioned by this skill against the base directory before using them. Load referenced resources only as needed.\n</skill_resources>\n\n<skill_instructions>\n# Excel workbooks\n\nFollow an explicit user or applicable AGENTS.md requirement for an environment or library. Otherwise call `load_workspace_dependencies` and run its Python executable with bundled `openpyxl` and `pandas`. Do not install packages or search for a system Python for the default workflow. If the tool is unavailable, use an already configured environment and report a missing dependency only when it prevents the requested operation.\n\nKeep scripts, working files, and outputs in the task workspace. The runtime and skill directory are shared read-only resources. Save to a new workbook unless the user requests an in-place edit.\n\n## Read and modify\n\nUse `openpyxl` for existing XLSX workbooks and targeted cell or style changes. Load with `data_only=False` when formulas must survive. Inspect sheet names, the affected cell types, formulas, styles, merged ranges, and referenced ranges before editing. Check the saved file by reopening it, including unchanged content that the request requires preserving.\n\nUse pandas for data analysis and transformations. A DataFrame is not the workbook: exporting it over an existing file can lose sheets, formulas, charts, and formatting. Write analysis results back to the intended ranges with openpyxl. `XlsxWriter` can create new workbooks, but cannot read or modify existing ones.\n\nFor a new workbook, the selected Python environment can write editable values, styles, and formulas directly:\n\n```python\nfrom openpyxl import Workbook\nfrom openpyxl.styles import Font\n\nworkbook = Workbook()\nsheet = workbook.active\nsheet.title = \"Revenue\"\nfor row in [(\"Quarter\", \"Revenue\"), (\"Q1\", 12), (\"Q2\", 18), (\"Total\", \"=SUM(B2:B3)\")]:\n sheet.append(row)\nfor cell in sheet[1]:\n cell.font = Font(bold=True)\nsheet.column_dimensions[\"A\"].width = 18\nsheet.column_dimensions[\"B\"].width = 18\nworkbook.save(\"report.xlsx\")\n```\n\nPreserve numbers, dates, booleans, and identifiers as the intended cell types; formatting is not a type conversion. For modifications, load the existing file with `openpyxl.load_workbook(\"input.xlsx\", data_only=False)`, change the requested ranges, and save a separate result. Avoid a DataFrame round trip when workbook features must survive.\n\nWriting a formula does not calculate its result. openpyxl and XlsxWriter do not evaluate formulas; `data_only=True` returns cached values that may be absent or stale. When calculated results must be refreshed, load `office-recalculate`. Do not replace requested formulas with constants or report stale values as newly calculated results.\n\nDo not rename `.xls`, `.xlsb`, encrypted files, or macro-enabled files to `.xlsx`. They need an appropriate supported operation. `keep_vba=True` can preserve VBA package content in an XLSM workflow, but does not execute or edit macros and does not guarantee every advanced workbook feature survives. Preserve the original and verify such requirements explicitly.\n\n## Check and deliver\n\nRun the shared structural checker when `office-check` is available:\n\n```text\noffice-check <workbook.xlsx> --out <checks.json>\n```\n\nIt checks ZIP/XML integrity and internal relationships, and reports sheet names, populated-cell counts, and formula counts. Repeated `--contains TEXT` arguments check string cells and sheet names, and `--count N` checks sheet count. `--contains` excludes numeric cells and does not validate formula results; verify those separately with openpyxl. The checker does not calculate formulas or judge workbook appearance. Compare relevant values, types, formulas, styles, and totals with the task's source data.\n\nIf `office-check` is unavailable, use an already configured environment to check the ZIP/XML package and internal relationships. Report the missing environment if those checks cannot run; do not claim structural validation.\n\nLoad `office-render` for requested images or visual inspection and whenever the user's primary task targets appearance, including cell fill colors, text alignment, spacing, or sizing. These appearance changes require rendering even without a separate visual-check request, unless the user explicitly skips it. New workbooks and data or formula edits do not require rendering solely because they include incidental basic formatting. In particular, bold headers and number formats accompanying data edits do not require loading `office-render` or running its commands.\n\nLoad `office-recalculate` when refreshed calculated values are needeLine truncated
|
||||
{"type":"tool/result","data":{"turn":1,"step":2,"message":{"role":"tool","source":{"kind":"tool","callId":"call_office_2"},"toolCallId":"call_office_2","content":[{"type":"text","text":"<skill_content name=\"office-xlsx\">\n<skill_resources>\nBase directory for this skill: {{cwd}}/office-skills/office-xlsx\nResolve relative paths mentioned by this skill against the base directory before using them. Load referenced resources only as needed.\n</skill_resources>\n\n<skill_instructions>\n# Excel workbooks\n\nFollow an explicit user or applicable AGENTS.md requirement for an environment or library. Otherwise call `load_workspace_dependencies` and run its Python executable with bundled `openpyxl` and `pandas`. Do not install packages or search for a system Python for the default workflow. If the tool is unavailable, use an already configured environment and report a missing dependency only when it prevents the requested operation.\n\nKeep scripts, working files, and outputs in the task workspace. The runtime and skill directory are shared read-only resources. Save to a new workbook unless the user requests an in-place edit.\n\n## Read and modify\n\nUse `openpyxl` for existing XLSX workbooks and targeted cell or style changes. Load with `data_only=False` when formulas must survive. Inspect sheet names, the affected cell types, formulas, styles, merged ranges, and referenced ranges before editing. Check the saved file by reopening it, including unchanged content that the request requires preserving.\n\nUse pandas for data analysis and transformations. A DataFrame is not the workbook: exporting it over an existing file can lose sheets, formulas, charts, and formatting. Write analysis results back to the intended ranges with openpyxl. `XlsxWriter` can create new workbooks, but cannot read or modify existing ones.\n\nFor a new workbook, the selected Python environment can write editable values, styles, and formulas directly:\n\n```python\nfrom openpyxl import Workbook\nfrom openpyxl.styles import Font\n\nworkbook = Workbook()\nsheet = workbook.active\nsheet.title = \"Revenue\"\nfor row in [(\"Quarter\", \"Revenue\"), (\"Q1\", 12), (\"Q2\", 18), (\"Total\", \"=SUM(B2:B3)\")]:\n sheet.append(row)\nfor cell in sheet[1]:\n cell.font = Font(bold=True)\nsheet.column_dimensions[\"A\"].width = 18\nsheet.column_dimensions[\"B\"].width = 18\nworkbook.save(\"report.xlsx\")\n```\n\nPreserve numbers, dates, booleans, and identifiers as the intended cell types; formatting is not a type conversion. For modifications, load the existing file with `openpyxl.load_workbook(\"input.xlsx\", data_only=False)`, change the requested ranges, and save a separate result. Avoid a DataFrame round trip when workbook features must survive.\n\nWriting a formula does not calculate its result. openpyxl and XlsxWriter do not evaluate formulas; `data_only=True` returns cached values that may be absent or stale. When calculated results must be refreshed, load `office-recalculate`. Do not replace requested formulas with constants or report stale values as newly calculated results.\n\nDo not rename `.xls`, `.xlsb`, encrypted files, or macro-enabled files to `.xlsx`. They need an appropriate supported operation. `keep_vba=True` can preserve VBA package content in an XLSM workflow, but does not execute or edit macros and does not guarantee every advanced workbook feature survives. Preserve the original and verify such requirements explicitly.\n\n## Check and deliver\n\nRun the shared structural checker when `office-check` is available:\n\nIn PowerShell, prefix the quoted Python executable with `&`. Resolve the checker path relative to this skill directory.\n\n```text\n\"<python>\" \"<skill-directory>/../scripts/check_office.py\" <workbook.xlsx> --out <checks.json>\n```\n\nIt checks ZIP/XML integrity and internal relationships, and reports sheet names, populated-cell counts, and formula counts. Repeated `--contains TEXT` arguments check string cells and sheet names, and `--count N` checks sheet count. `--contains` excludes numeric cells and does not validate formula results; verify those separately with openpyxl. The checker does not calculate formulas or judge workbook appearance. Compare relevant values, types, formulas, styles, and totals with the task's source data.\n\nIf the Python checker cannot run, use an already configured environment to check the ZIP/XML package and internal relationships. Report the missing environment if those checks cannot run; do not claim structural validation.\n\nLoad `office-render` for requested images or visual inspection and whenever the user's primary task targets appearance, including cell fill colors, text alignment, spacing, or sizing. These appearance changes require rendering even without a separate visual-check request, unless the user explicitly skips it. New workbooks and data or formula edits do not require rendering solely because they include incidental basic formatting. In particular, bold headers and nuLine truncated
|
||||
{"type":"step/end","data":{"turn":1,"step":2}}
|
||||
{"type":"step/start","data":{"turn":1,"step":3}}
|
||||
{"type":"assistant/message","data":{"turn":1,"step":3,"message":{"role":"assistant","content":[{"type":"tool-call","id":"call_office_3","name":"skill","arguments":"{\"name\":\"office-recalculate\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{message:9}}"},"stream":[{"type":"chunk","time":1791559898470,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}},{"type":"tool-call-chunks","time0":1791559898470,"index":0,"dt":[],"id":"call_office_3","name":"skill","args":["{\"name\":\"office-recalculate\"}"]},{"type":"chunk","time":1791559898470,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"call_office_3","name":"skill","arguments":"{\"name\":\"office-recalculate\"}"}}},{"type":"chunk","time":1791559898470,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}]},"surfaceOp":"append"}
|
||||
{"type":"tool/call","data":{"turn":1,"step":3,"callId":"call_office_3","name":"skill","arguments":"{\"name\":\"office-recalculate\"}"}}
|
||||
{"type":"tool/result","data":{"turn":1,"step":3,"message":{"role":"tool","source":{"kind":"tool","callId":"call_office_3"},"toolCallId":"call_office_3","content":[{"type":"text","text":"<skill_content name=\"office-recalculate\">\n<skill_resources>\nBase directory for this skill: {{cwd}}/office-skills/office-recalculate\nResolve relative paths mentioned by this skill against the base directory before using them. Load referenced resources only as needed.\n</skill_resources>\n\n<skill_instructions>\n# Recalculate spreadsheet formulas\n\nUse the installed LibreOffice Kit CLI through the shell with `dsoffice`. Prefer bundled LibreOffice unless the user requests another installation. If the Office sidecar is missing, follow [sidecar setup](../office/references/sidecar.md): ask whether the user wants to download it and install only after they agree. Do not invoke system soffice, use npx, or install a replacement to work around a failed recalculation with an installed sidecar.\n\nKeep the original workbook and write a new file in the task workspace. Quote each input and output path.\n\n```text\ndsoffice recalculate --input <workbook.xlsx> --output <recalculated.xlsx>\n```\n\nVerify the saved result with openpyxl, using `load_workspace_dependencies` for the Python path unless a project environment is required. Open it with both `data_only=False` and `data_only=True`. Check that formulas survive and cached results match the requested logic, expected totals, and cell types. Check required unchanged sheets, styles, and data. Recalculation does not validate business logic or guarantee Excel-specific feature compatibility.\n\nIf no supported recalculation engine is available or the command fails, preserve the workbook and explain that calculated values could not be refreshed. Do not replace requested formulas with constants or present stale/absent caches as fresh results. Deliver the verified output through `present` when available, keeping the file in place.\n</skill_instructions>\n</skill_content>"}],"isError":false,"id":"{{message:10}}"}},"sourceEventSeqs":[25],"surfaceOp":"append"}
|
||||
{"type":"tool/result","data":{"turn":1,"step":3,"message":{"role":"tool","source":{"kind":"tool","callId":"call_office_3"},"toolCallId":"call_office_3","content":[{"type":"text","text":"<skill_content name=\"office-recalculate\">\n<skill_resources>\nBase directory for this skill: {{cwd}}/office-skills/office-recalculate\nResolve relative paths mentioned by this skill against the base directory before using them. Load referenced resources only as needed.\n</skill_resources>\n\n<skill_instructions>\n# Recalculate spreadsheet formulas\n\nUse the installed LibreOffice Kit CLI through the shell with the absolute Node and CLI paths supplied below. In Bash, invoke `\"<node>\" \"<cli>\"`; in PowerShell, invoke `& \"<node>\" \"<cli>\"`. Prefer bundled LibreOffice unless the user requests another installation. If the Office sidecar is missing, follow [sidecar setup](../office/references/sidecar.md): ask whether the user wants to download it and install only after they agree. Do not invoke system soffice, use npx, or install a replacement to work around a failed recalculation with an installed sidecar.\n\nKeep the original workbook and write a new file in the task workspace. Quote each input and output path.\n\n```text\n\"<node>\" \"<cli>\" recalculate --input <workbook.xlsx> --output <recalculated.xlsx>\n```\n\nVerify the saved result with openpyxl, using `load_workspace_dependencies` for the Python path unless a project environment is required. Open it with both `data_only=False` and `data_only=True`. Check that formulas survive and cached results match the requested logic, expected totals, and cell types. Check required unchanged sheets, styles, and data. Recalculation does not validate business logic or guarantee Excel-specific feature compatibility.\n\nIf no supported recalculation engine is available or the command fails, preserve the workbook and explain that calculated values could not be refreshed. Do not replace requested formulas with constants or present stale/absent caches as fresh results. Deliver the verified output through `present` when available, keeping the file in place.\n\n## Installed LibreOffice Kit\n\nUse these absolute paths for every LibreOffice Kit command. Pass the CLI entry as the first argument to Node.\n\n{\n \"libreofficeKit\": {\n \"node\": \"{{cwd}}/office-node\",\n \"cli\": \"{{cwd}}/render-cli.cjs\"\n }\n}\n</skill_instructions>\n</skill_content>"}],"isError":false,"id":"{{message:10}}"}},"sourceEventSeqs":[25],"surfaceOp":"append"}
|
||||
{"type":"step/end","data":{"turn":1,"step":3}}
|
||||
{"type":"step/start","data":{"turn":1,"step":4}}
|
||||
{"type":"assistant/message","data":{"turn":1,"step":4,"message":{"role":"assistant","content":[{"type":"tool-call","id":"call_office_4","name":"skill","arguments":"{\"name\":\"office-export-pdf\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{message:11}}"},"stream":[{"type":"chunk","time":1791559898486,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}},{"type":"tool-call-chunks","time0":1791559898486,"index":0,"dt":[],"id":"call_office_4","name":"skill","args":["{\"name\":\"office-export-pdf\"}"]},{"type":"chunk","time":1791559898486,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"call_office_4","name":"skill","arguments":"{\"name\":\"office-export-pdf\"}"}}},{"type":"chunk","time":1791559898486,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}]},"surfaceOp":"append"}
|
||||
{"type":"tool/call","data":{"turn":1,"step":4,"callId":"call_office_4","name":"skill","arguments":"{\"name\":\"office-export-pdf\"}"}}
|
||||
{"type":"tool/result","data":{"turn":1,"step":4,"message":{"role":"tool","source":{"kind":"tool","callId":"call_office_4"},"toolCallId":"call_office_4","content":[{"type":"text","text":"<skill_content name=\"office-export-pdf\">\n<skill_resources>\nBase directory for this skill: {{cwd}}/office-skills/office-export-pdf\nResolve relative paths mentioned by this skill against the base directory before using them. Load referenced resources only as needed.\n</skill_resources>\n\n<skill_instructions>\n# Export an Office document to PDF\n\nUse the installed LibreOffice Kit CLI through the shell with `dsoffice`. Prefer bundled LibreOffice unless the user requests another installation. If the Office sidecar is missing, follow [sidecar setup](../office/references/sidecar.md): ask whether the user wants to download it and install only after they agree. Do not invoke system soffice, use npx, or install a replacement to work around a failed conversion with an installed sidecar.\n\nConvert the final saved Office file to a new PDF in the task workspace. Preserve the source. Quote each input and output path.\n\n```text\ndsoffice convert --input <final-office-file> --output <new-file.pdf>\n```\n\nCheck the command result, nonempty output, and `%PDF-` file signature. If a PDF reader library is already available, compare page count and extractable text with the requested content. If it is unavailable, report the extent of validation; do not generate images or install extra tools to validate a conversion. Spreadsheet PDF pages follow workbook print settings; change those settings only when requested. Conversion may differ from the native application's pagination or fonts.\n\nIf export fails, preserve the usable source and report the export limitation. Do not repeatedly convert an unchanged source or use conversion to investigate a failed preview. For PDF export alone, stop after these checks. Only a request for images or visual inspection calls for `office-render`; load it before that separate operation. Deliver the requested PDF through `present` when available, keeping the file in place.\n</skill_instructions>\n</skill_content>"}],"isError":false,"id":"{{message:12}}"}},"sourceEventSeqs":[30],"surfaceOp":"append"}
|
||||
{"type":"tool/result","data":{"turn":1,"step":4,"message":{"role":"tool","source":{"kind":"tool","callId":"call_office_4"},"toolCallId":"call_office_4","content":[{"type":"text","text":"<skill_content name=\"office-export-pdf\">\n<skill_resources>\nBase directory for this skill: {{cwd}}/office-skills/office-export-pdf\nResolve relative paths mentioned by this skill against the base directory before using them. Load referenced resources only as needed.\n</skill_resources>\n\n<skill_instructions>\n# Export an Office document to PDF\n\nUse the installed LibreOffice Kit CLI through the shell with the absolute Node and CLI paths supplied below. In Bash, invoke `\"<node>\" \"<cli>\"`; in PowerShell, invoke `& \"<node>\" \"<cli>\"`. Prefer bundled LibreOffice unless the user requests another installation. If the Office sidecar is missing, follow [sidecar setup](../office/references/sidecar.md): ask whether the user wants to download it and install only after they agree. Do not invoke system soffice, use npx, or install a replacement to work around a failed conversion with an installed sidecar.\n\nConvert the final saved Office file to a new PDF in the task workspace. Preserve the source. Quote each input and output path.\n\n```text\n\"<node>\" \"<cli>\" convert --input <final-office-file> --output <new-file.pdf>\n```\n\nCheck the command result, nonempty output, and `%PDF-` file signature. If a PDF reader library is already available, compare page count and extractable text with the requested content. If it is unavailable, report the extent of validation; do not generate images or install extra tools to validate a conversion. Spreadsheet PDF pages follow workbook print settings; change those settings only when requested. Conversion may differ from the native application's pagination or fonts.\n\nIf export fails, preserve the usable source and report the export limitation. Do not repeatedly convert an unchanged source or use conversion to investigate a failed preview. For PDF export alone, stop after these checks. Only a request for images or visual inspection calls for `office-render`; load it before that separate operation. Deliver the requested PDF through `present` when available, keeping the file in place.\n\n## Installed LibreOffice Kit\n\nUse these absolute paths for every LibreOffice Kit command. Pass the CLI entry as the first argument to Node.\n\n{\n \"libreofficeKit\": {\n \"node\": \"{{cwd}}/office-node\",\n \"cli\": \"{{cwd}}/render-cli.cjs\"\n }\n}\n</skill_instructions>\n</skill_content>"}],"isError":false,"id":"{{message:12}}"}},"sourceEventSeqs":[30],"surfaceOp":"append"}
|
||||
{"type":"step/end","data":{"turn":1,"step":4}}
|
||||
{"type":"step/start","data":{"turn":1,"step":5}}
|
||||
{"type":"assistant/message","data":{"turn":1,"step":5,"message":{"role":"assistant","content":[{"type":"text","text":"DONE"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{message:13}}"},"usage":{"inputTokens":12,"outputTokens":2,"cacheReadTokens":10},"stream":[{"type":"chunk","time":1791559898502,"chunk":{"type":"block-start","index":0,"blockType":"text"}},{"type":"text-chunks","time0":1791559898502,"index":0,"dt":[],"texts":["DONE"]},{"type":"chunk","time":1791559898502,"chunk":{"type":"block-end","index":0,"block":{"type":"text","text":"DONE"}}},{"type":"chunk","time":1791559898502,"chunk":{"type":"usage","usage":{"inputTokens":12,"outputTokens":2,"cacheReadTokens":10}}},{"type":"chunk","time":1791559898502,"chunk":{"type":"finish","reason":{"kind":"stop"}}}]},"surfaceOp":"append"}
|
||||
|
||||
@@ -26,33 +26,33 @@
|
||||
{"type":"assistant/message","data":{"turn":1,"step":2,"message":{"role":"assistant","content":[{"type":"tool-call","id":"call_office_2","name":"run_code","arguments":"{\"code\":\"console.log(await tools.skill({\\\"name\\\":\\\"office-docx\\\"}));\",\"description\":\"Load task instructions\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{message:8}}"},"stream":[{"type":"chunk","time":1791559899691,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}},{"type":"tool-call-chunks","time0":1791559899691,"index":0,"dt":[],"id":"call_office_2","name":"run_code","args":["{\"code\":\"console.log(await tools.skill({\\\"name\\\":\\\"office-docx\\\"}));\",\"description\":\"Load task instructions\"}"]},{"type":"chunk","time":1791559899691,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"call_office_2","name":"run_code","arguments":"{\"code\":\"console.log(await tools.skill({\\\"name\\\":\\\"office-docx\\\"}));\",\"description\":\"Load task instructions\"}"}}},{"type":"chunk","time":1791559899691,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}]},"surfaceOp":"append"}
|
||||
{"type":"tool/call","data":{"turn":1,"step":2,"callId":"call_office_2","name":"run_code","arguments":"{\"code\":\"console.log(await tools.skill({\\\"name\\\":\\\"office-docx\\\"}));\",\"description\":\"Load task instructions\"}"}}
|
||||
{"type":"tool/ptc-dispatch-start","data":{"rootCallId":"call_office_2","parentCallId":"call_office_2","subCallId":"call_office_2:ptc:1","name":"skill","arguments":{"name":"office-docx"}}}
|
||||
{"type":"tool/ptc-dispatch","data":{"rootCallId":"call_office_2","parentCallId":"call_office_2","subCallId":"call_office_2:ptc:1","name":"skill","arguments":{"name":"office-docx"},"isError":false,"content":[{"type":"text","text":"<skill_content name=\"office-docx\">\n<skill_resources>\nBase directory for this skill: {{cwd}}/office-skills/office-docx\nResolve relative paths mentioned by this skill against the base directory before using them. Load referenced resources only as needed.\n</skill_resources>\n\n<skill_instructions>\n# Word documents\n\nUse `python-docx` for DOCX creation and ordinary edits. Follow an explicit user or applicable AGENTS.md requirement for a project environment or another library. Otherwise call `load_workspace_dependencies` and execute the returned Python path with its bundled libraries. Do not install packages or discover a system Python for the default workflow. If the tool is unavailable, use an already configured environment and report a missing dependency only when it prevents the requested operation.\n\nKeep source scripts, intermediate files, and final documents in the task workspace; the runtime and this skill directory are read-only resources. Use the user's requested language and preserve an existing document's design unless a redesign is requested.\n\n## Create and edit\n\nFor existing files, inspect paragraphs, runs, tables, sections, headers, and footers before changing the affected content. Save to a new file unless the user requests an in-place edit. Replacing a paragraph's `.text` destroys its run formatting; change the relevant runs when formatting must survive. Reconstructing the whole document can lose features outside python-docx's supported editing API.\n\nUse paragraph styles for headings and body text. Size tables for the section that contains them, and account for merged cells and nested tables. Chinese, Japanese, and Korean text may need an explicit `w:eastAsia` font assignment in addition to `run.font.name`; font names alone do not establish glyph availability or rendered appearance.\n\nFor a new document, use the selected Python executable:\n\n```python\nfrom docx import Document\n\ndocument = Document()\ndocument.add_heading(\"Project report\", level=0)\ndocument.add_paragraph(\"Summary\", style=\"Heading 1\")\ndocument.add_paragraph(\"The requested findings go here.\")\ndocument.save(\"report.docx\")\n```\n\npython-docx does not paginate or render documents. Do not represent ordinary replacement, colored text, or comments as tracked changes. When real revisions or unsupported OOXML features matter, preserve their package parts and verify the requested operation rather than silently discarding them.\n\n## Check and deliver\n\nRun the shared structural checker when `office-check` is available:\n\n```text\noffice-check <document.docx> --out <checks.json>\n```\n\nIt checks ZIP/XML integrity and internal relationships, and reports paragraphs, logical table dimensions, and sections. Optional `--contains TEXT` arguments assert required text. A successful structural check does not verify pagination, clipping, fonts, or visual appearance. Compare the summary and reopened document with the user's request, including unchanged content that matters to an edit.\n\nIf `office-check` is unavailable, use an already configured environment to check the ZIP/XML package and internal relationships. Report the missing environment if those checks cannot run; do not claim structural validation.\n\nDeliver after the requested content and structural checks pass. Creating a file or changing content with incidental basic formatting does not require additional operations. Load `office-render` for requested images or visual inspection and for appearance-focused styling, spacing, sizing, or alignment changes unless the user explicitly skips rendering. For PDF output load `office-export-pdf`.\n\nCall `present({\"files\":[{\"path\":\"report.docx\"}]})` with the actual final DOCX path. It exposes the current source file without copying or preserving its bytes, so keep that file in place and do not present temporary QA reports unless requested. If `present` is unavailable, provide the final workspace path using the session's supported file delivery method.\n</skill_instructions>\n</skill_content>"}]}}
|
||||
{"type":"tool/result","data":{"turn":1,"step":2,"message":{"role":"tool","source":{"kind":"tool","callId":"call_office_2"},"toolCallId":"call_office_2","content":[{"type":"text","text":"{\n name: 'office-docx',\n provider: 'dsh-office',\n resourceBase: {\n kind: 'directory',\n path: '{{cwd}}/office-skills/office-docx'\n },\n content: '# Word documents\\n' +\n '\\n' +\n 'Use `python-docx` for DOCX creation and ordinary edits. Follow an explicit user or applicable AGENTS.md requirement for a project environment or another library. Otherwise call `load_workspace_dependencies` and execute the returned Python path with its bundled libraries. Do not install packages or discover a system Python for the default workflow. If the tool is unavailable, use an already configured environment and report a missing dependency only when it prevents the requested operation.\\n' +\n '\\n' +\n \"Keep source scripts, intermediate files, and final documents in the task workspace; the runtime and this skill directory are read-only resources. Use the user's requested language and preserve an existing document's design unless a redesign is requested.\\n\" +\n '\\n' +\n '## Create and edit\\n' +\n '\\n' +\n \"For existing files, inspect paragraphs, runs, tables, sections, headers, and footers before changing the affected content. Save to a new file unless the user requests an in-place edit. Replacing a paragraph's `.text` destroys its run formatting; change the relevant runs when formatting must survive. Reconstructing the whole document can lose features outside python-docx's supported editing API.\\n\" +\n '\\n' +\n 'Use paragraph styles for headings and body text. Size tables for the section that contains them, and account for merged cells and nested tables. Chinese, Japanese, and Korean text may need an explicit `w:eastAsia` font assignment in addition to `run.font.name`; font names alone do not establish glyph availability or rendered appearance.\\n' +\n '\\n' +\n 'For a new document, use the selected Python executable:\\n' +\n '\\n' +\n '```python\\n' +\n 'from docx import Document\\n' +\n '\\n' +\n 'document = Document()\\n' +\n 'document.add_heading(\"Project report\", level=0)\\n' +\n 'document.add_paragraph(\"Summary\", style=\"Heading 1\")\\n' +\n 'document.add_paragraph(\"The requested findings go here.\")\\n' +\n 'document.save(\"report.docx\")\\n' +\n '```\\n' +\n '\\n' +\n 'python-docx does not paginate or render documents. Do not represent ordinary replacement, colored text, or comments as tracked changes. When real revisions or unsupported OOXML features matter, preserve their package parts and verify the requested operation rather than silently discarding them.\\n' +\n '\\n' +\n '## Check and deliver\\n' +\n '\\n' +\n 'Run the shared structural checker when `office-check` is available:\\n' +\n '\\n' +\n '```text\\n' +\n 'office-check <document.docx> --out <checks.json>\\n' +\n '```\\n' +\n '\\n' +\n \"It checks ZIP/XML integrity and internal relationships, and reports paragraphs, logical table dimensions, and sections. Optional `--contains TEXT` arguments assert required text. A successful structural check does not verify pagination, clipping, fonts, or visual appearance. Compare the summary and reopened document with the user's request, including unchanged content that matters to an edit.\\n\" +\n '\\n' +\n 'If `office-check` is unavailable, use an already configured environment to check the ZIP/XML package and internal relationships. Report the missing environment if those checks cannot run; do not claim structural validation.\\n' +\n '\\n' +\n 'Deliver after the requested content and structural checks pass. Creating a file or changing content with incidental basic formatting does not require additional operations. Load `office-render` for requested images or visual inspection and for appearance-focused styling, spacing, sizing, or alignment changes unless the user explicitly skips rendering. For PDF output load `office-export-pdf`.\\n' +\n '\\n' +\n 'Call `present({\"files\":[{\"path\":\"report.docx\"}]})` with the actual final DOCX path. It exposes the current source file without copying or preserving its bytes, so keep that file in place and do not present temporary QA reports unless requested. If `present` is unavailable, provide the final workspace path using the session\\'s supported file delivery method.'\n}"}],"isError":false,"id":"{{message:9}}"}},"sourceEventSeqs":[25],"surfaceOp":"append"}
|
||||
{"type":"agent/inbox/spliced","data":{"target":"next-step","start":0,"inserted":[{"content":[{"type":"text","text":"<skill_content name=\"office-docx\">\n<skill_resources>\nBase directory for this skill: {{cwd}}/office-skills/office-docx\nResolve relative paths mentioned by this skill against the base directory before using them. Load referenced resources only as needed.\n</skill_resources>\n\n<skill_instructions>\n# Word documents\n\nUse `python-docx` for DOCX creation and ordinary edits. Follow an explicit user or applicable AGENTS.md requirement for a project environment or another library. Otherwise call `load_workspace_dependencies` and execute the returned Python path with its bundled libraries. Do not install packages or discover a system Python for the default workflow. If the tool is unavailable, use an already configured environment and report a missing dependency only when it prevents the requested operation.\n\nKeep source scripts, intermediate files, and final documents in the task workspace; the runtime and this skill directory are read-only resources. Use the user's requested language and preserve an existing document's design unless a redesign is requested.\n\n## Create and edit\n\nFor existing files, inspect paragraphs, runs, tables, sections, headers, and footers before changing the affected content. Save to a new file unless the user requests an in-place edit. Replacing a paragraph's `.text` destroys its run formatting; change the relevant runs when formatting must survive. Reconstructing the whole document can lose features outside python-docx's supported editing API.\n\nUse paragraph styles for headings and body text. Size tables for the section that contains them, and account for merged cells and nested tables. Chinese, Japanese, and Korean text may need an explicit `w:eastAsia` font assignment in addition to `run.font.name`; font names alone do not establish glyph availability or rendered appearance.\n\nFor a new document, use the selected Python executable:\n\n```python\nfrom docx import Document\n\ndocument = Document()\ndocument.add_heading(\"Project report\", level=0)\ndocument.add_paragraph(\"Summary\", style=\"Heading 1\")\ndocument.add_paragraph(\"The requested findings go here.\")\ndocument.save(\"report.docx\")\n```\n\npython-docx does not paginate or render documents. Do not represent ordinary replacement, colored text, or comments as tracked changes. When real revisions or unsupported OOXML features matter, preserve their package parts and verify the requested operation rather than silently discarding them.\n\n## Check and deliver\n\nRun the shared structural checker when `office-check` is available:\n\n```text\noffice-check <document.docx> --out <checks.json>\n```\n\nIt checks ZIP/XML integrity and internal relationships, and reports paragraphs, logical table dimensions, and sections. Optional `--contains TEXT` arguments assert required text. A successful structural check does not verify pagination, clipping, fonts, or visual appearance. Compare the summary and reopened document with the user's request, including unchanged content that matters to an edit.\n\nIf `office-check` is unavailable, use an already configured environment to check the ZIP/XML package and internal relationships. Report the missing environment if those checks cannot run; do not claim structural validation.\n\nDeliver after the requested content and structural checks pass. Creating a file or changing content with incidental basic formatting does not require additional operations. Load `office-render` for requested images or visual inspection and for appearance-focused styling, spacing, sizing, or alignment changes unless the user explicitly skips rendering. For PDF output load `office-export-pdf`.\n\nCall `present({\"files\":[{\"path\":\"report.docx\"}]})` with the actual final DOCX path. It exposes the current source file without copying or preserving its bytes, so keep that file in place and do not present temporary QA reports unless requested. If `present` is unavailable, provide the final workspace path using the session's supported file delivery method.\n</skill_instructions>\n</skill_content>"}],"source":{"kind":"skill-invocation","name":"office-docx","form":"instructions"},"role":"user","id":"{{message:10}}"}]}}
|
||||
{"type":"tool/ptc-dispatch","data":{"rootCallId":"call_office_2","parentCallId":"call_office_2","subCallId":"call_office_2:ptc:1","name":"skill","arguments":{"name":"office-docx"},"isError":false,"content":[{"type":"text","text":"<skill_content name=\"office-docx\">\n<skill_resources>\nBase directory for this skill: {{cwd}}/office-skills/office-docx\nResolve relative paths mentioned by this skill against the base directory before using them. Load referenced resources only as needed.\n</skill_resources>\n\n<skill_instructions>\n# Word documents\n\nUse `python-docx` for DOCX creation and ordinary edits. Follow an explicit user or applicable AGENTS.md requirement for a project environment or another library. Otherwise call `load_workspace_dependencies` and execute the returned Python path with its bundled libraries. Do not install packages or discover a system Python for the default workflow. If the tool is unavailable, use an already configured environment and report a missing dependency only when it prevents the requested operation.\n\nKeep source scripts, intermediate files, and final documents in the task workspace; the runtime and this skill directory are read-only resources. Use the user's requested language and preserve an existing document's design unless a redesign is requested.\n\n## Create and edit\n\nFor existing files, inspect paragraphs, runs, tables, sections, headers, and footers before changing the affected content. Save to a new file unless the user requests an in-place edit. Replacing a paragraph's `.text` destroys its run formatting; change the relevant runs when formatting must survive. Reconstructing the whole document can lose features outside python-docx's supported editing API.\n\nUse paragraph styles for headings and body text. Size tables for the section that contains them, and account for merged cells and nested tables. Chinese, Japanese, and Korean text may need an explicit `w:eastAsia` font assignment in addition to `run.font.name`; font names alone do not establish glyph availability or rendered appearance.\n\nFor a new document, use the selected Python executable:\n\n```python\nfrom docx import Document\n\ndocument = Document()\ndocument.add_heading(\"Project report\", level=0)\ndocument.add_paragraph(\"Summary\", style=\"Heading 1\")\ndocument.add_paragraph(\"The requested findings go here.\")\ndocument.save(\"report.docx\")\n```\n\npython-docx does not paginate or render documents. Do not represent ordinary replacement, colored text, or comments as tracked changes. When real revisions or unsupported OOXML features matter, preserve their package parts and verify the requested operation rather than silently discarding them.\n\n## Check and deliver\n\nRun the shared structural checker when `office-check` is available:\n\nIn PowerShell, prefix the quoted Python executable with `&`. Resolve the checker path relative to this skill directory.\n\n```text\n\"<python>\" \"<skill-directory>/../scripts/check_office.py\" <document.docx> --out <checks.json>\n```\n\nIt checks ZIP/XML integrity and internal relationships, and reports paragraphs, logical table dimensions, and sections. Optional `--contains TEXT` arguments assert required text. A successful structural check does not verify pagination, clipping, fonts, or visual appearance. Compare the summary and reopened document with the user's request, including unchanged content that matters to an edit.\n\nIf the Python checker cannot run, use an already configured environment to check the ZIP/XML package and internal relationships. Report the missing environment if those checks cannot run; do not claim structural validation.\n\nDeliver after the requested content and structural checks pass. Creating a file or changing content with incidental basic formatting does not require additional operations. Load `office-render` for requested images or visual inspection. When styling, font color, spacing, sizing, or text alignment is the requested edit, load `office-render` and inspect the changed page even without a separate visual-check request, unless the user explicitly skips rendering. For PDF output load `office-export-pdf`.\n\nCall `present({\"files\":[{\"path\":\"report.docx\"}]})` with the actual final DOCX path. It exposes the current source file without copying or preserving its bytes, so keep that file in place and do not present temporary QA reports unless requested. If `present` is unavailable, provide the final workspace path using the session's supported file delivery method.\n</skill_instructions>\n</skill_content>"}]}}
|
||||
{"type":"tool/result","data":{"turn":1,"step":2,"message":{"role":"tool","source":{"kind":"tool","callId":"call_office_2"},"toolCallId":"call_office_2","content":[{"type":"text","text":"{\n name: 'office-docx',\n provider: 'dsh-office',\n resourceBase: {\n kind: 'directory',\n path: '{{cwd}}/office-skills/office-docx'\n },\n content: '# Word documents\\n' +\n '\\n' +\n 'Use `python-docx` for DOCX creation and ordinary edits. Follow an explicit user or applicable AGENTS.md requirement for a project environment or another library. Otherwise call `load_workspace_dependencies` and execute the returned Python path with its bundled libraries. Do not install packages or discover a system Python for the default workflow. If the tool is unavailable, use an already configured environment and report a missing dependency only when it prevents the requested operation.\\n' +\n '\\n' +\n \"Keep source scripts, intermediate files, and final documents in the task workspace; the runtime and this skill directory are read-only resources. Use the user's requested language and preserve an existing document's design unless a redesign is requested.\\n\" +\n '\\n' +\n '## Create and edit\\n' +\n '\\n' +\n \"For existing files, inspect paragraphs, runs, tables, sections, headers, and footers before changing the affected content. Save to a new file unless the user requests an in-place edit. Replacing a paragraph's `.text` destroys its run formatting; change the relevant runs when formatting must survive. Reconstructing the whole document can lose features outside python-docx's supported editing API.\\n\" +\n '\\n' +\n 'Use paragraph styles for headings and body text. Size tables for the section that contains them, and account for merged cells and nested tables. Chinese, Japanese, and Korean text may need an explicit `w:eastAsia` font assignment in addition to `run.font.name`; font names alone do not establish glyph availability or rendered appearance.\\n' +\n '\\n' +\n 'For a new document, use the selected Python executable:\\n' +\n '\\n' +\n '```python\\n' +\n 'from docx import Document\\n' +\n '\\n' +\n 'document = Document()\\n' +\n 'document.add_heading(\"Project report\", level=0)\\n' +\n 'document.add_paragraph(\"Summary\", style=\"Heading 1\")\\n' +\n 'document.add_paragraph(\"The requested findings go here.\")\\n' +\n 'document.save(\"report.docx\")\\n' +\n '```\\n' +\n '\\n' +\n 'python-docx does not paginate or render documents. Do not represent ordinary replacement, colored text, or comments as tracked changes. When real revisions or unsupported OOXML features matter, preserve their package parts and verify the requested operation rather than silently discarding them.\\n' +\n '\\n' +\n '## Check and deliver\\n' +\n '\\n' +\n 'Run the shared structural checker when `office-check` is available:\\n' +\n '\\n' +\n 'In PowerShell, prefix the quoted Python executable with `&`. Resolve the checker path relative to this skill directory.\\n' +\n '\\n' +\n '```text\\n' +\n '\"<python>\" \"<skill-directory>/../scripts/check_office.py\" <document.docx> --out <checks.json>\\n' +\n '```\\n' +\n '\\n' +\n \"It checks ZIP/XML integrity and internal relationships, and reports paragraphs, logical table dimensions, and sections. Optional `--contains TEXT` arguments assert required text. A successful structural check does not verify pagination, clipping, fonts, or visual appearance. Compare the summary and reopened document with the user's request, including unchanged content that matters to an edit.\\n\" +\n '\\n' +\n 'If the Python checker cannot run, use an already configured environment to check the ZIP/XML package and internal relationships. Report the missing environment if those checks cannot run; do not claim structural validation.\\n' +\n '\\n' +\n 'Deliver after the requested content and structural checks pass. Creating a file or changing content with incidental basic formatting does not require additional operations. Load `office-render` for requested images or visual inspection. When styling, font color, spacing, sizing, or text alignment is the requested edit, load `office-render` and inspect the changed page even without a separate visual-check request, unless the user explicitly skips rendering. For PDF output load `office-export-pdf`.\\n' +\n '\\n' +\n 'Call `present({\"files\":[{\"path\":\"report.docx\"}]})` with the actual final DOCX path. It exposes the current source file without copying or preserving its bytes, so keep that file in place and do not present temporary QA reports unless requested. If `present` is unavailable, provide the final workspace path using the session\\'s supported file delivery method.'\n}"}],"isError":false,"id":"{{message:9}}"}},"sourceEventSeqs":[25],"surfaceOp":"append"}
|
||||
{"type":"agent/inbox/spliced","data":{"target":"next-step","start":0,"inserted":[{"content":[{"type":"text","text":"<skill_content name=\"office-docx\">\n<skill_resources>\nBase directory for this skill: {{cwd}}/office-skills/office-docx\nResolve relative paths mentioned by this skill against the base directory before using them. Load referenced resources only as needed.\n</skill_resources>\n\n<skill_instructions>\n# Word documents\n\nUse `python-docx` for DOCX creation and ordinary edits. Follow an explicit user or applicable AGENTS.md requirement for a project environment or another library. Otherwise call `load_workspace_dependencies` and execute the returned Python path with its bundled libraries. Do not install packages or discover a system Python for the default workflow. If the tool is unavailable, use an already configured environment and report a missing dependency only when it prevents the requested operation.\n\nKeep source scripts, intermediate files, and final documents in the task workspace; the runtime and this skill directory are read-only resources. Use the user's requested language and preserve an existing document's design unless a redesign is requested.\n\n## Create and edit\n\nFor existing files, inspect paragraphs, runs, tables, sections, headers, and footers before changing the affected content. Save to a new file unless the user requests an in-place edit. Replacing a paragraph's `.text` destroys its run formatting; change the relevant runs when formatting must survive. Reconstructing the whole document can lose features outside python-docx's supported editing API.\n\nUse paragraph styles for headings and body text. Size tables for the section that contains them, and account for merged cells and nested tables. Chinese, Japanese, and Korean text may need an explicit `w:eastAsia` font assignment in addition to `run.font.name`; font names alone do not establish glyph availability or rendered appearance.\n\nFor a new document, use the selected Python executable:\n\n```python\nfrom docx import Document\n\ndocument = Document()\ndocument.add_heading(\"Project report\", level=0)\ndocument.add_paragraph(\"Summary\", style=\"Heading 1\")\ndocument.add_paragraph(\"The requested findings go here.\")\ndocument.save(\"report.docx\")\n```\n\npython-docx does not paginate or render documents. Do not represent ordinary replacement, colored text, or comments as tracked changes. When real revisions or unsupported OOXML features matter, preserve their package parts and verify the requested operation rather than silently discarding them.\n\n## Check and deliver\n\nRun the shared structural checker when `office-check` is available:\n\nIn PowerShell, prefix the quoted Python executable with `&`. Resolve the checker path relative to this skill directory.\n\n```text\n\"<python>\" \"<skill-directory>/../scripts/check_office.py\" <document.docx> --out <checks.json>\n```\n\nIt checks ZIP/XML integrity and internal relationships, and reports paragraphs, logical table dimensions, and sections. Optional `--contains TEXT` arguments assert required text. A successful structural check does not verify pagination, clipping, fonts, or visual appearance. Compare the summary and reopened document with the user's request, including unchanged content that matters to an edit.\n\nIf the Python checker cannot run, use an already configured environment to check the ZIP/XML package and internal relationships. Report the missing environment if those checks cannot run; do not claim structural validation.\n\nDeliver after the requested content and structural checks pass. Creating a file or changing content with incidental basic formatting does not require additional operations. Load `office-render` for requested images or visual inspection. When styling, font color, spacing, sizing, or text alignment is the requested edit, load `office-render` and inspect the changed page even without a separate visual-check request, unless the user explicitly skips rendering. For PDF output load `office-export-pdf`.\n\nCall `present({\"files\":[{\"path\":\"report.docx\"}]})` with the actual final DOCX path. It exposes the current source file without copying or preserving its bytes, so keep that file in place and do not present temporary QA reports unless requested. If `present` is unavailable, provide the final workspace path using the session's supported file delivery method.\n</skill_instructions>\n</skill_content>"}],"source":{"kind":"skill-invocation","name":"office-docx","form":"instructions"},"role":"user","id":"{{message:10}}"}]}}
|
||||
{"type":"step/end","data":{"turn":1,"step":2}}
|
||||
{"type":"agent/inbox/spliced","data":{"target":"next-step","start":0,"removedCount":1,"inserted":[]}}
|
||||
{"type":"step/start","data":{"turn":1,"step":3}}
|
||||
{"type":"user/message","data":{"content":[{"type":"text","text":"<skill_content name=\"office-docx\">\n<skill_resources>\nBase directory for this skill: {{cwd}}/office-skills/office-docx\nResolve relative paths mentioned by this skill against the base directory before using them. Load referenced resources only as needed.\n</skill_resources>\n\n<skill_instructions>\n# Word documents\n\nUse `python-docx` for DOCX creation and ordinary edits. Follow an explicit user or applicable AGENTS.md requirement for a project environment or another library. Otherwise call `load_workspace_dependencies` and execute the returned Python path with its bundled libraries. Do not install packages or discover a system Python for the default workflow. If the tool is unavailable, use an already configured environment and report a missing dependency only when it prevents the requested operation.\n\nKeep source scripts, intermediate files, and final documents in the task workspace; the runtime and this skill directory are read-only resources. Use the user's requested language and preserve an existing document's design unless a redesign is requested.\n\n## Create and edit\n\nFor existing files, inspect paragraphs, runs, tables, sections, headers, and footers before changing the affected content. Save to a new file unless the user requests an in-place edit. Replacing a paragraph's `.text` destroys its run formatting; change the relevant runs when formatting must survive. Reconstructing the whole document can lose features outside python-docx's supported editing API.\n\nUse paragraph styles for headings and body text. Size tables for the section that contains them, and account for merged cells and nested tables. Chinese, Japanese, and Korean text may need an explicit `w:eastAsia` font assignment in addition to `run.font.name`; font names alone do not establish glyph availability or rendered appearance.\n\nFor a new document, use the selected Python executable:\n\n```python\nfrom docx import Document\n\ndocument = Document()\ndocument.add_heading(\"Project report\", level=0)\ndocument.add_paragraph(\"Summary\", style=\"Heading 1\")\ndocument.add_paragraph(\"The requested findings go here.\")\ndocument.save(\"report.docx\")\n```\n\npython-docx does not paginate or render documents. Do not represent ordinary replacement, colored text, or comments as tracked changes. When real revisions or unsupported OOXML features matter, preserve their package parts and verify the requested operation rather than silently discarding them.\n\n## Check and deliver\n\nRun the shared structural checker when `office-check` is available:\n\n```text\noffice-check <document.docx> --out <checks.json>\n```\n\nIt checks ZIP/XML integrity and internal relationships, and reports paragraphs, logical table dimensions, and sections. Optional `--contains TEXT` arguments assert required text. A successful structural check does not verify pagination, clipping, fonts, or visual appearance. Compare the summary and reopened document with the user's request, including unchanged content that matters to an edit.\n\nIf `office-check` is unavailable, use an already configured environment to check the ZIP/XML package and internal relationships. Report the missing environment if those checks cannot run; do not claim structural validation.\n\nDeliver after the requested content and structural checks pass. Creating a file or changing content with incidental basic formatting does not require additional operations. Load `office-render` for requested images or visual inspection and for appearance-focused styling, spacing, sizing, or alignment changes unless the user explicitly skips rendering. For PDF output load `office-export-pdf`.\n\nCall `present({\"files\":[{\"path\":\"report.docx\"}]})` with the actual final DOCX path. It exposes the current source file without copying or preserving its bytes, so keep that file in place and do not present temporary QA reports unless requested. If `present` is unavailable, provide the final workspace path using the session's supported file delivery method.\n</skill_instructions>\n</skill_content>"}],"source":{"kind":"skill-invocation","name":"office-docx","form":"instructions"},"role":"user","id":"{{message:10}}"},"surfaceOp":"append"}
|
||||
{"type":"user/message","data":{"content":[{"type":"text","text":"<skill_content name=\"office-docx\">\n<skill_resources>\nBase directory for this skill: {{cwd}}/office-skills/office-docx\nResolve relative paths mentioned by this skill against the base directory before using them. Load referenced resources only as needed.\n</skill_resources>\n\n<skill_instructions>\n# Word documents\n\nUse `python-docx` for DOCX creation and ordinary edits. Follow an explicit user or applicable AGENTS.md requirement for a project environment or another library. Otherwise call `load_workspace_dependencies` and execute the returned Python path with its bundled libraries. Do not install packages or discover a system Python for the default workflow. If the tool is unavailable, use an already configured environment and report a missing dependency only when it prevents the requested operation.\n\nKeep source scripts, intermediate files, and final documents in the task workspace; the runtime and this skill directory are read-only resources. Use the user's requested language and preserve an existing document's design unless a redesign is requested.\n\n## Create and edit\n\nFor existing files, inspect paragraphs, runs, tables, sections, headers, and footers before changing the affected content. Save to a new file unless the user requests an in-place edit. Replacing a paragraph's `.text` destroys its run formatting; change the relevant runs when formatting must survive. Reconstructing the whole document can lose features outside python-docx's supported editing API.\n\nUse paragraph styles for headings and body text. Size tables for the section that contains them, and account for merged cells and nested tables. Chinese, Japanese, and Korean text may need an explicit `w:eastAsia` font assignment in addition to `run.font.name`; font names alone do not establish glyph availability or rendered appearance.\n\nFor a new document, use the selected Python executable:\n\n```python\nfrom docx import Document\n\ndocument = Document()\ndocument.add_heading(\"Project report\", level=0)\ndocument.add_paragraph(\"Summary\", style=\"Heading 1\")\ndocument.add_paragraph(\"The requested findings go here.\")\ndocument.save(\"report.docx\")\n```\n\npython-docx does not paginate or render documents. Do not represent ordinary replacement, colored text, or comments as tracked changes. When real revisions or unsupported OOXML features matter, preserve their package parts and verify the requested operation rather than silently discarding them.\n\n## Check and deliver\n\nRun the shared structural checker when `office-check` is available:\n\nIn PowerShell, prefix the quoted Python executable with `&`. Resolve the checker path relative to this skill directory.\n\n```text\n\"<python>\" \"<skill-directory>/../scripts/check_office.py\" <document.docx> --out <checks.json>\n```\n\nIt checks ZIP/XML integrity and internal relationships, and reports paragraphs, logical table dimensions, and sections. Optional `--contains TEXT` arguments assert required text. A successful structural check does not verify pagination, clipping, fonts, or visual appearance. Compare the summary and reopened document with the user's request, including unchanged content that matters to an edit.\n\nIf the Python checker cannot run, use an already configured environment to check the ZIP/XML package and internal relationships. Report the missing environment if those checks cannot run; do not claim structural validation.\n\nDeliver after the requested content and structural checks pass. Creating a file or changing content with incidental basic formatting does not require additional operations. Load `office-render` for requested images or visual inspection. When styling, font color, spacing, sizing, or text alignment is the requested edit, load `office-render` and inspect the changed page even without a separate visual-check request, unless the user explicitly skips rendering. For PDF output load `office-export-pdf`.\n\nCall `present({\"files\":[{\"path\":\"report.docx\"}]})` with the actual final DOCX path. It exposes the current source file without copying or preserving its bytes, so keep that file in place and do not present temporary QA reports unless requested. If `present` is unavailable, provide the final workspace path using the session's supported file delivery method.\n</skill_instructions>\n</skill_content>"}],"source":{"kind":"skill-invocation","name":"office-docx","form":"instructions"},"role":"user","id":"{{message:10}}"},"surfaceOp":"append"}
|
||||
{"type":"assistant/message","data":{"turn":1,"step":3,"message":{"role":"assistant","content":[{"type":"tool-call","id":"call_office_3","name":"run_code","arguments":"{\"code\":\"console.log(await tools.skill({\\\"name\\\":\\\"office-render\\\"}));\",\"description\":\"Load task instructions\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{message:11}}"},"stream":[{"type":"chunk","time":1791559899803,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}},{"type":"tool-call-chunks","time0":1791559899803,"index":0,"dt":[],"id":"call_office_3","name":"run_code","args":["{\"code\":\"console.log(await tools.skill({\\\"name\\\":\\\"office-render\\\"}));\",\"description\":\"Load task instructions\"}"]},{"type":"chunk","time":1791559899803,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"call_office_3","name":"run_code","arguments":"{\"code\":\"console.log(await tools.skill({\\\"name\\\":\\\"office-render\\\"}));\",\"description\":\"Load task instructions\"}"}}},{"type":"chunk","time":1791559899803,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}]},"surfaceOp":"append"}
|
||||
{"type":"tool/call","data":{"turn":1,"step":3,"callId":"call_office_3","name":"run_code","arguments":"{\"code\":\"console.log(await tools.skill({\\\"name\\\":\\\"office-render\\\"}));\",\"description\":\"Load task instructions\"}"}}
|
||||
{"type":"tool/ptc-dispatch-start","data":{"rootCallId":"call_office_3","parentCallId":"call_office_3","subCallId":"call_office_3:ptc:1","name":"skill","arguments":{"name":"office-render"}}}
|
||||
{"type":"tool/ptc-dispatch","data":{"rootCallId":"call_office_3","parentCallId":"call_office_3","subCallId":"call_office_3:ptc:1","name":"skill","arguments":{"name":"office-render"},"isError":false,"content":[{"type":"text","text":"<skill_content name=\"office-render\">\n<skill_resources>\nBase directory for this skill: {{cwd}}/office-skills/office-render\nResolve relative paths mentioned by this skill against the base directory before using them. Load referenced resources only as needed.\n</skill_resources>\n\n<skill_instructions>\n# Document images and visual inspection\n\nUse the installed LibreOffice Kit CLI through the shell with `dsoffice`. Prefer bundled LibreOffice unless the user requests another installation. If the Office sidecar is missing, follow [sidecar setup](../office/references/sidecar.md): ask whether the user wants to download it and install only after they agree. Do not invoke system soffice, use npx, install a replacement renderer, or build an alternative rendering pipeline to work around a failed render with an installed sidecar.\n\nBefore generating images only for inspection, establish that the current model accepts images. Otherwise finish the applicable content and structure checks and report the requested visual check as unavailable. Do not generate unreadable previews, retry image reads, or choose a second model. Requested image exports can still be delivered.\n\n## Render the saved deliverable\n\nKeep the saved deliverable in the task workspace. For requested image exports, use the requested output directory and retain the images. For inspection-only previews, create a private, uniquely named temporary parent inside that workspace and pass a child path that does not yet exist as `--output-dir`; the CLI creates that child. On POSIX, use `preview_root=$(mktemp -d \"./.dsh-office.XXXXXXXX\")` (owner-only permissions) and `--output-dir \"$preview_root/render\"`. On PowerShell, create a parent named `.dsh-office-` plus `[guid]::NewGuid().ToString('N')` under the task workspace and pass an uncreated `render` child; it inherits the workspace ACL. Quote each input and output path. Retain the parent until image inspection finishes, then remove only that parent, including after a failed render. Never use a fixed directory name or remove the workspace itself.\n\n```text\ndsoffice render --input <final-file> --output-dir <new-directory> --pages \"1,3,4\"\ndsoffice render --input <final-workbook.xlsx> --output-dir <new-directory> --sheet <exact-name> --range <A1-range>\n```\n\nFor DOCX, PPTX, or PDF, batch requested pages/slides in one call. In PowerShell, quote comma-separated `--pages` values so they remain one argument. Inspect all pages only for a requested whole-document review. For worksheets, choose the exact affected range, including chart/drawing regions; worksheet numbers are not PDF page numbers. Inspect the final saved file, reuse existing images for an unchanged source, and rerender only after requested source changes or for previously unrendered regions. Change print areas or scaling only when the user requests print layout.\n\nRead the returned JSON manifest for image paths, page counts, fragment rectangles, and missing-font diagnostics. Use the session's image-reading tool to inspect the requested images. Check clipping, alignment, headings, table widths, contrast, chart labels, and number formats as relevant to the task. A successful command or image read alone does not establish a usable preview; guessed text geometry does not establish overflow.\n\n## Failed or blank previews\n\nFor populated content, a fully transparent or uniformly blank image is a renderer failure. If a pixel check is needed, composite RGBA onto white first; raw RGB under transparent pixels can look nonblank. Check once and do not reread the same image. Stop visual checks for the task immediately after a blank result. This overrides the rerender-after-edit guidance above: do not render or read images again, even after editing or copying the source, or try another range, page, sheet, DPI, output format, diagnostic export, or print setting. Preserve the usable source and requested outputs and finish applicable content/data checks.\n\nIf content and structure checks pass, name the saved file and verified edits as needed, then include exactly one visual-status sentence: \"Content and structure checks passed; visual inspection was not completed.\" in English, or \"内容与结构检查通过;视觉检查未完成。\" in Chinese. Do not add a render or preview bullet, explain why inspection stopped, or describe the image or pixels. Report content or structure failures separately; never say all checks passed or claim visual verification.\n\nLibreOffice output can differ from Word, PowerPoint, or Excel. Images do not certify animation/media playback, refresh formula caches in the source workbook, or guarantee native application fidelity. Deliver requested files through `present` when available; keep the fiLine truncated
|
||||
{"type":"tool/result","data":{"turn":1,"step":3,"message":{"role":"tool","source":{"kind":"tool","callId":"call_office_3"},"toolCallId":"call_office_3","content":[{"type":"text","text":"{\n name: 'office-render',\n provider: 'dsh-office',\n resourceBase: {\n kind: 'directory',\n path: '{{cwd}}/office-skills/office-render'\n },\n content: '# Document images and visual inspection\\n' +\n '\\n' +\n 'Use the installed LibreOffice Kit CLI through the shell with `dsoffice`. Prefer bundled LibreOffice unless the user requests another installation. If the Office sidecar is missing, follow [sidecar setup](../office/references/sidecar.md): ask whether the user wants to download it and install only after they agree. Do not invoke system soffice, use npx, install a replacement renderer, or build an alternative rendering pipeline to work around a failed render with an installed sidecar.\\n' +\n '\\n' +\n 'Before generating images only for inspection, establish that the current model accepts images. Otherwise finish the applicable content and structure checks and report the requested visual check as unavailable. Do not generate unreadable previews, retry image reads, or choose a second model. Requested image exports can still be delivered.\\n' +\n '\\n' +\n '## Render the saved deliverable\\n' +\n '\\n' +\n 'Keep the saved deliverable in the task workspace. For requested image exports, use the requested output directory and retain the images. For inspection-only previews, create a private, uniquely named temporary parent inside that workspace and pass a child path that does not yet exist as `--output-dir`; the CLI creates that child. On POSIX, use `preview_root=$(mktemp -d \"./.dsh-office.XXXXXXXX\")` (owner-only permissions) and `--output-dir \"$preview_root/render\"`. On PowerShell, create a parent named `.dsh-office-` plus `[guid]::NewGuid().ToString(\\'N\\')` under the task workspace and pass an uncreated `render` child; it inherits the workspace ACL. Quote each input and output path. Retain the parent until image inspection finishes, then remove only that parent, including after a failed render. Never use a fixed directory name or remove the workspace itself.\\n' +\n '\\n' +\n '```text\\n' +\n 'dsoffice render --input <final-file> --output-dir <new-directory> --pages \"1,3,4\"\\n' +\n 'dsoffice render --input <final-workbook.xlsx> --output-dir <new-directory> --sheet <exact-name> --range <A1-range>\\n' +\n '```\\n' +\n '\\n' +\n 'For DOCX, PPTX, or PDF, batch requested pages/slides in one call. In PowerShell, quote comma-separated `--pages` values so they remain one argument. Inspect all pages only for a requested whole-document review. For worksheets, choose the exact affected range, including chart/drawing regions; worksheet numbers are not PDF page numbers. Inspect the final saved file, reuse existing images for an unchanged source, and rerender only after requested source changes or for previously unrendered regions. Change print areas or scaling only when the user requests print layout.\\n' +\n '\\n' +\n \"Read the returned JSON manifest for image paths, page counts, fragment rectangles, and missing-font diagnostics. Use the session's image-reading tool to inspect the requested images. Check clipping, alignment, headings, table widths, contrast, chart labels, and number formats as relevant to the task. A successful command or image read alone does not establish a usable preview; guessed text geometry does not establish overflow.\\n\" +\n '\\n' +\n '## Failed or blank previews\\n' +\n '\\n' +\n 'For populated content, a fully transparent or uniformly blank image is a renderer failure. If a pixel check is needed, composite RGBA onto white first; raw RGB under transparent pixels can look nonblank. Check once and do not reread the same image. Stop visual checks for the task immediately after a blank result. This overrides the rerender-after-edit guidance above: do not render or read images again, even after editing or copying the source, or try another range, page, sheet, DPI, output format, diagnostic export, or print setting. Preserve the usable source and requested outputs and finish applicable content/data checks.\\n' +\n '\\n' +\n 'If content and structure checks pass, name the saved file and verified edits as needed, then include exactly one visual-status sentence: \"Content and structure checks passed; visual inspection was not completed.\" in English, or \"内容与结构检查通过;视觉检查未完成。\" in Chinese. Do not add a render or preview bullet, explain why inspection stopped, or describe the image or pixels. Report content or structure failures separately; never say all checks passed or claim visual verification.\\n' +\n '\\n' +\n 'LibreOffice output can differ from Word, PowerPoint, or Excel. Images do not certify animation/media playback, refresh formula caches in the source workbook, or guarantee natiLine truncated
|
||||
{"type":"agent/inbox/spliced","data":{"target":"next-step","start":0,"inserted":[{"content":[{"type":"text","text":"<skill_content name=\"office-render\">\n<skill_resources>\nBase directory for this skill: {{cwd}}/office-skills/office-render\nResolve relative paths mentioned by this skill against the base directory before using them. Load referenced resources only as needed.\n</skill_resources>\n\n<skill_instructions>\n# Document images and visual inspection\n\nUse the installed LibreOffice Kit CLI through the shell with `dsoffice`. Prefer bundled LibreOffice unless the user requests another installation. If the Office sidecar is missing, follow [sidecar setup](../office/references/sidecar.md): ask whether the user wants to download it and install only after they agree. Do not invoke system soffice, use npx, install a replacement renderer, or build an alternative rendering pipeline to work around a failed render with an installed sidecar.\n\nBefore generating images only for inspection, establish that the current model accepts images. Otherwise finish the applicable content and structure checks and report the requested visual check as unavailable. Do not generate unreadable previews, retry image reads, or choose a second model. Requested image exports can still be delivered.\n\n## Render the saved deliverable\n\nKeep the saved deliverable in the task workspace. For requested image exports, use the requested output directory and retain the images. For inspection-only previews, create a private, uniquely named temporary parent inside that workspace and pass a child path that does not yet exist as `--output-dir`; the CLI creates that child. On POSIX, use `preview_root=$(mktemp -d \"./.dsh-office.XXXXXXXX\")` (owner-only permissions) and `--output-dir \"$preview_root/render\"`. On PowerShell, create a parent named `.dsh-office-` plus `[guid]::NewGuid().ToString('N')` under the task workspace and pass an uncreated `render` child; it inherits the workspace ACL. Quote each input and output path. Retain the parent until image inspection finishes, then remove only that parent, including after a failed render. Never use a fixed directory name or remove the workspace itself.\n\n```text\ndsoffice render --input <final-file> --output-dir <new-directory> --pages \"1,3,4\"\ndsoffice render --input <final-workbook.xlsx> --output-dir <new-directory> --sheet <exact-name> --range <A1-range>\n```\n\nFor DOCX, PPTX, or PDF, batch requested pages/slides in one call. In PowerShell, quote comma-separated `--pages` values so they remain one argument. Inspect all pages only for a requested whole-document review. For worksheets, choose the exact affected range, including chart/drawing regions; worksheet numbers are not PDF page numbers. Inspect the final saved file, reuse existing images for an unchanged source, and rerender only after requested source changes or for previously unrendered regions. Change print areas or scaling only when the user requests print layout.\n\nRead the returned JSON manifest for image paths, page counts, fragment rectangles, and missing-font diagnostics. Use the session's image-reading tool to inspect the requested images. Check clipping, alignment, headings, table widths, contrast, chart labels, and number formats as relevant to the task. A successful command or image read alone does not establish a usable preview; guessed text geometry does not establish overflow.\n\n## Failed or blank previews\n\nFor populated content, a fully transparent or uniformly blank image is a renderer failure. If a pixel check is needed, composite RGBA onto white first; raw RGB under transparent pixels can look nonblank. Check once and do not reread the same image. Stop visual checks for the task immediately after a blank result. This overrides the rerender-after-edit guidance above: do not render or read images again, even after editing or copying the source, or try another range, page, sheet, DPI, output format, diagnostic export, or print setting. Preserve the usable source and requested outputs and finish applicable content/data checks.\n\nIf content and structure checks pass, name the saved file and verified edits as needed, then include exactly one visual-status sentence: \"Content and structure checks passed; visual inspection was not completed.\" in English, or \"内容与结构检查通过;视觉检查未完成。\" in Chinese. Do not add a render or preview bullet, explain why inspection stopped, or describe the image or pixels. Report content or structure failures separately; never say all checks passed or claim visual verification.\n\nLibreOffice output can differ from Word, PowerPoint, or Excel. Images do not certify animation/media playback, refresh formula caches in the source workbook, or guarantee native application fidelity. Deliver requested files through `present` when available; keep the files in place. Do not deliver inspection images or reports unless requested.\n</skill_instructions>\n</skill_content>Line truncated
|
||||
{"type":"tool/ptc-dispatch","data":{"rootCallId":"call_office_3","parentCallId":"call_office_3","subCallId":"call_office_3:ptc:1","name":"skill","arguments":{"name":"office-render"},"isError":false,"content":[{"type":"text","text":"<skill_content name=\"office-render\">\n<skill_resources>\nBase directory for this skill: {{cwd}}/office-skills/office-render\nResolve relative paths mentioned by this skill against the base directory before using them. Load referenced resources only as needed.\n</skill_resources>\n\n<skill_instructions>\n# Document images and visual inspection\n\nUse the installed LibreOffice Kit CLI through the shell with the absolute Node and CLI paths supplied below. In Bash, invoke `\"<node>\" \"<cli>\"`; in PowerShell, invoke `& \"<node>\" \"<cli>\"`. Prefer bundled LibreOffice unless the user requests another installation. If the Office sidecar is missing, follow [sidecar setup](../office/references/sidecar.md): ask whether the user wants to download it and install only after they agree. Do not invoke system soffice, use npx, install a replacement renderer, or build an alternative rendering pipeline to work around a failed render with an installed sidecar.\n\nBefore generating images only for inspection, establish that the current model accepts images. Otherwise finish the applicable content and structure checks and report the requested visual check as unavailable. Do not generate unreadable previews, retry image reads, or choose a second model. Requested image exports can still be delivered.\n\n## Render the saved deliverable\n\nKeep the saved deliverable in the task workspace. For requested image exports, use the requested output directory and retain the images. For inspection-only previews, create a private, uniquely named temporary parent inside that workspace and pass a child path that does not yet exist as `--output-dir`; the CLI creates that child. On POSIX, use `preview_root=$(mktemp -d \"./.dsh-office.XXXXXXXX\")` (owner-only permissions) and `--output-dir \"$preview_root/render\"`. On PowerShell, create a parent named `.dsh-office-` plus `[guid]::NewGuid().ToString('N')` under the task workspace and pass an uncreated `render` child; it inherits the workspace ACL. Quote each input and output path. Retain the parent until image inspection finishes, then remove only that parent, including after a failed render. Never use a fixed directory name or remove the workspace itself.\n\n```text\n\"<node>\" \"<cli>\" render --input <final-file> --output-dir <new-directory> --pages \"1,3,4\"\n\"<node>\" \"<cli>\" render --input <final-workbook.xlsx> --output-dir <new-directory> --sheet <exact-name> --range <A1-range>\n```\n\nFor DOCX, PPTX, or PDF, batch requested pages/slides in one call. In PowerShell, quote comma-separated `--pages` values so they remain one argument. Inspect all pages only for a requested whole-document review. For worksheets, choose the exact affected range, including chart/drawing regions; worksheet numbers are not PDF page numbers. Inspect the final saved file, reuse existing images for an unchanged source, and rerender only after requested source changes or for previously unrendered regions. Change print areas or scaling only when the user requests print layout.\n\nRead the returned JSON manifest for image paths, page counts, fragment rectangles, and missing-font diagnostics. Use the session's image-reading tool to inspect the requested images. Check clipping, alignment, headings, table widths, contrast, chart labels, and number formats as relevant to the task. A successful command or image read alone does not establish a usable preview; guessed text geometry does not establish overflow.\n\n## Failed or blank previews\n\nFor populated content, a fully transparent or uniformly blank image is a renderer failure. If a pixel check is needed, composite RGBA onto white first; raw RGB under transparent pixels can look nonblank. Check once and do not reread the same image. Stop visual checks for the task immediately after a blank result. This overrides the rerender-after-edit guidance above: do not render or read images again, even after editing or copying the source, or try another range, page, sheet, DPI, output format, diagnostic export, or print setting. Preserve the usable source and requested outputs and finish applicable content/data checks.\n\nIf content and structure checks pass, name the saved file and verified edits as needed, then include exactly one visual-status sentence: \"Content and structure checks passed; visual inspection was not completed.\" in English, or \"内容与结构检查通过;视觉检查未完成。\" in Chinese. Do not add a render or preview bullet, explain why inspection stopped, or describe the image or pixels. Report content or structure failures separately; never say all checks passed or claim visual verification.\n\nLibreOffice output can differ from Word, PowerPoint, or Excel. Images do not certify animation/media playback, refresh foLine truncated
|
||||
{"type":"tool/result","data":{"turn":1,"step":3,"message":{"role":"tool","source":{"kind":"tool","callId":"call_office_3"},"toolCallId":"call_office_3","content":[{"type":"text","text":"{\n name: 'office-render',\n provider: 'dsh-office',\n resourceBase: {\n kind: 'directory',\n path: '{{cwd}}/office-skills/office-render'\n },\n content: '# Document images and visual inspection\\n' +\n '\\n' +\n 'Use the installed LibreOffice Kit CLI through the shell with the absolute Node and CLI paths supplied below. In Bash, invoke `\"<node>\" \"<cli>\"`; in PowerShell, invoke `& \"<node>\" \"<cli>\"`. Prefer bundled LibreOffice unless the user requests another installation. If the Office sidecar is missing, follow [sidecar setup](../office/references/sidecar.md): ask whether the user wants to download it and install only after they agree. Do not invoke system soffice, use npx, install a replacement renderer, or build an alternative rendering pipeline to work around a failed render with an installed sidecar.\\n' +\n '\\n' +\n 'Before generating images only for inspection, establish that the current model accepts images. Otherwise finish the applicable content and structure checks and report the requested visual check as unavailable. Do not generate unreadable previews, retry image reads, or choose a second model. Requested image exports can still be delivered.\\n' +\n '\\n' +\n '## Render the saved deliverable\\n' +\n '\\n' +\n 'Keep the saved deliverable in the task workspace. For requested image exports, use the requested output directory and retain the images. For inspection-only previews, create a private, uniquely named temporary parent inside that workspace and pass a child path that does not yet exist as `--output-dir`; the CLI creates that child. On POSIX, use `preview_root=$(mktemp -d \"./.dsh-office.XXXXXXXX\")` (owner-only permissions) and `--output-dir \"$preview_root/render\"`. On PowerShell, create a parent named `.dsh-office-` plus `[guid]::NewGuid().ToString(\\'N\\')` under the task workspace and pass an uncreated `render` child; it inherits the workspace ACL. Quote each input and output path. Retain the parent until image inspection finishes, then remove only that parent, including after a failed render. Never use a fixed directory name or remove the workspace itself.\\n' +\n '\\n' +\n '```text\\n' +\n '\"<node>\" \"<cli>\" render --input <final-file> --output-dir <new-directory> --pages \"1,3,4\"\\n' +\n '\"<node>\" \"<cli>\" render --input <final-workbook.xlsx> --output-dir <new-directory> --sheet <exact-name> --range <A1-range>\\n' +\n '```\\n' +\n '\\n' +\n 'For DOCX, PPTX, or PDF, batch requested pages/slides in one call. In PowerShell, quote comma-separated `--pages` values so they remain one argument. Inspect all pages only for a requested whole-document review. For worksheets, choose the exact affected range, including chart/drawing regions; worksheet numbers are not PDF page numbers. Inspect the final saved file, reuse existing images for an unchanged source, and rerender only after requested source changes or for previously unrendered regions. Change print areas or scaling only when the user requests print layout.\\n' +\n '\\n' +\n \"Read the returned JSON manifest for image paths, page counts, fragment rectangles, and missing-font diagnostics. Use the session's image-reading tool to inspect the requested images. Check clipping, alignment, headings, table widths, contrast, chart labels, and number formats as relevant to the task. A successful command or image read alone does not establish a usable preview; guessed text geometry does not establish overflow.\\n\" +\n '\\n' +\n '## Failed or blank previews\\n' +\n '\\n' +\n 'For populated content, a fully transparent or uniformly blank image is a renderer failure. If a pixel check is needed, composite RGBA onto white first; raw RGB under transparent pixels can look nonblank. Check once and do not reread the same image. Stop visual checks for the task immediately after a blank result. This overrides the rerender-after-edit guidance above: do not render or read images again, even after editing or copying the source, or try another range, page, sheet, DPI, output format, diagnostic export, or print setting. Preserve the usable source and requested outputs and finish applicable content/data checks.\\n' +\n '\\n' +\n 'If content and structure checks pass, name the saved file and verified edits as needed, then include exactly one visual-status sentence: \"Content and structure checks passed; visual inspection was not completed.\" in English, or \"内容与结构检查通过;视觉检查未完成。\" in Chinese. Do not add a render or preview bullet, explain why inspection stopped, or describe the image or pixels. Report content or structure failures separately; never say all checks passed or claim visual verification.\\n' +\n '\\n' +\n 'LibreOffice output can diffLine truncated
|
||||
{"type":"agent/inbox/spliced","data":{"target":"next-step","start":0,"inserted":[{"content":[{"type":"text","text":"<skill_content name=\"office-render\">\n<skill_resources>\nBase directory for this skill: {{cwd}}/office-skills/office-render\nResolve relative paths mentioned by this skill against the base directory before using them. Load referenced resources only as needed.\n</skill_resources>\n\n<skill_instructions>\n# Document images and visual inspection\n\nUse the installed LibreOffice Kit CLI through the shell with the absolute Node and CLI paths supplied below. In Bash, invoke `\"<node>\" \"<cli>\"`; in PowerShell, invoke `& \"<node>\" \"<cli>\"`. Prefer bundled LibreOffice unless the user requests another installation. If the Office sidecar is missing, follow [sidecar setup](../office/references/sidecar.md): ask whether the user wants to download it and install only after they agree. Do not invoke system soffice, use npx, install a replacement renderer, or build an alternative rendering pipeline to work around a failed render with an installed sidecar.\n\nBefore generating images only for inspection, establish that the current model accepts images. Otherwise finish the applicable content and structure checks and report the requested visual check as unavailable. Do not generate unreadable previews, retry image reads, or choose a second model. Requested image exports can still be delivered.\n\n## Render the saved deliverable\n\nKeep the saved deliverable in the task workspace. For requested image exports, use the requested output directory and retain the images. For inspection-only previews, create a private, uniquely named temporary parent inside that workspace and pass a child path that does not yet exist as `--output-dir`; the CLI creates that child. On POSIX, use `preview_root=$(mktemp -d \"./.dsh-office.XXXXXXXX\")` (owner-only permissions) and `--output-dir \"$preview_root/render\"`. On PowerShell, create a parent named `.dsh-office-` plus `[guid]::NewGuid().ToString('N')` under the task workspace and pass an uncreated `render` child; it inherits the workspace ACL. Quote each input and output path. Retain the parent until image inspection finishes, then remove only that parent, including after a failed render. Never use a fixed directory name or remove the workspace itself.\n\n```text\n\"<node>\" \"<cli>\" render --input <final-file> --output-dir <new-directory> --pages \"1,3,4\"\n\"<node>\" \"<cli>\" render --input <final-workbook.xlsx> --output-dir <new-directory> --sheet <exact-name> --range <A1-range>\n```\n\nFor DOCX, PPTX, or PDF, batch requested pages/slides in one call. In PowerShell, quote comma-separated `--pages` values so they remain one argument. Inspect all pages only for a requested whole-document review. For worksheets, choose the exact affected range, including chart/drawing regions; worksheet numbers are not PDF page numbers. Inspect the final saved file, reuse existing images for an unchanged source, and rerender only after requested source changes or for previously unrendered regions. Change print areas or scaling only when the user requests print layout.\n\nRead the returned JSON manifest for image paths, page counts, fragment rectangles, and missing-font diagnostics. Use the session's image-reading tool to inspect the requested images. Check clipping, alignment, headings, table widths, contrast, chart labels, and number formats as relevant to the task. A successful command or image read alone does not establish a usable preview; guessed text geometry does not establish overflow.\n\n## Failed or blank previews\n\nFor populated content, a fully transparent or uniformly blank image is a renderer failure. If a pixel check is needed, composite RGBA onto white first; raw RGB under transparent pixels can look nonblank. Check once and do not reread the same image. Stop visual checks for the task immediately after a blank result. This overrides the rerender-after-edit guidance above: do not render or read images again, even after editing or copying the source, or try another range, page, sheet, DPI, output format, diagnostic export, or print setting. Preserve the usable source and requested outputs and finish applicable content/data checks.\n\nIf content and structure checks pass, name the saved file and verified edits as needed, then include exactly one visual-status sentence: \"Content and structure checks passed; visual inspection was not completed.\" in English, or \"内容与结构检查通过;视觉检查未完成。\" in Chinese. Do not add a render or preview bullet, explain why inspection stopped, or describe the image or pixels. Report content or structure failures separately; never say all checks passed or claim visual verification.\n\nLibreOffice output can differ from Word, PowerPoint, or Excel. Images do not certify animation/media playback, refresh formula caches in the source workbook, or guarantee native application fidelity. Deliver requested files through `presLine truncated
|
||||
{"type":"step/end","data":{"turn":1,"step":3}}
|
||||
{"type":"agent/inbox/spliced","data":{"target":"next-step","start":0,"removedCount":1,"inserted":[]}}
|
||||
{"type":"step/start","data":{"turn":1,"step":4}}
|
||||
{"type":"user/message","data":{"content":[{"type":"text","text":"<skill_content name=\"office-render\">\n<skill_resources>\nBase directory for this skill: {{cwd}}/office-skills/office-render\nResolve relative paths mentioned by this skill against the base directory before using them. Load referenced resources only as needed.\n</skill_resources>\n\n<skill_instructions>\n# Document images and visual inspection\n\nUse the installed LibreOffice Kit CLI through the shell with `dsoffice`. Prefer bundled LibreOffice unless the user requests another installation. If the Office sidecar is missing, follow [sidecar setup](../office/references/sidecar.md): ask whether the user wants to download it and install only after they agree. Do not invoke system soffice, use npx, install a replacement renderer, or build an alternative rendering pipeline to work around a failed render with an installed sidecar.\n\nBefore generating images only for inspection, establish that the current model accepts images. Otherwise finish the applicable content and structure checks and report the requested visual check as unavailable. Do not generate unreadable previews, retry image reads, or choose a second model. Requested image exports can still be delivered.\n\n## Render the saved deliverable\n\nKeep the saved deliverable in the task workspace. For requested image exports, use the requested output directory and retain the images. For inspection-only previews, create a private, uniquely named temporary parent inside that workspace and pass a child path that does not yet exist as `--output-dir`; the CLI creates that child. On POSIX, use `preview_root=$(mktemp -d \"./.dsh-office.XXXXXXXX\")` (owner-only permissions) and `--output-dir \"$preview_root/render\"`. On PowerShell, create a parent named `.dsh-office-` plus `[guid]::NewGuid().ToString('N')` under the task workspace and pass an uncreated `render` child; it inherits the workspace ACL. Quote each input and output path. Retain the parent until image inspection finishes, then remove only that parent, including after a failed render. Never use a fixed directory name or remove the workspace itself.\n\n```text\ndsoffice render --input <final-file> --output-dir <new-directory> --pages \"1,3,4\"\ndsoffice render --input <final-workbook.xlsx> --output-dir <new-directory> --sheet <exact-name> --range <A1-range>\n```\n\nFor DOCX, PPTX, or PDF, batch requested pages/slides in one call. In PowerShell, quote comma-separated `--pages` values so they remain one argument. Inspect all pages only for a requested whole-document review. For worksheets, choose the exact affected range, including chart/drawing regions; worksheet numbers are not PDF page numbers. Inspect the final saved file, reuse existing images for an unchanged source, and rerender only after requested source changes or for previously unrendered regions. Change print areas or scaling only when the user requests print layout.\n\nRead the returned JSON manifest for image paths, page counts, fragment rectangles, and missing-font diagnostics. Use the session's image-reading tool to inspect the requested images. Check clipping, alignment, headings, table widths, contrast, chart labels, and number formats as relevant to the task. A successful command or image read alone does not establish a usable preview; guessed text geometry does not establish overflow.\n\n## Failed or blank previews\n\nFor populated content, a fully transparent or uniformly blank image is a renderer failure. If a pixel check is needed, composite RGBA onto white first; raw RGB under transparent pixels can look nonblank. Check once and do not reread the same image. Stop visual checks for the task immediately after a blank result. This overrides the rerender-after-edit guidance above: do not render or read images again, even after editing or copying the source, or try another range, page, sheet, DPI, output format, diagnostic export, or print setting. Preserve the usable source and requested outputs and finish applicable content/data checks.\n\nIf content and structure checks pass, name the saved file and verified edits as needed, then include exactly one visual-status sentence: \"Content and structure checks passed; visual inspection was not completed.\" in English, or \"内容与结构检查通过;视觉检查未完成。\" in Chinese. Do not add a render or preview bullet, explain why inspection stopped, or describe the image or pixels. Report content or structure failures separately; never say all checks passed or claim visual verification.\n\nLibreOffice output can differ from Word, PowerPoint, or Excel. Images do not certify animation/media playback, refresh formula caches in the source workbook, or guarantee native application fidelity. Deliver requested files through `present` when available; keep the files in place. Do not deliver inspection images or reports unless requested.\n</skill_instructions>\n</skill_content>"}],"source":{"kind":"skill-invocation","name":"offLine truncated
|
||||
{"type":"user/message","data":{"content":[{"type":"text","text":"<skill_content name=\"office-render\">\n<skill_resources>\nBase directory for this skill: {{cwd}}/office-skills/office-render\nResolve relative paths mentioned by this skill against the base directory before using them. Load referenced resources only as needed.\n</skill_resources>\n\n<skill_instructions>\n# Document images and visual inspection\n\nUse the installed LibreOffice Kit CLI through the shell with the absolute Node and CLI paths supplied below. In Bash, invoke `\"<node>\" \"<cli>\"`; in PowerShell, invoke `& \"<node>\" \"<cli>\"`. Prefer bundled LibreOffice unless the user requests another installation. If the Office sidecar is missing, follow [sidecar setup](../office/references/sidecar.md): ask whether the user wants to download it and install only after they agree. Do not invoke system soffice, use npx, install a replacement renderer, or build an alternative rendering pipeline to work around a failed render with an installed sidecar.\n\nBefore generating images only for inspection, establish that the current model accepts images. Otherwise finish the applicable content and structure checks and report the requested visual check as unavailable. Do not generate unreadable previews, retry image reads, or choose a second model. Requested image exports can still be delivered.\n\n## Render the saved deliverable\n\nKeep the saved deliverable in the task workspace. For requested image exports, use the requested output directory and retain the images. For inspection-only previews, create a private, uniquely named temporary parent inside that workspace and pass a child path that does not yet exist as `--output-dir`; the CLI creates that child. On POSIX, use `preview_root=$(mktemp -d \"./.dsh-office.XXXXXXXX\")` (owner-only permissions) and `--output-dir \"$preview_root/render\"`. On PowerShell, create a parent named `.dsh-office-` plus `[guid]::NewGuid().ToString('N')` under the task workspace and pass an uncreated `render` child; it inherits the workspace ACL. Quote each input and output path. Retain the parent until image inspection finishes, then remove only that parent, including after a failed render. Never use a fixed directory name or remove the workspace itself.\n\n```text\n\"<node>\" \"<cli>\" render --input <final-file> --output-dir <new-directory> --pages \"1,3,4\"\n\"<node>\" \"<cli>\" render --input <final-workbook.xlsx> --output-dir <new-directory> --sheet <exact-name> --range <A1-range>\n```\n\nFor DOCX, PPTX, or PDF, batch requested pages/slides in one call. In PowerShell, quote comma-separated `--pages` values so they remain one argument. Inspect all pages only for a requested whole-document review. For worksheets, choose the exact affected range, including chart/drawing regions; worksheet numbers are not PDF page numbers. Inspect the final saved file, reuse existing images for an unchanged source, and rerender only after requested source changes or for previously unrendered regions. Change print areas or scaling only when the user requests print layout.\n\nRead the returned JSON manifest for image paths, page counts, fragment rectangles, and missing-font diagnostics. Use the session's image-reading tool to inspect the requested images. Check clipping, alignment, headings, table widths, contrast, chart labels, and number formats as relevant to the task. A successful command or image read alone does not establish a usable preview; guessed text geometry does not establish overflow.\n\n## Failed or blank previews\n\nFor populated content, a fully transparent or uniformly blank image is a renderer failure. If a pixel check is needed, composite RGBA onto white first; raw RGB under transparent pixels can look nonblank. Check once and do not reread the same image. Stop visual checks for the task immediately after a blank result. This overrides the rerender-after-edit guidance above: do not render or read images again, even after editing or copying the source, or try another range, page, sheet, DPI, output format, diagnostic export, or print setting. Preserve the usable source and requested outputs and finish applicable content/data checks.\n\nIf content and structure checks pass, name the saved file and verified edits as needed, then include exactly one visual-status sentence: \"Content and structure checks passed; visual inspection was not completed.\" in English, or \"内容与结构检查通过;视觉检查未完成。\" in Chinese. Do not add a render or preview bullet, explain why inspection stopped, or describe the image or pixels. Report content or structure failures separately; never say all checks passed or claim visual verification.\n\nLibreOffice output can differ from Word, PowerPoint, or Excel. Images do not certify animation/media playback, refresh formula caches in the source workbook, or guarantee native application fidelity. Deliver requested files through `present` when available; keep the files in place. Do noLine truncated
|
||||
{"type":"assistant/message","data":{"turn":1,"step":4,"message":{"role":"assistant","content":[{"type":"tool-call","id":"call_office_4","name":"run_code","arguments":"{\"code\":\"console.log(await tools.skill({\\\"name\\\":\\\"office-export-pdf\\\"}));\",\"description\":\"Load task instructions\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{message:14}}"},"stream":[{"type":"chunk","time":1791559899915,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}},{"type":"tool-call-chunks","time0":1791559899915,"index":0,"dt":[],"id":"call_office_4","name":"run_code","args":["{\"code\":\"console.log(await tools.skill({\\\"name\\\":\\\"office-export-pdf\\\"}));\",\"description\":\"Load task instructions\"}"]},{"type":"chunk","time":1791559899915,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"call_office_4","name":"run_code","arguments":"{\"code\":\"console.log(await tools.skill({\\\"name\\\":\\\"office-export-pdf\\\"}));\",\"description\":\"Load task instructions\"}"}}},{"type":"chunk","time":1791559899915,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}]},"surfaceOp":"append"}
|
||||
{"type":"tool/call","data":{"turn":1,"step":4,"callId":"call_office_4","name":"run_code","arguments":"{\"code\":\"console.log(await tools.skill({\\\"name\\\":\\\"office-export-pdf\\\"}));\",\"description\":\"Load task instructions\"}"}}
|
||||
{"type":"tool/ptc-dispatch-start","data":{"rootCallId":"call_office_4","parentCallId":"call_office_4","subCallId":"call_office_4:ptc:1","name":"skill","arguments":{"name":"office-export-pdf"}}}
|
||||
{"type":"tool/ptc-dispatch","data":{"rootCallId":"call_office_4","parentCallId":"call_office_4","subCallId":"call_office_4:ptc:1","name":"skill","arguments":{"name":"office-export-pdf"},"isError":false,"content":[{"type":"text","text":"<skill_content name=\"office-export-pdf\">\n<skill_resources>\nBase directory for this skill: {{cwd}}/office-skills/office-export-pdf\nResolve relative paths mentioned by this skill against the base directory before using them. Load referenced resources only as needed.\n</skill_resources>\n\n<skill_instructions>\n# Export an Office document to PDF\n\nUse the installed LibreOffice Kit CLI through the shell with `dsoffice`. Prefer bundled LibreOffice unless the user requests another installation. If the Office sidecar is missing, follow [sidecar setup](../office/references/sidecar.md): ask whether the user wants to download it and install only after they agree. Do not invoke system soffice, use npx, or install a replacement to work around a failed conversion with an installed sidecar.\n\nConvert the final saved Office file to a new PDF in the task workspace. Preserve the source. Quote each input and output path.\n\n```text\ndsoffice convert --input <final-office-file> --output <new-file.pdf>\n```\n\nCheck the command result, nonempty output, and `%PDF-` file signature. If a PDF reader library is already available, compare page count and extractable text with the requested content. If it is unavailable, report the extent of validation; do not generate images or install extra tools to validate a conversion. Spreadsheet PDF pages follow workbook print settings; change those settings only when requested. Conversion may differ from the native application's pagination or fonts.\n\nIf export fails, preserve the usable source and report the export limitation. Do not repeatedly convert an unchanged source or use conversion to investigate a failed preview. For PDF export alone, stop after these checks. Only a request for images or visual inspection calls for `office-render`; load it before that separate operation. Deliver the requested PDF through `present` when available, keeping the file in place.\n</skill_instructions>\n</skill_content>"}]}}
|
||||
{"type":"tool/result","data":{"turn":1,"step":4,"message":{"role":"tool","source":{"kind":"tool","callId":"call_office_4"},"toolCallId":"call_office_4","content":[{"type":"text","text":"{\n name: 'office-export-pdf',\n provider: 'dsh-office',\n resourceBase: {\n kind: 'directory',\n path: '{{cwd}}/office-skills/office-export-pdf'\n },\n content: '# Export an Office document to PDF\\n' +\n '\\n' +\n 'Use the installed LibreOffice Kit CLI through the shell with `dsoffice`. Prefer bundled LibreOffice unless the user requests another installation. If the Office sidecar is missing, follow [sidecar setup](../office/references/sidecar.md): ask whether the user wants to download it and install only after they agree. Do not invoke system soffice, use npx, or install a replacement to work around a failed conversion with an installed sidecar.\\n' +\n '\\n' +\n 'Convert the final saved Office file to a new PDF in the task workspace. Preserve the source. Quote each input and output path.\\n' +\n '\\n' +\n '```text\\n' +\n 'dsoffice convert --input <final-office-file> --output <new-file.pdf>\\n' +\n '```\\n' +\n '\\n' +\n \"Check the command result, nonempty output, and `%PDF-` file signature. If a PDF reader library is already available, compare page count and extractable text with the requested content. If it is unavailable, report the extent of validation; do not generate images or install extra tools to validate a conversion. Spreadsheet PDF pages follow workbook print settings; change those settings only when requested. Conversion may differ from the native application's pagination or fonts.\\n\" +\n '\\n' +\n 'If export fails, preserve the usable source and report the export limitation. Do not repeatedly convert an unchanged source or use conversion to investigate a failed preview. For PDF export alone, stop after these checks. Only a request for images or visual inspection calls for `office-render`; load it before that separate operation. Deliver the requested PDF through `present` when available, keeping the file in place.'\n}"}],"isError":false,"id":"{{message:15}}"}},"sourceEventSeqs":[45],"surfaceOp":"append"}
|
||||
{"type":"agent/inbox/spliced","data":{"target":"next-step","start":0,"inserted":[{"content":[{"type":"text","text":"<skill_content name=\"office-export-pdf\">\n<skill_resources>\nBase directory for this skill: {{cwd}}/office-skills/office-export-pdf\nResolve relative paths mentioned by this skill against the base directory before using them. Load referenced resources only as needed.\n</skill_resources>\n\n<skill_instructions>\n# Export an Office document to PDF\n\nUse the installed LibreOffice Kit CLI through the shell with `dsoffice`. Prefer bundled LibreOffice unless the user requests another installation. If the Office sidecar is missing, follow [sidecar setup](../office/references/sidecar.md): ask whether the user wants to download it and install only after they agree. Do not invoke system soffice, use npx, or install a replacement to work around a failed conversion with an installed sidecar.\n\nConvert the final saved Office file to a new PDF in the task workspace. Preserve the source. Quote each input and output path.\n\n```text\ndsoffice convert --input <final-office-file> --output <new-file.pdf>\n```\n\nCheck the command result, nonempty output, and `%PDF-` file signature. If a PDF reader library is already available, compare page count and extractable text with the requested content. If it is unavailable, report the extent of validation; do not generate images or install extra tools to validate a conversion. Spreadsheet PDF pages follow workbook print settings; change those settings only when requested. Conversion may differ from the native application's pagination or fonts.\n\nIf export fails, preserve the usable source and report the export limitation. Do not repeatedly convert an unchanged source or use conversion to investigate a failed preview. For PDF export alone, stop after these checks. Only a request for images or visual inspection calls for `office-render`; load it before that separate operation. Deliver the requested PDF through `present` when available, keeping the file in place.\n</skill_instructions>\n</skill_content>"}],"source":{"kind":"skill-invocation","name":"office-export-pdf","form":"instructions"},"role":"user","id":"{{message:16}}"}]}}
|
||||
{"type":"tool/ptc-dispatch","data":{"rootCallId":"call_office_4","parentCallId":"call_office_4","subCallId":"call_office_4:ptc:1","name":"skill","arguments":{"name":"office-export-pdf"},"isError":false,"content":[{"type":"text","text":"<skill_content name=\"office-export-pdf\">\n<skill_resources>\nBase directory for this skill: {{cwd}}/office-skills/office-export-pdf\nResolve relative paths mentioned by this skill against the base directory before using them. Load referenced resources only as needed.\n</skill_resources>\n\n<skill_instructions>\n# Export an Office document to PDF\n\nUse the installed LibreOffice Kit CLI through the shell with the absolute Node and CLI paths supplied below. In Bash, invoke `\"<node>\" \"<cli>\"`; in PowerShell, invoke `& \"<node>\" \"<cli>\"`. Prefer bundled LibreOffice unless the user requests another installation. If the Office sidecar is missing, follow [sidecar setup](../office/references/sidecar.md): ask whether the user wants to download it and install only after they agree. Do not invoke system soffice, use npx, or install a replacement to work around a failed conversion with an installed sidecar.\n\nConvert the final saved Office file to a new PDF in the task workspace. Preserve the source. Quote each input and output path.\n\n```text\n\"<node>\" \"<cli>\" convert --input <final-office-file> --output <new-file.pdf>\n```\n\nCheck the command result, nonempty output, and `%PDF-` file signature. If a PDF reader library is already available, compare page count and extractable text with the requested content. If it is unavailable, report the extent of validation; do not generate images or install extra tools to validate a conversion. Spreadsheet PDF pages follow workbook print settings; change those settings only when requested. Conversion may differ from the native application's pagination or fonts.\n\nIf export fails, preserve the usable source and report the export limitation. Do not repeatedly convert an unchanged source or use conversion to investigate a failed preview. For PDF export alone, stop after these checks. Only a request for images or visual inspection calls for `office-render`; load it before that separate operation. Deliver the requested PDF through `present` when available, keeping the file in place.\n\n## Installed LibreOffice Kit\n\nUse these absolute paths for every LibreOffice Kit command. Pass the CLI entry as the first argument to Node.\n\n{\n \"libreofficeKit\": {\n \"node\": \"{{cwd}}/office-node\",\n \"cli\": \"{{cwd}}/render-cli.cjs\"\n }\n}\n</skill_instructions>\n</skill_content>"}]}}
|
||||
{"type":"tool/result","data":{"turn":1,"step":4,"message":{"role":"tool","source":{"kind":"tool","callId":"call_office_4"},"toolCallId":"call_office_4","content":[{"type":"text","text":"{\n name: 'office-export-pdf',\n provider: 'dsh-office',\n resourceBase: {\n kind: 'directory',\n path: '{{cwd}}/office-skills/office-export-pdf'\n },\n content: '# Export an Office document to PDF\\n' +\n '\\n' +\n 'Use the installed LibreOffice Kit CLI through the shell with the absolute Node and CLI paths supplied below. In Bash, invoke `\"<node>\" \"<cli>\"`; in PowerShell, invoke `& \"<node>\" \"<cli>\"`. Prefer bundled LibreOffice unless the user requests another installation. If the Office sidecar is missing, follow [sidecar setup](../office/references/sidecar.md): ask whether the user wants to download it and install only after they agree. Do not invoke system soffice, use npx, or install a replacement to work around a failed conversion with an installed sidecar.\\n' +\n '\\n' +\n 'Convert the final saved Office file to a new PDF in the task workspace. Preserve the source. Quote each input and output path.\\n' +\n '\\n' +\n '```text\\n' +\n '\"<node>\" \"<cli>\" convert --input <final-office-file> --output <new-file.pdf>\\n' +\n '```\\n' +\n '\\n' +\n \"Check the command result, nonempty output, and `%PDF-` file signature. If a PDF reader library is already available, compare page count and extractable text with the requested content. If it is unavailable, report the extent of validation; do not generate images or install extra tools to validate a conversion. Spreadsheet PDF pages follow workbook print settings; change those settings only when requested. Conversion may differ from the native application's pagination or fonts.\\n\" +\n '\\n' +\n 'If export fails, preserve the usable source and report the export limitation. Do not repeatedly convert an unchanged source or use conversion to investigate a failed preview. For PDF export alone, stop after these checks. Only a request for images or visual inspection calls for `office-render`; load it before that separate operation. Deliver the requested PDF through `present` when available, keeping the file in place.\\n' +\n '\\n' +\n '## Installed LibreOffice Kit\\n' +\n '\\n' +\n 'Use these absolute paths for every LibreOffice Kit command. Pass the CLI entry as the first argument to Node.\\n' +\n '\\n' +\n '{\\n' +\n ' \"libreofficeKit\": {\\n' +\n ' \"node\": \"{{cwd}}/office-node\",\\n' +\n ' \"cli\": \"{{cwd}}/render-cli.cjs\"\\n' +\n ' }\\n' +\n '}'\n}"}],"isError":false,"id":"{{message:15}}"}},"sourceEventSeqs":[45],"surfaceOp":"append"}
|
||||
{"type":"agent/inbox/spliced","data":{"target":"next-step","start":0,"inserted":[{"content":[{"type":"text","text":"<skill_content name=\"office-export-pdf\">\n<skill_resources>\nBase directory for this skill: {{cwd}}/office-skills/office-export-pdf\nResolve relative paths mentioned by this skill against the base directory before using them. Load referenced resources only as needed.\n</skill_resources>\n\n<skill_instructions>\n# Export an Office document to PDF\n\nUse the installed LibreOffice Kit CLI through the shell with the absolute Node and CLI paths supplied below. In Bash, invoke `\"<node>\" \"<cli>\"`; in PowerShell, invoke `& \"<node>\" \"<cli>\"`. Prefer bundled LibreOffice unless the user requests another installation. If the Office sidecar is missing, follow [sidecar setup](../office/references/sidecar.md): ask whether the user wants to download it and install only after they agree. Do not invoke system soffice, use npx, or install a replacement to work around a failed conversion with an installed sidecar.\n\nConvert the final saved Office file to a new PDF in the task workspace. Preserve the source. Quote each input and output path.\n\n```text\n\"<node>\" \"<cli>\" convert --input <final-office-file> --output <new-file.pdf>\n```\n\nCheck the command result, nonempty output, and `%PDF-` file signature. If a PDF reader library is already available, compare page count and extractable text with the requested content. If it is unavailable, report the extent of validation; do not generate images or install extra tools to validate a conversion. Spreadsheet PDF pages follow workbook print settings; change those settings only when requested. Conversion may differ from the native application's pagination or fonts.\n\nIf export fails, preserve the usable source and report the export limitation. Do not repeatedly convert an unchanged source or use conversion to investigate a failed preview. For PDF export alone, stop after these checks. Only a request for images or visual inspection calls for `office-render`; load it before that separate operation. Deliver the requested PDF through `present` when available, keeping the file in place.\n\n## Installed LibreOffice Kit\n\nUse these absolute paths for every LibreOffice Kit command. Pass the CLI entry as the first argument to Node.\n\n{\n \"libreofficeKit\": {\n \"node\": \"{{cwd}}/office-node\",\n \"cli\": \"{{cwd}}/render-cli.cjs\"\n }\n}\n</skill_instructions>\n</skill_content>"}],"source":{"kind":"skill-invocation","name":"office-export-pdf","form":"instructions"},"role":"user","id":"{{message:16}}"}]}}
|
||||
{"type":"step/end","data":{"turn":1,"step":4}}
|
||||
{"type":"agent/inbox/spliced","data":{"target":"next-step","start":0,"removedCount":1,"inserted":[]}}
|
||||
{"type":"step/start","data":{"turn":1,"step":5}}
|
||||
{"type":"user/message","data":{"content":[{"type":"text","text":"<skill_content name=\"office-export-pdf\">\n<skill_resources>\nBase directory for this skill: {{cwd}}/office-skills/office-export-pdf\nResolve relative paths mentioned by this skill against the base directory before using them. Load referenced resources only as needed.\n</skill_resources>\n\n<skill_instructions>\n# Export an Office document to PDF\n\nUse the installed LibreOffice Kit CLI through the shell with `dsoffice`. Prefer bundled LibreOffice unless the user requests another installation. If the Office sidecar is missing, follow [sidecar setup](../office/references/sidecar.md): ask whether the user wants to download it and install only after they agree. Do not invoke system soffice, use npx, or install a replacement to work around a failed conversion with an installed sidecar.\n\nConvert the final saved Office file to a new PDF in the task workspace. Preserve the source. Quote each input and output path.\n\n```text\ndsoffice convert --input <final-office-file> --output <new-file.pdf>\n```\n\nCheck the command result, nonempty output, and `%PDF-` file signature. If a PDF reader library is already available, compare page count and extractable text with the requested content. If it is unavailable, report the extent of validation; do not generate images or install extra tools to validate a conversion. Spreadsheet PDF pages follow workbook print settings; change those settings only when requested. Conversion may differ from the native application's pagination or fonts.\n\nIf export fails, preserve the usable source and report the export limitation. Do not repeatedly convert an unchanged source or use conversion to investigate a failed preview. For PDF export alone, stop after these checks. Only a request for images or visual inspection calls for `office-render`; load it before that separate operation. Deliver the requested PDF through `present` when available, keeping the file in place.\n</skill_instructions>\n</skill_content>"}],"source":{"kind":"skill-invocation","name":"office-export-pdf","form":"instructions"},"role":"user","id":"{{message:16}}"},"surfaceOp":"append"}
|
||||
{"type":"user/message","data":{"content":[{"type":"text","text":"<skill_content name=\"office-export-pdf\">\n<skill_resources>\nBase directory for this skill: {{cwd}}/office-skills/office-export-pdf\nResolve relative paths mentioned by this skill against the base directory before using them. Load referenced resources only as needed.\n</skill_resources>\n\n<skill_instructions>\n# Export an Office document to PDF\n\nUse the installed LibreOffice Kit CLI through the shell with the absolute Node and CLI paths supplied below. In Bash, invoke `\"<node>\" \"<cli>\"`; in PowerShell, invoke `& \"<node>\" \"<cli>\"`. Prefer bundled LibreOffice unless the user requests another installation. If the Office sidecar is missing, follow [sidecar setup](../office/references/sidecar.md): ask whether the user wants to download it and install only after they agree. Do not invoke system soffice, use npx, or install a replacement to work around a failed conversion with an installed sidecar.\n\nConvert the final saved Office file to a new PDF in the task workspace. Preserve the source. Quote each input and output path.\n\n```text\n\"<node>\" \"<cli>\" convert --input <final-office-file> --output <new-file.pdf>\n```\n\nCheck the command result, nonempty output, and `%PDF-` file signature. If a PDF reader library is already available, compare page count and extractable text with the requested content. If it is unavailable, report the extent of validation; do not generate images or install extra tools to validate a conversion. Spreadsheet PDF pages follow workbook print settings; change those settings only when requested. Conversion may differ from the native application's pagination or fonts.\n\nIf export fails, preserve the usable source and report the export limitation. Do not repeatedly convert an unchanged source or use conversion to investigate a failed preview. For PDF export alone, stop after these checks. Only a request for images or visual inspection calls for `office-render`; load it before that separate operation. Deliver the requested PDF through `present` when available, keeping the file in place.\n\n## Installed LibreOffice Kit\n\nUse these absolute paths for every LibreOffice Kit command. Pass the CLI entry as the first argument to Node.\n\n{\n \"libreofficeKit\": {\n \"node\": \"{{cwd}}/office-node\",\n \"cli\": \"{{cwd}}/render-cli.cjs\"\n }\n}\n</skill_instructions>\n</skill_content>"}],"source":{"kind":"skill-invocation","name":"office-export-pdf","form":"instructions"},"role":"user","id":"{{message:16}}"},"surfaceOp":"append"}
|
||||
{"type":"assistant/message","data":{"turn":1,"step":5,"message":{"role":"assistant","content":[{"type":"text","text":"DONE"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{message:17}}"},"usage":{"inputTokens":12,"outputTokens":2,"cacheReadTokens":10},"stream":[{"type":"chunk","time":1791559900023,"chunk":{"type":"block-start","index":0,"blockType":"text"}},{"type":"text-chunks","time0":1791559900023,"index":0,"dt":[],"texts":["DONE"]},{"type":"chunk","time":1791559900023,"chunk":{"type":"block-end","index":0,"block":{"type":"text","text":"DONE"}}},{"type":"chunk","time":1791559900023,"chunk":{"type":"usage","usage":{"inputTokens":12,"outputTokens":2,"cacheReadTokens":10}}},{"type":"chunk","time":1791559900023,"chunk":{"type":"finish","reason":{"kind":"stop"}}}]},"surfaceOp":"append"}
|
||||
{"type":"step/end","data":{"turn":1,"step":5}}
|
||||
{"type":"turn/end","data":{"turn":1,"reason":{"kind":"completed"}}}
|
||||
@@ -52,6 +52,8 @@
|
||||
disabled: false
|
||||
config:
|
||||
assetRoot: !!js process.cwd() + '/office-skills'
|
||||
node: !!js process.cwd() + '/office-node'
|
||||
cli: !!js process.cwd() + '/render-cli.cjs'
|
||||
|
||||
- id: tool-bash
|
||||
disabled: true
|
||||
@@ -68,10 +70,3 @@
|
||||
launch:
|
||||
kind: node-script
|
||||
executable: !!js process.cwd() + '/office-ptc-node'
|
||||
|
||||
- insert:
|
||||
- id: office-commands
|
||||
name: '@deepseek-ai/dsh-skill-office/commands'
|
||||
disabled: false
|
||||
config:
|
||||
command: !!js "[process.cwd() + '/office-node', process.cwd() + '/render-cli.cjs']"
|
||||
@@ -3,6 +3,8 @@
|
||||
name: '@deepseek-ai/dsh-skill-office'
|
||||
config:
|
||||
assetRoot: !!js process.cwd() + '/office-skills'
|
||||
node: !!js process.cwd() + '/office-node'
|
||||
cli: !!js process.cwd() + '/render-cli.cjs'
|
||||
|
||||
- id: tool-bash
|
||||
disabled: true
|
||||
@@ -13,9 +15,3 @@
|
||||
- id: tools
|
||||
config:
|
||||
mode: ptc
|
||||
|
||||
- insert:
|
||||
- id: office-commands
|
||||
name: '@deepseek-ai/dsh-skill-office/commands'
|
||||
config:
|
||||
command: !!js "[process.cwd() + '/office-node', process.cwd() + '/render-cli.cjs']"
|
||||
@@ -10,20 +10,20 @@
|
||||
{"type":"user/message","data":{"content":[{"type":"text","text":"/office-docx Load the Office rendering tool, render page 1 of report.docx to preview, remove the rendering tool, then reply DONE."}],"source":{"kind":"user"},"role":"user","id":"{{message:1}}"},"surfaceOp":"append"}
|
||||
{"type":"user/message","data":{"content":[{"type":"text","text":"Current runtime context. This snapshot supersedes earlier runtime-context snapshots.\n\nCurrent working directory: \"{{cwd}}\".\n\nCurrent DSH file policy: danger-full-access. The DSH file sandbox does not restrict file modifications by available operations.\n\nApproval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`)."}],"source":{"kind":"runtime-context","form":"snapshot","sections":[{"name":"working-directory:current","text":"Current working directory: \"{{cwd}}\"."},{"name":"sandbox:policy","text":"Current DSH file policy: danger-full-access. The DSH file sandbox does not restrict file modifications by available operations."},{"name":"approval:policy","text":"Approval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`)."}]},"role":"user","id":"{{message:3}}"},"surfaceOp":"append"}
|
||||
{"type":"user/message","data":{"content":[{"type":"text","text":"<system-reminder>\nA skill is a reusable set of task-specific instructions. The following skills are available in this session:\n\n<available_skills>\n- `office`: Create, edit, inspect, or convert Office documents, spreadsheets, presentations, and PDFs. Load to choose the relevant workflow.\n- `office-docx`: Create, read, edit, and validate Word documents (.docx).\n- `office-export-pdf`: Convert an Office document to a requested PDF with LibreOffice Kit.\n- `office-pptx`: Create, read, edit, and validate PowerPoint presentations (.pptx).\n- `office-recalculate`: Refresh spreadsheet formula caches and verify calculated values with LibreOffice Kit.\n- `office-render`: Render requested document images or inspect visual layout with LibreOffice Kit.\n- `office-xlsx`: Read, create, edit, and validate Excel workbooks, data, and formulas (.xlsx).\n</available_skills>\n\nIf the user names a skill, or the task clearly matches a skill's description, call the `skill` tool with the exact skill name before taking task actions. Load all applicable skills, then follow their full instructions. This catalog contains summaries only; do not infer or follow a skill's instructions until it has been loaded.\nA user may also invoke a skill directly; its <skill_content> block then appears in this conversation. Follow it, and do not call the `skill` tool again for that skill.\n</system-reminder>"}],"source":{"kind":"skill-catalog","form":"catalog","entries":[{"name":"office","description":"Create, edit, inspect, or convert Office documents, spreadsheets, presentations, and PDFs. Load to choose the relevant workflow."},{"name":"office-docx","description":"Create, read, edit, and validate Word documents (.docx)."},{"name":"office-export-pdf","description":"Convert an Office document to a requested PDF with LibreOffice Kit."},{"name":"office-pptx","description":"Create, read, edit, and validate PowerPoint presentations (.pptx)."},{"name":"office-recalculate","description":"Refresh spreadsheet formula caches and verify calculated values with LibreOffice Kit."},{"name":"office-render","description":"Render requested document images or inspect visual layout with LibreOffice Kit."},{"name":"office-xlsx","description":"Read, create, edit, and validate Excel workbooks, data, and formulas (.xlsx)."}]},"role":"user","id":"{{message:4}}"},"surfaceOp":"append"}
|
||||
{"type":"user/message","data":{"content":[{"type":"text","text":"<skill_content name=\"office-docx\">\n<skill_resources>\nBase directory for this skill: {{cwd}}/office-skills/office-docx\nResolve relative paths mentioned by this skill against the base directory before using them. Load referenced resources only as needed.\n</skill_resources>\n\n<skill_instructions>\n# Word documents\n\nUse `python-docx` for DOCX creation and ordinary edits. Follow an explicit user or applicable AGENTS.md requirement for a project environment or another library. Otherwise call `load_workspace_dependencies` and execute the returned Python path with its bundled libraries. Do not install packages or discover a system Python for the default workflow. If the tool is unavailable, use an already configured environment and report a missing dependency only when it prevents the requested operation.\n\nKeep source scripts, intermediate files, and final documents in the task workspace; the runtime and this skill directory are read-only resources. Use the user's requested language and preserve an existing document's design unless a redesign is requested.\n\n## Create and edit\n\nFor existing files, inspect paragraphs, runs, tables, sections, headers, and footers before changing the affected content. Save to a new file unless the user requests an in-place edit. Replacing a paragraph's `.text` destroys its run formatting; change the relevant runs when formatting must survive. Reconstructing the whole document can lose features outside python-docx's supported editing API.\n\nUse paragraph styles for headings and body text. Size tables for the section that contains them, and account for merged cells and nested tables. Chinese, Japanese, and Korean text may need an explicit `w:eastAsia` font assignment in addition to `run.font.name`; font names alone do not establish glyph availability or rendered appearance.\n\nFor a new document, use the selected Python executable:\n\n```python\nfrom docx import Document\n\ndocument = Document()\ndocument.add_heading(\"Project report\", level=0)\ndocument.add_paragraph(\"Summary\", style=\"Heading 1\")\ndocument.add_paragraph(\"The requested findings go here.\")\ndocument.save(\"report.docx\")\n```\n\npython-docx does not paginate or render documents. Do not represent ordinary replacement, colored text, or comments as tracked changes. When real revisions or unsupported OOXML features matter, preserve their package parts and verify the requested operation rather than silently discarding them.\n\n## Check and deliver\n\nRun the shared structural checker when `office-check` is available:\n\n```text\noffice-check <document.docx> --out <checks.json>\n```\n\nIt checks ZIP/XML integrity and internal relationships, and reports paragraphs, logical table dimensions, and sections. Optional `--contains TEXT` arguments assert required text. A successful structural check does not verify pagination, clipping, fonts, or visual appearance. Compare the summary and reopened document with the user's request, including unchanged content that matters to an edit.\n\nIf `office-check` is unavailable, use an already configured environment to check the ZIP/XML package and internal relationships. Report the missing environment if those checks cannot run; do not claim structural validation.\n\nDeliver after the requested content and structural checks pass. Creating a file or changing content with incidental basic formatting does not require additional operations. Load `office-render` for requested images or visual inspection and for appearance-focused styling, spacing, sizing, or alignment changes unless the user explicitly skips rendering. For PDF output load `office-export-pdf`.\n\nCall `present({\"files\":[{\"path\":\"report.docx\"}]})` with the actual final DOCX path. It exposes the current source file without copying or preserving its bytes, so keep that file in place and do not present temporary QA reports unless requested. If `present` is unavailable, provide the final workspace path using the session's supported file delivery method.\n</skill_instructions>\n</skill_content>"}],"source":{"kind":"skill-invocation","name":"office-docx","form":"instructions"},"role":"user","id":"{{message:5}}"},"surfaceOp":"append"}
|
||||
{"type":"user/message","data":{"content":[{"type":"text","text":"<skill_content name=\"office-docx\">\n<skill_resources>\nBase directory for this skill: {{cwd}}/office-skills/office-docx\nResolve relative paths mentioned by this skill against the base directory before using them. Load referenced resources only as needed.\n</skill_resources>\n\n<skill_instructions>\n# Word documents\n\nUse `python-docx` for DOCX creation and ordinary edits. Follow an explicit user or applicable AGENTS.md requirement for a project environment or another library. Otherwise call `load_workspace_dependencies` and execute the returned Python path with its bundled libraries. Do not install packages or discover a system Python for the default workflow. If the tool is unavailable, use an already configured environment and report a missing dependency only when it prevents the requested operation.\n\nKeep source scripts, intermediate files, and final documents in the task workspace; the runtime and this skill directory are read-only resources. Use the user's requested language and preserve an existing document's design unless a redesign is requested.\n\n## Create and edit\n\nFor existing files, inspect paragraphs, runs, tables, sections, headers, and footers before changing the affected content. Save to a new file unless the user requests an in-place edit. Replacing a paragraph's `.text` destroys its run formatting; change the relevant runs when formatting must survive. Reconstructing the whole document can lose features outside python-docx's supported editing API.\n\nUse paragraph styles for headings and body text. Size tables for the section that contains them, and account for merged cells and nested tables. Chinese, Japanese, and Korean text may need an explicit `w:eastAsia` font assignment in addition to `run.font.name`; font names alone do not establish glyph availability or rendered appearance.\n\nFor a new document, use the selected Python executable:\n\n```python\nfrom docx import Document\n\ndocument = Document()\ndocument.add_heading(\"Project report\", level=0)\ndocument.add_paragraph(\"Summary\", style=\"Heading 1\")\ndocument.add_paragraph(\"The requested findings go here.\")\ndocument.save(\"report.docx\")\n```\n\npython-docx does not paginate or render documents. Do not represent ordinary replacement, colored text, or comments as tracked changes. When real revisions or unsupported OOXML features matter, preserve their package parts and verify the requested operation rather than silently discarding them.\n\n## Check and deliver\n\nRun the shared structural checker when `office-check` is available:\n\nIn PowerShell, prefix the quoted Python executable with `&`. Resolve the checker path relative to this skill directory.\n\n```text\n\"<python>\" \"<skill-directory>/../scripts/check_office.py\" <document.docx> --out <checks.json>\n```\n\nIt checks ZIP/XML integrity and internal relationships, and reports paragraphs, logical table dimensions, and sections. Optional `--contains TEXT` arguments assert required text. A successful structural check does not verify pagination, clipping, fonts, or visual appearance. Compare the summary and reopened document with the user's request, including unchanged content that matters to an edit.\n\nIf the Python checker cannot run, use an already configured environment to check the ZIP/XML package and internal relationships. Report the missing environment if those checks cannot run; do not claim structural validation.\n\nDeliver after the requested content and structural checks pass. Creating a file or changing content with incidental basic formatting does not require additional operations. Load `office-render` for requested images or visual inspection. When styling, font color, spacing, sizing, or text alignment is the requested edit, load `office-render` and inspect the changed page even without a separate visual-check request, unless the user explicitly skips rendering. For PDF output load `office-export-pdf`.\n\nCall `present({\"files\":[{\"path\":\"report.docx\"}]})` with the actual final DOCX path. It exposes the current source file without copying or preserving its bytes, so keep that file in place and do not present temporary QA reports unless requested. If `present` is unavailable, provide the final workspace path using the session's supported file delivery method.\n</skill_instructions>\n</skill_content>"}],"source":{"kind":"skill-invocation","name":"office-docx","form":"instructions"},"role":"user","id":"{{message:5}}"},"surfaceOp":"append"}
|
||||
{"type":"request/header","data":{"header":{"config":{"provider":"deepseek-official","model":"deepseek-v4-flash"},"tools":"{{tools}}"},"reason":"initial"}}
|
||||
{"type":"request/context","data":{"provider":"deepseek-official","model":"deepseek-v4-flash"}}
|
||||
{"type":"session/title","data":{"title":"/office-docx Load the Office rendering","messageSeqs":[8],"source":{"kind":"fallback"}}}
|
||||
{"type":"assistant/message","data":{"turn":1,"step":1,"message":{"role":"assistant","content":[{"type":"tool-call","id":"call_office_skill","name":"run_code","arguments":"{\"code\":\"console.log(await tools.skill({\\\"name\\\":\\\"office-xlsx\\\"}));\",\"description\":\"Use the Office workflow\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{message:6}}"},"stream":[{"type":"chunk","time":1791559901535,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}},{"type":"tool-call-chunks","time0":1791559901535,"index":0,"dt":[],"id":"call_office_skill","name":"run_code","args":["{\"code\":\"console.log(await tools.skill({\\\"name\\\":\\\"office-xlsx\\\"}));\",\"description\":\"Use the Office workflow\"}"]},{"type":"chunk","time":1791559901535,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"call_office_skill","name":"run_code","arguments":"{\"code\":\"console.log(await tools.skill({\\\"name\\\":\\\"office-xlsx\\\"}));\",\"description\":\"Use the Office workflow\"}"}}},{"type":"chunk","time":1791559901535,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}]},"surfaceOp":"append"}
|
||||
{"type":"tool/call","data":{"turn":1,"step":1,"callId":"call_office_skill","name":"run_code","arguments":"{\"code\":\"console.log(await tools.skill({\\\"name\\\":\\\"office-xlsx\\\"}));\",\"description\":\"Use the Office workflow\"}"}}
|
||||
{"type":"tool/ptc-dispatch-start","data":{"rootCallId":"call_office_skill","parentCallId":"call_office_skill","subCallId":"call_office_skill:ptc:1","name":"skill","arguments":{"name":"office-xlsx"}}}
|
||||
{"type":"tool/ptc-dispatch","data":{"rootCallId":"call_office_skill","parentCallId":"call_office_skill","subCallId":"call_office_skill:ptc:1","name":"skill","arguments":{"name":"office-xlsx"},"isError":false,"content":[{"type":"text","text":"<skill_content name=\"office-xlsx\">\n<skill_resources>\nBase directory for this skill: {{cwd}}/office-skills/office-xlsx\nResolve relative paths mentioned by this skill against the base directory before using them. Load referenced resources only as needed.\n</skill_resources>\n\n<skill_instructions>\n# Excel workbooks\n\nFollow an explicit user or applicable AGENTS.md requirement for an environment or library. Otherwise call `load_workspace_dependencies` and run its Python executable with bundled `openpyxl` and `pandas`. Do not install packages or search for a system Python for the default workflow. If the tool is unavailable, use an already configured environment and report a missing dependency only when it prevents the requested operation.\n\nKeep scripts, working files, and outputs in the task workspace. The runtime and skill directory are shared read-only resources. Save to a new workbook unless the user requests an in-place edit.\n\n## Read and modify\n\nUse `openpyxl` for existing XLSX workbooks and targeted cell or style changes. Load with `data_only=False` when formulas must survive. Inspect sheet names, the affected cell types, formulas, styles, merged ranges, and referenced ranges before editing. Check the saved file by reopening it, including unchanged content that the request requires preserving.\n\nUse pandas for data analysis and transformations. A DataFrame is not the workbook: exporting it over an existing file can lose sheets, formulas, charts, and formatting. Write analysis results back to the intended ranges with openpyxl. `XlsxWriter` can create new workbooks, but cannot read or modify existing ones.\n\nFor a new workbook, the selected Python environment can write editable values, styles, and formulas directly:\n\n```python\nfrom openpyxl import Workbook\nfrom openpyxl.styles import Font\n\nworkbook = Workbook()\nsheet = workbook.active\nsheet.title = \"Revenue\"\nfor row in [(\"Quarter\", \"Revenue\"), (\"Q1\", 12), (\"Q2\", 18), (\"Total\", \"=SUM(B2:B3)\")]:\n sheet.append(row)\nfor cell in sheet[1]:\n cell.font = Font(bold=True)\nsheet.column_dimensions[\"A\"].width = 18\nsheet.column_dimensions[\"B\"].width = 18\nworkbook.save(\"report.xlsx\")\n```\n\nPreserve numbers, dates, booleans, and identifiers as the intended cell types; formatting is not a type conversion. For modifications, load the existing file with `openpyxl.load_workbook(\"input.xlsx\", data_only=False)`, change the requested ranges, and save a separate result. Avoid a DataFrame round trip when workbook features must survive.\n\nWriting a formula does not calculate its result. openpyxl and XlsxWriter do not evaluate formulas; `data_only=True` returns cached values that may be absent or stale. When calculated results must be refreshed, load `office-recalculate`. Do not replace requested formulas with constants or report stale values as newly calculated results.\n\nDo not rename `.xls`, `.xlsb`, encrypted files, or macro-enabled files to `.xlsx`. They need an appropriate supported operation. `keep_vba=True` can preserve VBA package content in an XLSM workflow, but does not execute or edit macros and does not guarantee every advanced workbook feature survives. Preserve the original and verify such requirements explicitly.\n\n## Check and deliver\n\nRun the shared structural checker when `office-check` is available:\n\n```text\noffice-check <workbook.xlsx> --out <checks.json>\n```\n\nIt checks ZIP/XML integrity and internal relationships, and reports sheet names, populated-cell counts, and formula counts. Repeated `--contains TEXT` arguments check string cells and sheet names, and `--count N` checks sheet count. `--contains` excludes numeric cells and does not validate formula results; verify those separately with openpyxl. The checker does not calculate formulas or judge workbook appearance. Compare relevant values, types, formulas, styles, and totals with the task's source data.\n\nIf `office-check` is unavailable, use an already configured environment to check the ZIP/XML package and internal relationships. Report the missing environment if those checks cannot run; do not claim structural validation.\n\nLoad `office-render` for requested images or visual inspection and whenever the user's primary task targets appearance, including cell fill colors, text alignment, spacing, or sizing. These appearance changes require rendering even without a separate visual-check request, unless the user explicitly skips it. New workbooks and data or formula edits do not require rendering solely because they include incidental basic formatting. In particular, bold headers and number formats accompanying data edits do not require loading `office-render` or running its commands.\n\nLoad `officeLine truncated
|
||||
{"type":"tool/result","data":{"turn":1,"step":1,"message":{"role":"tool","source":{"kind":"tool","callId":"call_office_skill"},"toolCallId":"call_office_skill","content":[{"type":"text","text":"{\n name: 'office-xlsx',\n provider: 'dsh-office',\n resourceBase: {\n kind: 'directory',\n path: '{{cwd}}/office-skills/office-xlsx'\n },\n content: '# Excel workbooks\\n' +\n '\\n' +\n 'Follow an explicit user or applicable AGENTS.md requirement for an environment or library. Otherwise call `load_workspace_dependencies` and run its Python executable with bundled `openpyxl` and `pandas`. Do not install packages or search for a system Python for the default workflow. If the tool is unavailable, use an already configured environment and report a missing dependency only when it prevents the requested operation.\\n' +\n '\\n' +\n 'Keep scripts, working files, and outputs in the task workspace. The runtime and skill directory are shared read-only resources. Save to a new workbook unless the user requests an in-place edit.\\n' +\n '\\n' +\n '## Read and modify\\n' +\n '\\n' +\n 'Use `openpyxl` for existing XLSX workbooks and targeted cell or style changes. Load with `data_only=False` when formulas must survive. Inspect sheet names, the affected cell types, formulas, styles, merged ranges, and referenced ranges before editing. Check the saved file by reopening it, including unchanged content that the request requires preserving.\\n' +\n '\\n' +\n 'Use pandas for data analysis and transformations. A DataFrame is not the workbook: exporting it over an existing file can lose sheets, formulas, charts, and formatting. Write analysis results back to the intended ranges with openpyxl. `XlsxWriter` can create new workbooks, but cannot read or modify existing ones.\\n' +\n '\\n' +\n 'For a new workbook, the selected Python environment can write editable values, styles, and formulas directly:\\n' +\n '\\n' +\n '```python\\n' +\n 'from openpyxl import Workbook\\n' +\n 'from openpyxl.styles import Font\\n' +\n '\\n' +\n 'workbook = Workbook()\\n' +\n 'sheet = workbook.active\\n' +\n 'sheet.title = \"Revenue\"\\n' +\n 'for row in [(\"Quarter\", \"Revenue\"), (\"Q1\", 12), (\"Q2\", 18), (\"Total\", \"=SUM(B2:B3)\")]:\\n' +\n ' sheet.append(row)\\n' +\n 'for cell in sheet[1]:\\n' +\n ' cell.font = Font(bold=True)\\n' +\n 'sheet.column_dimensions[\"A\"].width = 18\\n' +\n 'sheet.column_dimensions[\"B\"].width = 18\\n' +\n 'workbook.save(\"report.xlsx\")\\n' +\n '```\\n' +\n '\\n' +\n 'Preserve numbers, dates, booleans, and identifiers as the intended cell types; formatting is not a type conversion. For modifications, load the existing file with `openpyxl.load_workbook(\"input.xlsx\", data_only=False)`, change the requested ranges, and save a separate result. Avoid a DataFrame round trip when workbook features must survive.\\n' +\n '\\n' +\n 'Writing a formula does not calculate its result. openpyxl and XlsxWriter do not evaluate formulas; `data_only=True` returns cached values that may be absent or stale. When calculated results must be refreshed, load `office-recalculate`. Do not replace requested formulas with constants or report stale values as newly calculated results.\\n' +\n '\\n' +\n 'Do not rename `.xls`, `.xlsb`, encrypted files, or macro-enabled files to `.xlsx`. They need an appropriate supported operation. `keep_vba=True` can preserve VBA package content in an XLSM workflow, but does not execute or edit macros and does not guarantee every advanced workbook feature survives. Preserve the original and verify such requirements explicitly.\\n' +\n '\\n' +\n '## Check and deliver\\n' +\n '\\n' +\n 'Run the shared structural checker when `office-check` is available:\\n' +\n '\\n' +\n '```text\\n' +\n 'office-check <workbook.xlsx> --out <checks.json>\\n' +\n '```\\n' +\n '\\n' +\n \"It checks ZIP/XML integrity and internal relationships, and reports sheet names, populated-cell counts, and formula counts. Repeated `--contains TEXT` arguments check string cells and sheet names, and `--count N` checks sheet count. `--contains` excludes numeric cells and does not validate formula results; verify those separately with openpyxl. The checker does not calculate formulas or judge workbook appearance. Compare relevant values, types, formulas, styles, and totals with the task's source data.\\n\" +\n '\\n' +\n 'If `office-check` is unavailable, use an already configured environment to check the ZIP/XML package and internal relationships. Report the missing environment if those checks cannot run; do not claim structural validation.\\n' +\n '\\n' +\n \"Load `office-render` for requested images or visual inspection and whenever the user's primary task targets appearance, including cell fill colors, text alignment, spacing, or sizing. These appearance changes require rendering even without Line truncated
|
||||
{"type":"agent/inbox/spliced","data":{"target":"next-step","start":0,"inserted":[{"content":[{"type":"text","text":"<skill_content name=\"office-xlsx\">\n<skill_resources>\nBase directory for this skill: {{cwd}}/office-skills/office-xlsx\nResolve relative paths mentioned by this skill against the base directory before using them. Load referenced resources only as needed.\n</skill_resources>\n\n<skill_instructions>\n# Excel workbooks\n\nFollow an explicit user or applicable AGENTS.md requirement for an environment or library. Otherwise call `load_workspace_dependencies` and run its Python executable with bundled `openpyxl` and `pandas`. Do not install packages or search for a system Python for the default workflow. If the tool is unavailable, use an already configured environment and report a missing dependency only when it prevents the requested operation.\n\nKeep scripts, working files, and outputs in the task workspace. The runtime and skill directory are shared read-only resources. Save to a new workbook unless the user requests an in-place edit.\n\n## Read and modify\n\nUse `openpyxl` for existing XLSX workbooks and targeted cell or style changes. Load with `data_only=False` when formulas must survive. Inspect sheet names, the affected cell types, formulas, styles, merged ranges, and referenced ranges before editing. Check the saved file by reopening it, including unchanged content that the request requires preserving.\n\nUse pandas for data analysis and transformations. A DataFrame is not the workbook: exporting it over an existing file can lose sheets, formulas, charts, and formatting. Write analysis results back to the intended ranges with openpyxl. `XlsxWriter` can create new workbooks, but cannot read or modify existing ones.\n\nFor a new workbook, the selected Python environment can write editable values, styles, and formulas directly:\n\n```python\nfrom openpyxl import Workbook\nfrom openpyxl.styles import Font\n\nworkbook = Workbook()\nsheet = workbook.active\nsheet.title = \"Revenue\"\nfor row in [(\"Quarter\", \"Revenue\"), (\"Q1\", 12), (\"Q2\", 18), (\"Total\", \"=SUM(B2:B3)\")]:\n sheet.append(row)\nfor cell in sheet[1]:\n cell.font = Font(bold=True)\nsheet.column_dimensions[\"A\"].width = 18\nsheet.column_dimensions[\"B\"].width = 18\nworkbook.save(\"report.xlsx\")\n```\n\nPreserve numbers, dates, booleans, and identifiers as the intended cell types; formatting is not a type conversion. For modifications, load the existing file with `openpyxl.load_workbook(\"input.xlsx\", data_only=False)`, change the requested ranges, and save a separate result. Avoid a DataFrame round trip when workbook features must survive.\n\nWriting a formula does not calculate its result. openpyxl and XlsxWriter do not evaluate formulas; `data_only=True` returns cached values that may be absent or stale. When calculated results must be refreshed, load `office-recalculate`. Do not replace requested formulas with constants or report stale values as newly calculated results.\n\nDo not rename `.xls`, `.xlsb`, encrypted files, or macro-enabled files to `.xlsx`. They need an appropriate supported operation. `keep_vba=True` can preserve VBA package content in an XLSM workflow, but does not execute or edit macros and does not guarantee every advanced workbook feature survives. Preserve the original and verify such requirements explicitly.\n\n## Check and deliver\n\nRun the shared structural checker when `office-check` is available:\n\n```text\noffice-check <workbook.xlsx> --out <checks.json>\n```\n\nIt checks ZIP/XML integrity and internal relationships, and reports sheet names, populated-cell counts, and formula counts. Repeated `--contains TEXT` arguments check string cells and sheet names, and `--count N` checks sheet count. `--contains` excludes numeric cells and does not validate formula results; verify those separately with openpyxl. The checker does not calculate formulas or judge workbook appearance. Compare relevant values, types, formulas, styles, and totals with the task's source data.\n\nIf `office-check` is unavailable, use an already configured environment to check the ZIP/XML package and internal relationships. Report the missing environment if those checks cannot run; do not claim structural validation.\n\nLoad `office-render` for requested images or visual inspection and whenever the user's primary task targets appearance, including cell fill colors, text alignment, spacing, or sizing. These appearance changes require rendering even without a separate visual-check request, unless the user explicitly skips it. New workbooks and data or formula edits do not require rendering solely because they include incidental basic formatting. In particular, bold headers and number formats accompanying data edits do not require loading `office-render` or running its commands.\n\nLoad `office-recalculate` when refreshed calculated values are needed and `office-export-pdf` for PDF output. Deliver after structural andLine truncated
|
||||
{"type":"tool/ptc-dispatch","data":{"rootCallId":"call_office_skill","parentCallId":"call_office_skill","subCallId":"call_office_skill:ptc:1","name":"skill","arguments":{"name":"office-xlsx"},"isError":false,"content":[{"type":"text","text":"<skill_content name=\"office-xlsx\">\n<skill_resources>\nBase directory for this skill: {{cwd}}/office-skills/office-xlsx\nResolve relative paths mentioned by this skill against the base directory before using them. Load referenced resources only as needed.\n</skill_resources>\n\n<skill_instructions>\n# Excel workbooks\n\nFollow an explicit user or applicable AGENTS.md requirement for an environment or library. Otherwise call `load_workspace_dependencies` and run its Python executable with bundled `openpyxl` and `pandas`. Do not install packages or search for a system Python for the default workflow. If the tool is unavailable, use an already configured environment and report a missing dependency only when it prevents the requested operation.\n\nKeep scripts, working files, and outputs in the task workspace. The runtime and skill directory are shared read-only resources. Save to a new workbook unless the user requests an in-place edit.\n\n## Read and modify\n\nUse `openpyxl` for existing XLSX workbooks and targeted cell or style changes. Load with `data_only=False` when formulas must survive. Inspect sheet names, the affected cell types, formulas, styles, merged ranges, and referenced ranges before editing. Check the saved file by reopening it, including unchanged content that the request requires preserving.\n\nUse pandas for data analysis and transformations. A DataFrame is not the workbook: exporting it over an existing file can lose sheets, formulas, charts, and formatting. Write analysis results back to the intended ranges with openpyxl. `XlsxWriter` can create new workbooks, but cannot read or modify existing ones.\n\nFor a new workbook, the selected Python environment can write editable values, styles, and formulas directly:\n\n```python\nfrom openpyxl import Workbook\nfrom openpyxl.styles import Font\n\nworkbook = Workbook()\nsheet = workbook.active\nsheet.title = \"Revenue\"\nfor row in [(\"Quarter\", \"Revenue\"), (\"Q1\", 12), (\"Q2\", 18), (\"Total\", \"=SUM(B2:B3)\")]:\n sheet.append(row)\nfor cell in sheet[1]:\n cell.font = Font(bold=True)\nsheet.column_dimensions[\"A\"].width = 18\nsheet.column_dimensions[\"B\"].width = 18\nworkbook.save(\"report.xlsx\")\n```\n\nPreserve numbers, dates, booleans, and identifiers as the intended cell types; formatting is not a type conversion. For modifications, load the existing file with `openpyxl.load_workbook(\"input.xlsx\", data_only=False)`, change the requested ranges, and save a separate result. Avoid a DataFrame round trip when workbook features must survive.\n\nWriting a formula does not calculate its result. openpyxl and XlsxWriter do not evaluate formulas; `data_only=True` returns cached values that may be absent or stale. When calculated results must be refreshed, load `office-recalculate`. Do not replace requested formulas with constants or report stale values as newly calculated results.\n\nDo not rename `.xls`, `.xlsb`, encrypted files, or macro-enabled files to `.xlsx`. They need an appropriate supported operation. `keep_vba=True` can preserve VBA package content in an XLSM workflow, but does not execute or edit macros and does not guarantee every advanced workbook feature survives. Preserve the original and verify such requirements explicitly.\n\n## Check and deliver\n\nRun the shared structural checker when `office-check` is available:\n\nIn PowerShell, prefix the quoted Python executable with `&`. Resolve the checker path relative to this skill directory.\n\n```text\n\"<python>\" \"<skill-directory>/../scripts/check_office.py\" <workbook.xlsx> --out <checks.json>\n```\n\nIt checks ZIP/XML integrity and internal relationships, and reports sheet names, populated-cell counts, and formula counts. Repeated `--contains TEXT` arguments check string cells and sheet names, and `--count N` checks sheet count. `--contains` excludes numeric cells and does not validate formula results; verify those separately with openpyxl. The checker does not calculate formulas or judge workbook appearance. Compare relevant values, types, formulas, styles, and totals with the task's source data.\n\nIf the Python checker cannot run, use an already configured environment to check the ZIP/XML package and internal relationships. Report the missing environment if those checks cannot run; do not claim structural validation.\n\nLoad `office-render` for requested images or visual inspection and whenever the user's primary task targets appearance, including cell fill colors, text alignment, spacing, or sizing. These appearance changes require rendering even without a separate visual-check request, unless the user explicitly skips it. New workbooks and data or formula edits do not require rendering solely because they include incidenLine truncated
|
||||
{"type":"tool/result","data":{"turn":1,"step":1,"message":{"role":"tool","source":{"kind":"tool","callId":"call_office_skill"},"toolCallId":"call_office_skill","content":[{"type":"text","text":"{\n name: 'office-xlsx',\n provider: 'dsh-office',\n resourceBase: {\n kind: 'directory',\n path: '{{cwd}}/office-skills/office-xlsx'\n },\n content: '# Excel workbooks\\n' +\n '\\n' +\n 'Follow an explicit user or applicable AGENTS.md requirement for an environment or library. Otherwise call `load_workspace_dependencies` and run its Python executable with bundled `openpyxl` and `pandas`. Do not install packages or search for a system Python for the default workflow. If the tool is unavailable, use an already configured environment and report a missing dependency only when it prevents the requested operation.\\n' +\n '\\n' +\n 'Keep scripts, working files, and outputs in the task workspace. The runtime and skill directory are shared read-only resources. Save to a new workbook unless the user requests an in-place edit.\\n' +\n '\\n' +\n '## Read and modify\\n' +\n '\\n' +\n 'Use `openpyxl` for existing XLSX workbooks and targeted cell or style changes. Load with `data_only=False` when formulas must survive. Inspect sheet names, the affected cell types, formulas, styles, merged ranges, and referenced ranges before editing. Check the saved file by reopening it, including unchanged content that the request requires preserving.\\n' +\n '\\n' +\n 'Use pandas for data analysis and transformations. A DataFrame is not the workbook: exporting it over an existing file can lose sheets, formulas, charts, and formatting. Write analysis results back to the intended ranges with openpyxl. `XlsxWriter` can create new workbooks, but cannot read or modify existing ones.\\n' +\n '\\n' +\n 'For a new workbook, the selected Python environment can write editable values, styles, and formulas directly:\\n' +\n '\\n' +\n '```python\\n' +\n 'from openpyxl import Workbook\\n' +\n 'from openpyxl.styles import Font\\n' +\n '\\n' +\n 'workbook = Workbook()\\n' +\n 'sheet = workbook.active\\n' +\n 'sheet.title = \"Revenue\"\\n' +\n 'for row in [(\"Quarter\", \"Revenue\"), (\"Q1\", 12), (\"Q2\", 18), (\"Total\", \"=SUM(B2:B3)\")]:\\n' +\n ' sheet.append(row)\\n' +\n 'for cell in sheet[1]:\\n' +\n ' cell.font = Font(bold=True)\\n' +\n 'sheet.column_dimensions[\"A\"].width = 18\\n' +\n 'sheet.column_dimensions[\"B\"].width = 18\\n' +\n 'workbook.save(\"report.xlsx\")\\n' +\n '```\\n' +\n '\\n' +\n 'Preserve numbers, dates, booleans, and identifiers as the intended cell types; formatting is not a type conversion. For modifications, load the existing file with `openpyxl.load_workbook(\"input.xlsx\", data_only=False)`, change the requested ranges, and save a separate result. Avoid a DataFrame round trip when workbook features must survive.\\n' +\n '\\n' +\n 'Writing a formula does not calculate its result. openpyxl and XlsxWriter do not evaluate formulas; `data_only=True` returns cached values that may be absent or stale. When calculated results must be refreshed, load `office-recalculate`. Do not replace requested formulas with constants or report stale values as newly calculated results.\\n' +\n '\\n' +\n 'Do not rename `.xls`, `.xlsb`, encrypted files, or macro-enabled files to `.xlsx`. They need an appropriate supported operation. `keep_vba=True` can preserve VBA package content in an XLSM workflow, but does not execute or edit macros and does not guarantee every advanced workbook feature survives. Preserve the original and verify such requirements explicitly.\\n' +\n '\\n' +\n '## Check and deliver\\n' +\n '\\n' +\n 'Run the shared structural checker when `office-check` is available:\\n' +\n '\\n' +\n 'In PowerShell, prefix the quoted Python executable with `&`. Resolve the checker path relative to this skill directory.\\n' +\n '\\n' +\n '```text\\n' +\n '\"<python>\" \"<skill-directory>/../scripts/check_office.py\" <workbook.xlsx> --out <checks.json>\\n' +\n '```\\n' +\n '\\n' +\n \"It checks ZIP/XML integrity and internal relationships, and reports sheet names, populated-cell counts, and formula counts. Repeated `--contains TEXT` arguments check string cells and sheet names, and `--count N` checks sheet count. `--contains` excludes numeric cells and does not validate formula results; verify those separately with openpyxl. The checker does not calculate formulas or judge workbook appearance. Compare relevant values, types, formulas, styles, and totals with the task's source data.\\n\" +\n '\\n' +\n 'If the Python checker cannot run, use an already configured environment to check the ZIP/XML package and internal relationships. Report the missing environment if those checks cannot run; do not claim structural validation.\\n' +\n '\\n' +\n \"Load `office-render` for requested images or vLine truncated
|
||||
{"type":"agent/inbox/spliced","data":{"target":"next-step","start":0,"inserted":[{"content":[{"type":"text","text":"<skill_content name=\"office-xlsx\">\n<skill_resources>\nBase directory for this skill: {{cwd}}/office-skills/office-xlsx\nResolve relative paths mentioned by this skill against the base directory before using them. Load referenced resources only as needed.\n</skill_resources>\n\n<skill_instructions>\n# Excel workbooks\n\nFollow an explicit user or applicable AGENTS.md requirement for an environment or library. Otherwise call `load_workspace_dependencies` and run its Python executable with bundled `openpyxl` and `pandas`. Do not install packages or search for a system Python for the default workflow. If the tool is unavailable, use an already configured environment and report a missing dependency only when it prevents the requested operation.\n\nKeep scripts, working files, and outputs in the task workspace. The runtime and skill directory are shared read-only resources. Save to a new workbook unless the user requests an in-place edit.\n\n## Read and modify\n\nUse `openpyxl` for existing XLSX workbooks and targeted cell or style changes. Load with `data_only=False` when formulas must survive. Inspect sheet names, the affected cell types, formulas, styles, merged ranges, and referenced ranges before editing. Check the saved file by reopening it, including unchanged content that the request requires preserving.\n\nUse pandas for data analysis and transformations. A DataFrame is not the workbook: exporting it over an existing file can lose sheets, formulas, charts, and formatting. Write analysis results back to the intended ranges with openpyxl. `XlsxWriter` can create new workbooks, but cannot read or modify existing ones.\n\nFor a new workbook, the selected Python environment can write editable values, styles, and formulas directly:\n\n```python\nfrom openpyxl import Workbook\nfrom openpyxl.styles import Font\n\nworkbook = Workbook()\nsheet = workbook.active\nsheet.title = \"Revenue\"\nfor row in [(\"Quarter\", \"Revenue\"), (\"Q1\", 12), (\"Q2\", 18), (\"Total\", \"=SUM(B2:B3)\")]:\n sheet.append(row)\nfor cell in sheet[1]:\n cell.font = Font(bold=True)\nsheet.column_dimensions[\"A\"].width = 18\nsheet.column_dimensions[\"B\"].width = 18\nworkbook.save(\"report.xlsx\")\n```\n\nPreserve numbers, dates, booleans, and identifiers as the intended cell types; formatting is not a type conversion. For modifications, load the existing file with `openpyxl.load_workbook(\"input.xlsx\", data_only=False)`, change the requested ranges, and save a separate result. Avoid a DataFrame round trip when workbook features must survive.\n\nWriting a formula does not calculate its result. openpyxl and XlsxWriter do not evaluate formulas; `data_only=True` returns cached values that may be absent or stale. When calculated results must be refreshed, load `office-recalculate`. Do not replace requested formulas with constants or report stale values as newly calculated results.\n\nDo not rename `.xls`, `.xlsb`, encrypted files, or macro-enabled files to `.xlsx`. They need an appropriate supported operation. `keep_vba=True` can preserve VBA package content in an XLSM workflow, but does not execute or edit macros and does not guarantee every advanced workbook feature survives. Preserve the original and verify such requirements explicitly.\n\n## Check and deliver\n\nRun the shared structural checker when `office-check` is available:\n\nIn PowerShell, prefix the quoted Python executable with `&`. Resolve the checker path relative to this skill directory.\n\n```text\n\"<python>\" \"<skill-directory>/../scripts/check_office.py\" <workbook.xlsx> --out <checks.json>\n```\n\nIt checks ZIP/XML integrity and internal relationships, and reports sheet names, populated-cell counts, and formula counts. Repeated `--contains TEXT` arguments check string cells and sheet names, and `--count N` checks sheet count. `--contains` excludes numeric cells and does not validate formula results; verify those separately with openpyxl. The checker does not calculate formulas or judge workbook appearance. Compare relevant values, types, formulas, styles, and totals with the task's source data.\n\nIf the Python checker cannot run, use an already configured environment to check the ZIP/XML package and internal relationships. Report the missing environment if those checks cannot run; do not claim structural validation.\n\nLoad `office-render` for requested images or visual inspection and whenever the user's primary task targets appearance, including cell fill colors, text alignment, spacing, or sizing. These appearance changes require rendering even without a separate visual-check request, unless the user explicitly skips it. New workbooks and data or formula edits do not require rendering solely because they include incidental basic formatting. In particular, bold headers and number formats accompanying data edits do not require loading `office-reLine truncated
|
||||
{"type":"step/end","data":{"turn":1,"step":1}}
|
||||
{"type":"agent/inbox/spliced","data":{"target":"next-step","start":0,"removedCount":1,"inserted":[]}}
|
||||
{"type":"step/start","data":{"turn":1,"step":2}}
|
||||
{"type":"user/message","data":{"content":[{"type":"text","text":"<skill_content name=\"office-xlsx\">\n<skill_resources>\nBase directory for this skill: {{cwd}}/office-skills/office-xlsx\nResolve relative paths mentioned by this skill against the base directory before using them. Load referenced resources only as needed.\n</skill_resources>\n\n<skill_instructions>\n# Excel workbooks\n\nFollow an explicit user or applicable AGENTS.md requirement for an environment or library. Otherwise call `load_workspace_dependencies` and run its Python executable with bundled `openpyxl` and `pandas`. Do not install packages or search for a system Python for the default workflow. If the tool is unavailable, use an already configured environment and report a missing dependency only when it prevents the requested operation.\n\nKeep scripts, working files, and outputs in the task workspace. The runtime and skill directory are shared read-only resources. Save to a new workbook unless the user requests an in-place edit.\n\n## Read and modify\n\nUse `openpyxl` for existing XLSX workbooks and targeted cell or style changes. Load with `data_only=False` when formulas must survive. Inspect sheet names, the affected cell types, formulas, styles, merged ranges, and referenced ranges before editing. Check the saved file by reopening it, including unchanged content that the request requires preserving.\n\nUse pandas for data analysis and transformations. A DataFrame is not the workbook: exporting it over an existing file can lose sheets, formulas, charts, and formatting. Write analysis results back to the intended ranges with openpyxl. `XlsxWriter` can create new workbooks, but cannot read or modify existing ones.\n\nFor a new workbook, the selected Python environment can write editable values, styles, and formulas directly:\n\n```python\nfrom openpyxl import Workbook\nfrom openpyxl.styles import Font\n\nworkbook = Workbook()\nsheet = workbook.active\nsheet.title = \"Revenue\"\nfor row in [(\"Quarter\", \"Revenue\"), (\"Q1\", 12), (\"Q2\", 18), (\"Total\", \"=SUM(B2:B3)\")]:\n sheet.append(row)\nfor cell in sheet[1]:\n cell.font = Font(bold=True)\nsheet.column_dimensions[\"A\"].width = 18\nsheet.column_dimensions[\"B\"].width = 18\nworkbook.save(\"report.xlsx\")\n```\n\nPreserve numbers, dates, booleans, and identifiers as the intended cell types; formatting is not a type conversion. For modifications, load the existing file with `openpyxl.load_workbook(\"input.xlsx\", data_only=False)`, change the requested ranges, and save a separate result. Avoid a DataFrame round trip when workbook features must survive.\n\nWriting a formula does not calculate its result. openpyxl and XlsxWriter do not evaluate formulas; `data_only=True` returns cached values that may be absent or stale. When calculated results must be refreshed, load `office-recalculate`. Do not replace requested formulas with constants or report stale values as newly calculated results.\n\nDo not rename `.xls`, `.xlsb`, encrypted files, or macro-enabled files to `.xlsx`. They need an appropriate supported operation. `keep_vba=True` can preserve VBA package content in an XLSM workflow, but does not execute or edit macros and does not guarantee every advanced workbook feature survives. Preserve the original and verify such requirements explicitly.\n\n## Check and deliver\n\nRun the shared structural checker when `office-check` is available:\n\n```text\noffice-check <workbook.xlsx> --out <checks.json>\n```\n\nIt checks ZIP/XML integrity and internal relationships, and reports sheet names, populated-cell counts, and formula counts. Repeated `--contains TEXT` arguments check string cells and sheet names, and `--count N` checks sheet count. `--contains` excludes numeric cells and does not validate formula results; verify those separately with openpyxl. The checker does not calculate formulas or judge workbook appearance. Compare relevant values, types, formulas, styles, and totals with the task's source data.\n\nIf `office-check` is unavailable, use an already configured environment to check the ZIP/XML package and internal relationships. Report the missing environment if those checks cannot run; do not claim structural validation.\n\nLoad `office-render` for requested images or visual inspection and whenever the user's primary task targets appearance, including cell fill colors, text alignment, spacing, or sizing. These appearance changes require rendering even without a separate visual-check request, unless the user explicitly skips it. New workbooks and data or formula edits do not require rendering solely because they include incidental basic formatting. In particular, bold headers and number formats accompanying data edits do not require loading `office-render` or running its commands.\n\nLoad `office-recalculate` when refreshed calculated values are needed and `office-export-pdf` for PDF output. Deliver after structural and data checks pass and the required operations finisLine truncated
|
||||
{"type":"user/message","data":{"content":[{"type":"text","text":"<skill_content name=\"office-xlsx\">\n<skill_resources>\nBase directory for this skill: {{cwd}}/office-skills/office-xlsx\nResolve relative paths mentioned by this skill against the base directory before using them. Load referenced resources only as needed.\n</skill_resources>\n\n<skill_instructions>\n# Excel workbooks\n\nFollow an explicit user or applicable AGENTS.md requirement for an environment or library. Otherwise call `load_workspace_dependencies` and run its Python executable with bundled `openpyxl` and `pandas`. Do not install packages or search for a system Python for the default workflow. If the tool is unavailable, use an already configured environment and report a missing dependency only when it prevents the requested operation.\n\nKeep scripts, working files, and outputs in the task workspace. The runtime and skill directory are shared read-only resources. Save to a new workbook unless the user requests an in-place edit.\n\n## Read and modify\n\nUse `openpyxl` for existing XLSX workbooks and targeted cell or style changes. Load with `data_only=False` when formulas must survive. Inspect sheet names, the affected cell types, formulas, styles, merged ranges, and referenced ranges before editing. Check the saved file by reopening it, including unchanged content that the request requires preserving.\n\nUse pandas for data analysis and transformations. A DataFrame is not the workbook: exporting it over an existing file can lose sheets, formulas, charts, and formatting. Write analysis results back to the intended ranges with openpyxl. `XlsxWriter` can create new workbooks, but cannot read or modify existing ones.\n\nFor a new workbook, the selected Python environment can write editable values, styles, and formulas directly:\n\n```python\nfrom openpyxl import Workbook\nfrom openpyxl.styles import Font\n\nworkbook = Workbook()\nsheet = workbook.active\nsheet.title = \"Revenue\"\nfor row in [(\"Quarter\", \"Revenue\"), (\"Q1\", 12), (\"Q2\", 18), (\"Total\", \"=SUM(B2:B3)\")]:\n sheet.append(row)\nfor cell in sheet[1]:\n cell.font = Font(bold=True)\nsheet.column_dimensions[\"A\"].width = 18\nsheet.column_dimensions[\"B\"].width = 18\nworkbook.save(\"report.xlsx\")\n```\n\nPreserve numbers, dates, booleans, and identifiers as the intended cell types; formatting is not a type conversion. For modifications, load the existing file with `openpyxl.load_workbook(\"input.xlsx\", data_only=False)`, change the requested ranges, and save a separate result. Avoid a DataFrame round trip when workbook features must survive.\n\nWriting a formula does not calculate its result. openpyxl and XlsxWriter do not evaluate formulas; `data_only=True` returns cached values that may be absent or stale. When calculated results must be refreshed, load `office-recalculate`. Do not replace requested formulas with constants or report stale values as newly calculated results.\n\nDo not rename `.xls`, `.xlsb`, encrypted files, or macro-enabled files to `.xlsx`. They need an appropriate supported operation. `keep_vba=True` can preserve VBA package content in an XLSM workflow, but does not execute or edit macros and does not guarantee every advanced workbook feature survives. Preserve the original and verify such requirements explicitly.\n\n## Check and deliver\n\nRun the shared structural checker when `office-check` is available:\n\nIn PowerShell, prefix the quoted Python executable with `&`. Resolve the checker path relative to this skill directory.\n\n```text\n\"<python>\" \"<skill-directory>/../scripts/check_office.py\" <workbook.xlsx> --out <checks.json>\n```\n\nIt checks ZIP/XML integrity and internal relationships, and reports sheet names, populated-cell counts, and formula counts. Repeated `--contains TEXT` arguments check string cells and sheet names, and `--count N` checks sheet count. `--contains` excludes numeric cells and does not validate formula results; verify those separately with openpyxl. The checker does not calculate formulas or judge workbook appearance. Compare relevant values, types, formulas, styles, and totals with the task's source data.\n\nIf the Python checker cannot run, use an already configured environment to check the ZIP/XML package and internal relationships. Report the missing environment if those checks cannot run; do not claim structural validation.\n\nLoad `office-render` for requested images or visual inspection and whenever the user's primary task targets appearance, including cell fill colors, text alignment, spacing, or sizing. These appearance changes require rendering even without a separate visual-check request, unless the user explicitly skips it. New workbooks and data or formula edits do not require rendering solely because they include incidental basic formatting. In particular, bold headers and number formats accompanying data edits do not require loading `office-render` or running its commands.\n\nLoad `office-recaLine truncated
|
||||
{"type":"assistant/message","data":{"turn":1,"step":2,"message":{"role":"assistant","content":[{"type":"tool-call","id":"call_office_2","name":"run_code","arguments":"{\"code\":\"console.log(await tools.office_tools({\\\"action\\\":\\\"load\\\"}));\",\"description\":\"Use the Office workflow\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{message:9}}"},"stream":[{"type":"chunk","time":1791559901972,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}},{"type":"tool-call-chunks","time0":1791559901972,"index":0,"dt":[],"id":"call_office_2","name":"run_code","args":["{\"code\":\"console.log(await tools.office_tools({\\\"action\\\":\\\"load\\\"}));\",\"description\":\"Use the Office workflow\"}"]},{"type":"chunk","time":1791559901972,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"call_office_2","name":"run_code","arguments":"{\"code\":\"console.log(await tools.office_tools({\\\"action\\\":\\\"load\\\"}));\",\"description\":\"Use the Office workflow\"}"}}},{"type":"chunk","time":1791559901972,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}]},"surfaceOp":"append"}
|
||||
{"type":"tool/call","data":{"turn":1,"step":2,"callId":"call_office_2","name":"run_code","arguments":"{\"code\":\"console.log(await tools.office_tools({\\\"action\\\":\\\"load\\\"}));\",\"description\":\"Use the Office workflow\"}"}}
|
||||
{"type":"tool/result","data":{"turn":1,"step":2,"message":{"role":"tool","source":{"kind":"tool","callId":"call_office_2"},"toolCallId":"call_office_2","content":[{"type":"text","text":"Error: code run failed (exception): TypeError: tools.office_tools is not a function\nFile sandbox: danger-full-access."}],"isError":true,"id":"{{message:10}}"},"error":{"name":"CodeRunFailedError","code":"CODE_RUN_FAILED"}},"sourceEventSeqs":[26],"surfaceOp":"append"}
|
||||
|
||||
@@ -52,16 +52,11 @@
|
||||
disabled: false
|
||||
config:
|
||||
assetRoot: !!js process.cwd() + '/office-skills'
|
||||
node: !!js process.cwd() + '/office-node'
|
||||
cli: !!js process.cwd() + '/render-cli.cjs'
|
||||
|
||||
- id: tool-bash
|
||||
disabled: true
|
||||
|
||||
- id: tool-pwsh
|
||||
disabled: true
|
||||
|
||||
- insert:
|
||||
- id: office-commands
|
||||
name: '@deepseek-ai/dsh-skill-office/commands'
|
||||
disabled: false
|
||||
config:
|
||||
command: !!js "[process.cwd() + '/office-node', process.cwd() + '/render-cli.cjs']"
|
||||
@@ -3,15 +3,11 @@
|
||||
name: '@deepseek-ai/dsh-skill-office'
|
||||
config:
|
||||
assetRoot: !!js process.cwd() + '/office-skills'
|
||||
node: !!js process.cwd() + '/office-node'
|
||||
cli: !!js process.cwd() + '/render-cli.cjs'
|
||||
|
||||
- id: tool-bash
|
||||
disabled: true
|
||||
|
||||
- id: tool-pwsh
|
||||
disabled: true
|
||||
|
||||
- insert:
|
||||
- id: office-commands
|
||||
name: '@deepseek-ai/dsh-skill-office/commands'
|
||||
config:
|
||||
command: !!js "[process.cwd() + '/office-node', process.cwd() + '/render-cli.cjs']"
|
||||
@@ -10,13 +10,13 @@
|
||||
{"type":"user/message","data":{"content":[{"type":"text","text":"/office-docx Load the Office rendering tool, render page 1 of report.docx to preview, remove the rendering tool, then reply DONE."}],"source":{"kind":"user"},"role":"user","id":"{{message:1}}"},"surfaceOp":"append"}
|
||||
{"type":"user/message","data":{"content":[{"type":"text","text":"Current runtime context. This snapshot supersedes earlier runtime-context snapshots.\n\nCurrent working directory: \"{{cwd}}\".\n\nCurrent DSH file policy: danger-full-access. The DSH file sandbox does not restrict file modifications by available operations.\n\nApproval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`)."}],"source":{"kind":"runtime-context","form":"snapshot","sections":[{"name":"working-directory:current","text":"Current working directory: \"{{cwd}}\"."},{"name":"sandbox:policy","text":"Current DSH file policy: danger-full-access. The DSH file sandbox does not restrict file modifications by available operations."},{"name":"approval:policy","text":"Approval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`)."}]},"role":"user","id":"{{message:3}}"},"surfaceOp":"append"}
|
||||
{"type":"user/message","data":{"content":[{"type":"text","text":"<system-reminder>\nA skill is a reusable set of task-specific instructions. The following skills are available in this session:\n\n<available_skills>\n- `office`: Create, edit, inspect, or convert Office documents, spreadsheets, presentations, and PDFs. Load to choose the relevant workflow.\n- `office-docx`: Create, read, edit, and validate Word documents (.docx).\n- `office-export-pdf`: Convert an Office document to a requested PDF with LibreOffice Kit.\n- `office-pptx`: Create, read, edit, and validate PowerPoint presentations (.pptx).\n- `office-recalculate`: Refresh spreadsheet formula caches and verify calculated values with LibreOffice Kit.\n- `office-render`: Render requested document images or inspect visual layout with LibreOffice Kit.\n- `office-xlsx`: Read, create, edit, and validate Excel workbooks, data, and formulas (.xlsx).\n</available_skills>\n\nIf the user names a skill, or the task clearly matches a skill's description, call the `skill` tool with the exact skill name before taking task actions. Load all applicable skills, then follow their full instructions. This catalog contains summaries only; do not infer or follow a skill's instructions until it has been loaded.\nA user may also invoke a skill directly; its <skill_content> block then appears in this conversation. Follow it, and do not call the `skill` tool again for that skill.\n</system-reminder>"}],"source":{"kind":"skill-catalog","form":"catalog","entries":[{"name":"office","description":"Create, edit, inspect, or convert Office documents, spreadsheets, presentations, and PDFs. Load to choose the relevant workflow."},{"name":"office-docx","description":"Create, read, edit, and validate Word documents (.docx)."},{"name":"office-export-pdf","description":"Convert an Office document to a requested PDF with LibreOffice Kit."},{"name":"office-pptx","description":"Create, read, edit, and validate PowerPoint presentations (.pptx)."},{"name":"office-recalculate","description":"Refresh spreadsheet formula caches and verify calculated values with LibreOffice Kit."},{"name":"office-render","description":"Render requested document images or inspect visual layout with LibreOffice Kit."},{"name":"office-xlsx","description":"Read, create, edit, and validate Excel workbooks, data, and formulas (.xlsx)."}]},"role":"user","id":"{{message:4}}"},"surfaceOp":"append"}
|
||||
{"type":"user/message","data":{"content":[{"type":"text","text":"<skill_content name=\"office-docx\">\n<skill_resources>\nBase directory for this skill: {{cwd}}/office-skills/office-docx\nResolve relative paths mentioned by this skill against the base directory before using them. Load referenced resources only as needed.\n</skill_resources>\n\n<skill_instructions>\n# Word documents\n\nUse `python-docx` for DOCX creation and ordinary edits. Follow an explicit user or applicable AGENTS.md requirement for a project environment or another library. Otherwise call `load_workspace_dependencies` and execute the returned Python path with its bundled libraries. Do not install packages or discover a system Python for the default workflow. If the tool is unavailable, use an already configured environment and report a missing dependency only when it prevents the requested operation.\n\nKeep source scripts, intermediate files, and final documents in the task workspace; the runtime and this skill directory are read-only resources. Use the user's requested language and preserve an existing document's design unless a redesign is requested.\n\n## Create and edit\n\nFor existing files, inspect paragraphs, runs, tables, sections, headers, and footers before changing the affected content. Save to a new file unless the user requests an in-place edit. Replacing a paragraph's `.text` destroys its run formatting; change the relevant runs when formatting must survive. Reconstructing the whole document can lose features outside python-docx's supported editing API.\n\nUse paragraph styles for headings and body text. Size tables for the section that contains them, and account for merged cells and nested tables. Chinese, Japanese, and Korean text may need an explicit `w:eastAsia` font assignment in addition to `run.font.name`; font names alone do not establish glyph availability or rendered appearance.\n\nFor a new document, use the selected Python executable:\n\n```python\nfrom docx import Document\n\ndocument = Document()\ndocument.add_heading(\"Project report\", level=0)\ndocument.add_paragraph(\"Summary\", style=\"Heading 1\")\ndocument.add_paragraph(\"The requested findings go here.\")\ndocument.save(\"report.docx\")\n```\n\npython-docx does not paginate or render documents. Do not represent ordinary replacement, colored text, or comments as tracked changes. When real revisions or unsupported OOXML features matter, preserve their package parts and verify the requested operation rather than silently discarding them.\n\n## Check and deliver\n\nRun the shared structural checker when `office-check` is available:\n\n```text\noffice-check <document.docx> --out <checks.json>\n```\n\nIt checks ZIP/XML integrity and internal relationships, and reports paragraphs, logical table dimensions, and sections. Optional `--contains TEXT` arguments assert required text. A successful structural check does not verify pagination, clipping, fonts, or visual appearance. Compare the summary and reopened document with the user's request, including unchanged content that matters to an edit.\n\nIf `office-check` is unavailable, use an already configured environment to check the ZIP/XML package and internal relationships. Report the missing environment if those checks cannot run; do not claim structural validation.\n\nDeliver after the requested content and structural checks pass. Creating a file or changing content with incidental basic formatting does not require additional operations. Load `office-render` for requested images or visual inspection and for appearance-focused styling, spacing, sizing, or alignment changes unless the user explicitly skips rendering. For PDF output load `office-export-pdf`.\n\nCall `present({\"files\":[{\"path\":\"report.docx\"}]})` with the actual final DOCX path. It exposes the current source file without copying or preserving its bytes, so keep that file in place and do not present temporary QA reports unless requested. If `present` is unavailable, provide the final workspace path using the session's supported file delivery method.\n</skill_instructions>\n</skill_content>"}],"source":{"kind":"skill-invocation","name":"office-docx","form":"instructions"},"role":"user","id":"{{message:5}}"},"surfaceOp":"append"}
|
||||
{"type":"user/message","data":{"content":[{"type":"text","text":"<skill_content name=\"office-docx\">\n<skill_resources>\nBase directory for this skill: {{cwd}}/office-skills/office-docx\nResolve relative paths mentioned by this skill against the base directory before using them. Load referenced resources only as needed.\n</skill_resources>\n\n<skill_instructions>\n# Word documents\n\nUse `python-docx` for DOCX creation and ordinary edits. Follow an explicit user or applicable AGENTS.md requirement for a project environment or another library. Otherwise call `load_workspace_dependencies` and execute the returned Python path with its bundled libraries. Do not install packages or discover a system Python for the default workflow. If the tool is unavailable, use an already configured environment and report a missing dependency only when it prevents the requested operation.\n\nKeep source scripts, intermediate files, and final documents in the task workspace; the runtime and this skill directory are read-only resources. Use the user's requested language and preserve an existing document's design unless a redesign is requested.\n\n## Create and edit\n\nFor existing files, inspect paragraphs, runs, tables, sections, headers, and footers before changing the affected content. Save to a new file unless the user requests an in-place edit. Replacing a paragraph's `.text` destroys its run formatting; change the relevant runs when formatting must survive. Reconstructing the whole document can lose features outside python-docx's supported editing API.\n\nUse paragraph styles for headings and body text. Size tables for the section that contains them, and account for merged cells and nested tables. Chinese, Japanese, and Korean text may need an explicit `w:eastAsia` font assignment in addition to `run.font.name`; font names alone do not establish glyph availability or rendered appearance.\n\nFor a new document, use the selected Python executable:\n\n```python\nfrom docx import Document\n\ndocument = Document()\ndocument.add_heading(\"Project report\", level=0)\ndocument.add_paragraph(\"Summary\", style=\"Heading 1\")\ndocument.add_paragraph(\"The requested findings go here.\")\ndocument.save(\"report.docx\")\n```\n\npython-docx does not paginate or render documents. Do not represent ordinary replacement, colored text, or comments as tracked changes. When real revisions or unsupported OOXML features matter, preserve their package parts and verify the requested operation rather than silently discarding them.\n\n## Check and deliver\n\nRun the shared structural checker when `office-check` is available:\n\nIn PowerShell, prefix the quoted Python executable with `&`. Resolve the checker path relative to this skill directory.\n\n```text\n\"<python>\" \"<skill-directory>/../scripts/check_office.py\" <document.docx> --out <checks.json>\n```\n\nIt checks ZIP/XML integrity and internal relationships, and reports paragraphs, logical table dimensions, and sections. Optional `--contains TEXT` arguments assert required text. A successful structural check does not verify pagination, clipping, fonts, or visual appearance. Compare the summary and reopened document with the user's request, including unchanged content that matters to an edit.\n\nIf the Python checker cannot run, use an already configured environment to check the ZIP/XML package and internal relationships. Report the missing environment if those checks cannot run; do not claim structural validation.\n\nDeliver after the requested content and structural checks pass. Creating a file or changing content with incidental basic formatting does not require additional operations. Load `office-render` for requested images or visual inspection. When styling, font color, spacing, sizing, or text alignment is the requested edit, load `office-render` and inspect the changed page even without a separate visual-check request, unless the user explicitly skips rendering. For PDF output load `office-export-pdf`.\n\nCall `present({\"files\":[{\"path\":\"report.docx\"}]})` with the actual final DOCX path. It exposes the current source file without copying or preserving its bytes, so keep that file in place and do not present temporary QA reports unless requested. If `present` is unavailable, provide the final workspace path using the session's supported file delivery method.\n</skill_instructions>\n</skill_content>"}],"source":{"kind":"skill-invocation","name":"office-docx","form":"instructions"},"role":"user","id":"{{message:5}}"},"surfaceOp":"append"}
|
||||
{"type":"request/header","data":{"header":{"config":{"provider":"deepseek-official","model":"deepseek-v4-flash"},"tools":"{{tools}}"},"reason":"initial"}}
|
||||
{"type":"request/context","data":{"provider":"deepseek-official","model":"deepseek-v4-flash"}}
|
||||
{"type":"session/title","data":{"title":"/office-docx Load the Office rendering","messageSeqs":[8],"source":{"kind":"fallback"}}}
|
||||
{"type":"assistant/message","data":{"turn":1,"step":1,"message":{"role":"assistant","content":[{"type":"tool-call","id":"call_office_skill","name":"skill","arguments":"{\"name\":\"office-xlsx\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{message:6}}"},"stream":[{"type":"chunk","time":1791559900742,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}},{"type":"tool-call-chunks","time0":1791559900742,"index":0,"dt":[],"id":"call_office_skill","name":"skill","args":["{\"name\":\"office-xlsx\"}"]},{"type":"chunk","time":1791559900742,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"call_office_skill","name":"skill","arguments":"{\"name\":\"office-xlsx\"}"}}},{"type":"chunk","time":1791559900742,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}]},"surfaceOp":"append"}
|
||||
{"type":"tool/call","data":{"turn":1,"step":1,"callId":"call_office_skill","name":"skill","arguments":"{\"name\":\"office-xlsx\"}"}}
|
||||
{"type":"tool/result","data":{"turn":1,"step":1,"message":{"role":"tool","source":{"kind":"tool","callId":"call_office_skill"},"toolCallId":"call_office_skill","content":[{"type":"text","text":"<skill_content name=\"office-xlsx\">\n<skill_resources>\nBase directory for this skill: {{cwd}}/office-skills/office-xlsx\nResolve relative paths mentioned by this skill against the base directory before using them. Load referenced resources only as needed.\n</skill_resources>\n\n<skill_instructions>\n# Excel workbooks\n\nFollow an explicit user or applicable AGENTS.md requirement for an environment or library. Otherwise call `load_workspace_dependencies` and run its Python executable with bundled `openpyxl` and `pandas`. Do not install packages or search for a system Python for the default workflow. If the tool is unavailable, use an already configured environment and report a missing dependency only when it prevents the requested operation.\n\nKeep scripts, working files, and outputs in the task workspace. The runtime and skill directory are shared read-only resources. Save to a new workbook unless the user requests an in-place edit.\n\n## Read and modify\n\nUse `openpyxl` for existing XLSX workbooks and targeted cell or style changes. Load with `data_only=False` when formulas must survive. Inspect sheet names, the affected cell types, formulas, styles, merged ranges, and referenced ranges before editing. Check the saved file by reopening it, including unchanged content that the request requires preserving.\n\nUse pandas for data analysis and transformations. A DataFrame is not the workbook: exporting it over an existing file can lose sheets, formulas, charts, and formatting. Write analysis results back to the intended ranges with openpyxl. `XlsxWriter` can create new workbooks, but cannot read or modify existing ones.\n\nFor a new workbook, the selected Python environment can write editable values, styles, and formulas directly:\n\n```python\nfrom openpyxl import Workbook\nfrom openpyxl.styles import Font\n\nworkbook = Workbook()\nsheet = workbook.active\nsheet.title = \"Revenue\"\nfor row in [(\"Quarter\", \"Revenue\"), (\"Q1\", 12), (\"Q2\", 18), (\"Total\", \"=SUM(B2:B3)\")]:\n sheet.append(row)\nfor cell in sheet[1]:\n cell.font = Font(bold=True)\nsheet.column_dimensions[\"A\"].width = 18\nsheet.column_dimensions[\"B\"].width = 18\nworkbook.save(\"report.xlsx\")\n```\n\nPreserve numbers, dates, booleans, and identifiers as the intended cell types; formatting is not a type conversion. For modifications, load the existing file with `openpyxl.load_workbook(\"input.xlsx\", data_only=False)`, change the requested ranges, and save a separate result. Avoid a DataFrame round trip when workbook features must survive.\n\nWriting a formula does not calculate its result. openpyxl and XlsxWriter do not evaluate formulas; `data_only=True` returns cached values that may be absent or stale. When calculated results must be refreshed, load `office-recalculate`. Do not replace requested formulas with constants or report stale values as newly calculated results.\n\nDo not rename `.xls`, `.xlsb`, encrypted files, or macro-enabled files to `.xlsx`. They need an appropriate supported operation. `keep_vba=True` can preserve VBA package content in an XLSM workflow, but does not execute or edit macros and does not guarantee every advanced workbook feature survives. Preserve the original and verify such requirements explicitly.\n\n## Check and deliver\n\nRun the shared structural checker when `office-check` is available:\n\n```text\noffice-check <workbook.xlsx> --out <checks.json>\n```\n\nIt checks ZIP/XML integrity and internal relationships, and reports sheet names, populated-cell counts, and formula counts. Repeated `--contains TEXT` arguments check string cells and sheet names, and `--count N` checks sheet count. `--contains` excludes numeric cells and does not validate formula results; verify those separately with openpyxl. The checker does not calculate formulas or judge workbook appearance. Compare relevant values, types, formulas, styles, and totals with the task's source data.\n\nIf `office-check` is unavailable, use an already configured environment to check the ZIP/XML package and internal relationships. Report the missing environment if those checks cannot run; do not claim structural validation.\n\nLoad `office-render` for requested images or visual inspection and whenever the user's primary task targets appearance, including cell fill colors, text alignment, spacing, or sizing. These appearance changes require rendering even without a separate visual-check request, unless the user explicitly skips it. New workbooks and data or formula edits do not require rendering solely because they include incidental basic formatting. In particular, bold headers and number formats accompanying data edits do not require loading `office-render` or running its commands.\n\nLoad `office-recalculate` when refreshed calculated values aLine truncated
|
||||
{"type":"tool/result","data":{"turn":1,"step":1,"message":{"role":"tool","source":{"kind":"tool","callId":"call_office_skill"},"toolCallId":"call_office_skill","content":[{"type":"text","text":"<skill_content name=\"office-xlsx\">\n<skill_resources>\nBase directory for this skill: {{cwd}}/office-skills/office-xlsx\nResolve relative paths mentioned by this skill against the base directory before using them. Load referenced resources only as needed.\n</skill_resources>\n\n<skill_instructions>\n# Excel workbooks\n\nFollow an explicit user or applicable AGENTS.md requirement for an environment or library. Otherwise call `load_workspace_dependencies` and run its Python executable with bundled `openpyxl` and `pandas`. Do not install packages or search for a system Python for the default workflow. If the tool is unavailable, use an already configured environment and report a missing dependency only when it prevents the requested operation.\n\nKeep scripts, working files, and outputs in the task workspace. The runtime and skill directory are shared read-only resources. Save to a new workbook unless the user requests an in-place edit.\n\n## Read and modify\n\nUse `openpyxl` for existing XLSX workbooks and targeted cell or style changes. Load with `data_only=False` when formulas must survive. Inspect sheet names, the affected cell types, formulas, styles, merged ranges, and referenced ranges before editing. Check the saved file by reopening it, including unchanged content that the request requires preserving.\n\nUse pandas for data analysis and transformations. A DataFrame is not the workbook: exporting it over an existing file can lose sheets, formulas, charts, and formatting. Write analysis results back to the intended ranges with openpyxl. `XlsxWriter` can create new workbooks, but cannot read or modify existing ones.\n\nFor a new workbook, the selected Python environment can write editable values, styles, and formulas directly:\n\n```python\nfrom openpyxl import Workbook\nfrom openpyxl.styles import Font\n\nworkbook = Workbook()\nsheet = workbook.active\nsheet.title = \"Revenue\"\nfor row in [(\"Quarter\", \"Revenue\"), (\"Q1\", 12), (\"Q2\", 18), (\"Total\", \"=SUM(B2:B3)\")]:\n sheet.append(row)\nfor cell in sheet[1]:\n cell.font = Font(bold=True)\nsheet.column_dimensions[\"A\"].width = 18\nsheet.column_dimensions[\"B\"].width = 18\nworkbook.save(\"report.xlsx\")\n```\n\nPreserve numbers, dates, booleans, and identifiers as the intended cell types; formatting is not a type conversion. For modifications, load the existing file with `openpyxl.load_workbook(\"input.xlsx\", data_only=False)`, change the requested ranges, and save a separate result. Avoid a DataFrame round trip when workbook features must survive.\n\nWriting a formula does not calculate its result. openpyxl and XlsxWriter do not evaluate formulas; `data_only=True` returns cached values that may be absent or stale. When calculated results must be refreshed, load `office-recalculate`. Do not replace requested formulas with constants or report stale values as newly calculated results.\n\nDo not rename `.xls`, `.xlsb`, encrypted files, or macro-enabled files to `.xlsx`. They need an appropriate supported operation. `keep_vba=True` can preserve VBA package content in an XLSM workflow, but does not execute or edit macros and does not guarantee every advanced workbook feature survives. Preserve the original and verify such requirements explicitly.\n\n## Check and deliver\n\nRun the shared structural checker when `office-check` is available:\n\nIn PowerShell, prefix the quoted Python executable with `&`. Resolve the checker path relative to this skill directory.\n\n```text\n\"<python>\" \"<skill-directory>/../scripts/check_office.py\" <workbook.xlsx> --out <checks.json>\n```\n\nIt checks ZIP/XML integrity and internal relationships, and reports sheet names, populated-cell counts, and formula counts. Repeated `--contains TEXT` arguments check string cells and sheet names, and `--count N` checks sheet count. `--contains` excludes numeric cells and does not validate formula results; verify those separately with openpyxl. The checker does not calculate formulas or judge workbook appearance. Compare relevant values, types, formulas, styles, and totals with the task's source data.\n\nIf the Python checker cannot run, use an already configured environment to check the ZIP/XML package and internal relationships. Report the missing environment if those checks cannot run; do not claim structural validation.\n\nLoad `office-render` for requested images or visual inspection and whenever the user's primary task targets appearance, including cell fill colors, text alignment, spacing, or sizing. These appearance changes require rendering even without a separate visual-check request, unless the user explicitly skips it. New workbooks and data or formula edits do not require rendering solely because they include incidental basic formatting. In particular, bold headerLine truncated
|
||||
{"type":"step/end","data":{"turn":1,"step":1}}
|
||||
{"type":"step/start","data":{"turn":1,"step":2}}
|
||||
{"type":"assistant/message","data":{"turn":1,"step":2,"message":{"role":"assistant","content":[{"type":"tool-call","id":"call_office_2","name":"office_tools","arguments":"{\"action\":\"load\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{message:8}}"},"stream":[{"type":"chunk","time":1791559900760,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}},{"type":"tool-call-chunks","time0":1791559900760,"index":0,"dt":[],"id":"call_office_2","name":"office_tools","args":["{\"action\":\"load\"}"]},{"type":"chunk","time":1791559900760,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"call_office_2","name":"office_tools","arguments":"{\"action\":\"load\"}"}}},{"type":"chunk","time":1791559900760,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}]},"surfaceOp":"append"}
|
||||
|
||||
@@ -52,6 +52,7 @@
|
||||
disabled: false
|
||||
config:
|
||||
assetRoot: !!js process.cwd() + '/office-skills'
|
||||
cli: false
|
||||
|
||||
- id: tool-bash
|
||||
disabled: true
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
disabled: false
|
||||
config:
|
||||
assetRoot: !!js process.cwd() + '/office-skills'
|
||||
cli: false
|
||||
|
||||
- id: tool-bash
|
||||
disabled: true
|
||||
|
||||
@@ -15,17 +15,17 @@
|
||||
{"type":"session/title","data":{"title":"Load the Office rendering, PDF","messageSeqs":[8],"source":{"kind":"fallback"}}}
|
||||
{"type":"assistant/message","data":{"turn":1,"step":1,"message":{"role":"assistant","content":[{"type":"tool-call","id":"call_office_skill","name":"skill","arguments":"{\"name\":\"office-render\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{message:5}}"},"stream":[{"type":"chunk","time":1790753571607,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}},{"type":"tool-call-chunks","time0":1790753571608,"index":0,"dt":[],"id":"call_office_skill","name":"skill","args":["{\"name\":\"office-render\"}"]},{"type":"chunk","time":1790753571608,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"call_office_skill","name":"skill","arguments":"{\"name\":\"office-render\"}"}}},{"type":"chunk","time":1790753571608,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}]},"surfaceOp":"append"}
|
||||
{"type":"tool/call","data":{"turn":1,"step":1,"callId":"call_office_skill","name":"skill","arguments":"{\"name\":\"office-render\"}"}}
|
||||
{"type":"tool/result","data":{"turn":1,"step":1,"message":{"role":"tool","source":{"kind":"tool","callId":"call_office_skill"},"toolCallId":"call_office_skill","content":[{"type":"text","text":"<skill_content name=\"office-render\">\n<skill_resources>\nBase directory for this skill: {{cwd}}/office-skills/office-render\nResolve relative paths mentioned by this skill against the base directory before using them. Load referenced resources only as needed.\n</skill_resources>\n\n<skill_instructions>\n# Document images and visual inspection\n\nUse the installed LibreOffice Kit CLI through the shell with `dsoffice`. Prefer bundled LibreOffice unless the user requests another installation. If the Office sidecar is missing, follow [sidecar setup](../office/references/sidecar.md): ask whether the user wants to download it and install only after they agree. Do not invoke system soffice, use npx, install a replacement renderer, or build an alternative rendering pipeline to work around a failed render with an installed sidecar.\n\nBefore generating images only for inspection, establish that the current model accepts images. Otherwise finish the applicable content and structure checks and report the requested visual check as unavailable. Do not generate unreadable previews, retry image reads, or choose a second model. Requested image exports can still be delivered.\n\n## Render the saved deliverable\n\nKeep the saved deliverable in the task workspace. For requested image exports, use the requested output directory and retain the images. For inspection-only previews, create a private, uniquely named temporary parent inside that workspace and pass a child path that does not yet exist as `--output-dir`; the CLI creates that child. On POSIX, use `preview_root=$(mktemp -d \"./.dsh-office.XXXXXXXX\")` (owner-only permissions) and `--output-dir \"$preview_root/render\"`. On PowerShell, create a parent named `.dsh-office-` plus `[guid]::NewGuid().ToString('N')` under the task workspace and pass an uncreated `render` child; it inherits the workspace ACL. Quote each input and output path. Retain the parent until image inspection finishes, then remove only that parent, including after a failed render. Never use a fixed directory name or remove the workspace itself.\n\n```text\ndsoffice render --input <final-file> --output-dir <new-directory> --pages \"1,3,4\"\ndsoffice render --input <final-workbook.xlsx> --output-dir <new-directory> --sheet <exact-name> --range <A1-range>\n```\n\nFor DOCX, PPTX, or PDF, batch requested pages/slides in one call. In PowerShell, quote comma-separated `--pages` values so they remain one argument. Inspect all pages only for a requested whole-document review. For worksheets, choose the exact affected range, including chart/drawing regions; worksheet numbers are not PDF page numbers. Inspect the final saved file, reuse existing images for an unchanged source, and rerender only after requested source changes or for previously unrendered regions. Change print areas or scaling only when the user requests print layout.\n\nRead the returned JSON manifest for image paths, page counts, fragment rectangles, and missing-font diagnostics. Use the session's image-reading tool to inspect the requested images. Check clipping, alignment, headings, table widths, contrast, chart labels, and number formats as relevant to the task. A successful command or image read alone does not establish a usable preview; guessed text geometry does not establish overflow.\n\n## Failed or blank previews\n\nFor populated content, a fully transparent or uniformly blank image is a renderer failure. If a pixel check is needed, composite RGBA onto white first; raw RGB under transparent pixels can look nonblank. Check once and do not reread the same image. Stop visual checks for the task immediately after a blank result. This overrides the rerender-after-edit guidance above: do not render or read images again, even after editing or copying the source, or try another range, page, sheet, DPI, output format, diagnostic export, or print setting. Preserve the usable source and requested outputs and finish applicable content/data checks.\n\nIf content and structure checks pass, name the saved file and verified edits as needed, then include exactly one visual-status sentence: \"Content and structure checks passed; visual inspection was not completed.\" in English, or \"内容与结构检查通过;视觉检查未完成。\" in Chinese. Do not add a render or preview bullet, explain why inspection stopped, or describe the image or pixels. Report content or structure failures separately; never say all checks passed or claim visual verification.\n\nLibreOffice output can differ from Word, PowerPoint, or Excel. Images do not certify animation/media playback, refresh formula caches in the source workbook, or guarantee native application fidelity. Deliver requested files through `present` when available; keep the files in place. Do not deliver inspectioLine truncated
|
||||
{"type":"tool/result","data":{"turn":1,"step":1,"message":{"role":"tool","source":{"kind":"tool","callId":"call_office_skill"},"toolCallId":"call_office_skill","content":[{"type":"text","text":"<skill_content name=\"office-render\">\n<skill_resources>\nBase directory for this skill: {{cwd}}/office-skills/office-render\nResolve relative paths mentioned by this skill against the base directory before using them. Load referenced resources only as needed.\n</skill_resources>\n\n<skill_instructions>\n# Document images and visual inspection\n\nUse the installed LibreOffice Kit CLI through the shell with the absolute Node and CLI paths supplied below. In Bash, invoke `\"<node>\" \"<cli>\"`; in PowerShell, invoke `& \"<node>\" \"<cli>\"`. Prefer bundled LibreOffice unless the user requests another installation. If the Office sidecar is missing, follow [sidecar setup](../office/references/sidecar.md): ask whether the user wants to download it and install only after they agree. Do not invoke system soffice, use npx, install a replacement renderer, or build an alternative rendering pipeline to work around a failed render with an installed sidecar.\n\nBefore generating images only for inspection, establish that the current model accepts images. Otherwise finish the applicable content and structure checks and report the requested visual check as unavailable. Do not generate unreadable previews, retry image reads, or choose a second model. Requested image exports can still be delivered.\n\n## Render the saved deliverable\n\nKeep the saved deliverable in the task workspace. For requested image exports, use the requested output directory and retain the images. For inspection-only previews, create a private, uniquely named temporary parent inside that workspace and pass a child path that does not yet exist as `--output-dir`; the CLI creates that child. On POSIX, use `preview_root=$(mktemp -d \"./.dsh-office.XXXXXXXX\")` (owner-only permissions) and `--output-dir \"$preview_root/render\"`. On PowerShell, create a parent named `.dsh-office-` plus `[guid]::NewGuid().ToString('N')` under the task workspace and pass an uncreated `render` child; it inherits the workspace ACL. Quote each input and output path. Retain the parent until image inspection finishes, then remove only that parent, including after a failed render. Never use a fixed directory name or remove the workspace itself.\n\n```text\n\"<node>\" \"<cli>\" render --input <final-file> --output-dir <new-directory> --pages \"1,3,4\"\n\"<node>\" \"<cli>\" render --input <final-workbook.xlsx> --output-dir <new-directory> --sheet <exact-name> --range <A1-range>\n```\n\nFor DOCX, PPTX, or PDF, batch requested pages/slides in one call. In PowerShell, quote comma-separated `--pages` values so they remain one argument. Inspect all pages only for a requested whole-document review. For worksheets, choose the exact affected range, including chart/drawing regions; worksheet numbers are not PDF page numbers. Inspect the final saved file, reuse existing images for an unchanged source, and rerender only after requested source changes or for previously unrendered regions. Change print areas or scaling only when the user requests print layout.\n\nRead the returned JSON manifest for image paths, page counts, fragment rectangles, and missing-font diagnostics. Use the session's image-reading tool to inspect the requested images. Check clipping, alignment, headings, table widths, contrast, chart labels, and number formats as relevant to the task. A successful command or image read alone does not establish a usable preview; guessed text geometry does not establish overflow.\n\n## Failed or blank previews\n\nFor populated content, a fully transparent or uniformly blank image is a renderer failure. If a pixel check is needed, composite RGBA onto white first; raw RGB under transparent pixels can look nonblank. Check once and do not reread the same image. Stop visual checks for the task immediately after a blank result. This overrides the rerender-after-edit guidance above: do not render or read images again, even after editing or copying the source, or try another range, page, sheet, DPI, output format, diagnostic export, or print setting. Preserve the usable source and requested outputs and finish applicable content/data checks.\n\nIf content and structure checks pass, name the saved file and verified edits as needed, then include exactly one visual-status sentence: \"Content and structure checks passed; visual inspection was not completed.\" in English, or \"内容与结构检查通过;视觉检查未完成。\" in Chinese. Do not add a render or preview bullet, explain why inspection stopped, or describe the image or pixels. Report content or structure failures separately; never say all checks passed or claim visual verification.\n\nLibreOffice output can differ from Word, PowerPoint, or Excel. Images do not certify animation/media playback, refresh formula caches in the source workbook, oLine truncated
|
||||
{"type":"step/end","data":{"turn":1,"step":1}}
|
||||
{"type":"step/start","data":{"turn":1,"step":2}}
|
||||
{"type":"assistant/message","data":{"turn":1,"step":2,"message":{"role":"assistant","content":[{"type":"tool-call","id":"call_office_2","name":"skill","arguments":"{\"name\":\"office-export-pdf\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{message:7}}"},"stream":[{"type":"chunk","time":1790753571639,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}},{"type":"tool-call-chunks","time0":1790753571639,"index":0,"dt":[],"id":"call_office_2","name":"skill","args":["{\"name\":\"office-export-pdf\"}"]},{"type":"chunk","time":1790753571639,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"call_office_2","name":"skill","arguments":"{\"name\":\"office-export-pdf\"}"}}},{"type":"chunk","time":1790753571639,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}]},"surfaceOp":"append"}
|
||||
{"type":"tool/call","data":{"turn":1,"step":2,"callId":"call_office_2","name":"skill","arguments":"{\"name\":\"office-export-pdf\"}"}}
|
||||
{"type":"tool/result","data":{"turn":1,"step":2,"message":{"role":"tool","source":{"kind":"tool","callId":"call_office_2"},"toolCallId":"call_office_2","content":[{"type":"text","text":"<skill_content name=\"office-export-pdf\">\n<skill_resources>\nBase directory for this skill: {{cwd}}/office-skills/office-export-pdf\nResolve relative paths mentioned by this skill against the base directory before using them. Load referenced resources only as needed.\n</skill_resources>\n\n<skill_instructions>\n# Export an Office document to PDF\n\nUse the installed LibreOffice Kit CLI through the shell with `dsoffice`. Prefer bundled LibreOffice unless the user requests another installation. If the Office sidecar is missing, follow [sidecar setup](../office/references/sidecar.md): ask whether the user wants to download it and install only after they agree. Do not invoke system soffice, use npx, or install a replacement to work around a failed conversion with an installed sidecar.\n\nConvert the final saved Office file to a new PDF in the task workspace. Preserve the source. Quote each input and output path.\n\n```text\ndsoffice convert --input <final-office-file> --output <new-file.pdf>\n```\n\nCheck the command result, nonempty output, and `%PDF-` file signature. If a PDF reader library is already available, compare page count and extractable text with the requested content. If it is unavailable, report the extent of validation; do not generate images or install extra tools to validate a conversion. Spreadsheet PDF pages follow workbook print settings; change those settings only when requested. Conversion may differ from the native application's pagination or fonts.\n\nIf export fails, preserve the usable source and report the export limitation. Do not repeatedly convert an unchanged source or use conversion to investigate a failed preview. For PDF export alone, stop after these checks. Only a request for images or visual inspection calls for `office-render`; load it before that separate operation. Deliver the requested PDF through `present` when available, keeping the file in place.\n</skill_instructions>\n</skill_content>"}],"isError":false,"id":"{{message:8}}"}},"sourceEventSeqs":[20],"surfaceOp":"append"}
|
||||
{"type":"tool/result","data":{"turn":1,"step":2,"message":{"role":"tool","source":{"kind":"tool","callId":"call_office_2"},"toolCallId":"call_office_2","content":[{"type":"text","text":"<skill_content name=\"office-export-pdf\">\n<skill_resources>\nBase directory for this skill: {{cwd}}/office-skills/office-export-pdf\nResolve relative paths mentioned by this skill against the base directory before using them. Load referenced resources only as needed.\n</skill_resources>\n\n<skill_instructions>\n# Export an Office document to PDF\n\nUse the installed LibreOffice Kit CLI through the shell with the absolute Node and CLI paths supplied below. In Bash, invoke `\"<node>\" \"<cli>\"`; in PowerShell, invoke `& \"<node>\" \"<cli>\"`. Prefer bundled LibreOffice unless the user requests another installation. If the Office sidecar is missing, follow [sidecar setup](../office/references/sidecar.md): ask whether the user wants to download it and install only after they agree. Do not invoke system soffice, use npx, or install a replacement to work around a failed conversion with an installed sidecar.\n\nConvert the final saved Office file to a new PDF in the task workspace. Preserve the source. Quote each input and output path.\n\n```text\n\"<node>\" \"<cli>\" convert --input <final-office-file> --output <new-file.pdf>\n```\n\nCheck the command result, nonempty output, and `%PDF-` file signature. If a PDF reader library is already available, compare page count and extractable text with the requested content. If it is unavailable, report the extent of validation; do not generate images or install extra tools to validate a conversion. Spreadsheet PDF pages follow workbook print settings; change those settings only when requested. Conversion may differ from the native application's pagination or fonts.\n\nIf export fails, preserve the usable source and report the export limitation. Do not repeatedly convert an unchanged source or use conversion to investigate a failed preview. For PDF export alone, stop after these checks. Only a request for images or visual inspection calls for `office-render`; load it before that separate operation. Deliver the requested PDF through `present` when available, keeping the file in place.\n\nLibreOffice Kit is disabled in this deployment.\n</skill_instructions>\n</skill_content>"}],"isError":false,"id":"{{message:8}}"}},"sourceEventSeqs":[20],"surfaceOp":"append"}
|
||||
{"type":"step/end","data":{"turn":1,"step":2}}
|
||||
{"type":"step/start","data":{"turn":1,"step":3}}
|
||||
{"type":"assistant/message","data":{"turn":1,"step":3,"message":{"role":"assistant","content":[{"type":"tool-call","id":"call_office_3","name":"skill","arguments":"{\"name\":\"office-recalculate\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{message:9}}"},"stream":[{"type":"chunk","time":1790753571666,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}},{"type":"tool-call-chunks","time0":1790753571666,"index":0,"dt":[],"id":"call_office_3","name":"skill","args":["{\"name\":\"office-recalculate\"}"]},{"type":"chunk","time":1790753571666,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"call_office_3","name":"skill","arguments":"{\"name\":\"office-recalculate\"}"}}},{"type":"chunk","time":1790753571666,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}]},"surfaceOp":"append"}
|
||||
{"type":"tool/call","data":{"turn":1,"step":3,"callId":"call_office_3","name":"skill","arguments":"{\"name\":\"office-recalculate\"}"}}
|
||||
{"type":"tool/result","data":{"turn":1,"step":3,"message":{"role":"tool","source":{"kind":"tool","callId":"call_office_3"},"toolCallId":"call_office_3","content":[{"type":"text","text":"<skill_content name=\"office-recalculate\">\n<skill_resources>\nBase directory for this skill: {{cwd}}/office-skills/office-recalculate\nResolve relative paths mentioned by this skill against the base directory before using them. Load referenced resources only as needed.\n</skill_resources>\n\n<skill_instructions>\n# Recalculate spreadsheet formulas\n\nUse the installed LibreOffice Kit CLI through the shell with `dsoffice`. Prefer bundled LibreOffice unless the user requests another installation. If the Office sidecar is missing, follow [sidecar setup](../office/references/sidecar.md): ask whether the user wants to download it and install only after they agree. Do not invoke system soffice, use npx, or install a replacement to work around a failed recalculation with an installed sidecar.\n\nKeep the original workbook and write a new file in the task workspace. Quote each input and output path.\n\n```text\ndsoffice recalculate --input <workbook.xlsx> --output <recalculated.xlsx>\n```\n\nVerify the saved result with openpyxl, using `load_workspace_dependencies` for the Python path unless a project environment is required. Open it with both `data_only=False` and `data_only=True`. Check that formulas survive and cached results match the requested logic, expected totals, and cell types. Check required unchanged sheets, styles, and data. Recalculation does not validate business logic or guarantee Excel-specific feature compatibility.\n\nIf no supported recalculation engine is available or the command fails, preserve the workbook and explain that calculated values could not be refreshed. Do not replace requested formulas with constants or present stale/absent caches as fresh results. Deliver the verified output through `present` when available, keeping the file in place.\n</skill_instructions>\n</skill_content>"}],"isError":false,"id":"{{message:10}}"}},"sourceEventSeqs":[25],"surfaceOp":"append"}
|
||||
{"type":"tool/result","data":{"turn":1,"step":3,"message":{"role":"tool","source":{"kind":"tool","callId":"call_office_3"},"toolCallId":"call_office_3","content":[{"type":"text","text":"<skill_content name=\"office-recalculate\">\n<skill_resources>\nBase directory for this skill: {{cwd}}/office-skills/office-recalculate\nResolve relative paths mentioned by this skill against the base directory before using them. Load referenced resources only as needed.\n</skill_resources>\n\n<skill_instructions>\n# Recalculate spreadsheet formulas\n\nUse the installed LibreOffice Kit CLI through the shell with the absolute Node and CLI paths supplied below. In Bash, invoke `\"<node>\" \"<cli>\"`; in PowerShell, invoke `& \"<node>\" \"<cli>\"`. Prefer bundled LibreOffice unless the user requests another installation. If the Office sidecar is missing, follow [sidecar setup](../office/references/sidecar.md): ask whether the user wants to download it and install only after they agree. Do not invoke system soffice, use npx, or install a replacement to work around a failed recalculation with an installed sidecar.\n\nKeep the original workbook and write a new file in the task workspace. Quote each input and output path.\n\n```text\n\"<node>\" \"<cli>\" recalculate --input <workbook.xlsx> --output <recalculated.xlsx>\n```\n\nVerify the saved result with openpyxl, using `load_workspace_dependencies` for the Python path unless a project environment is required. Open it with both `data_only=False` and `data_only=True`. Check that formulas survive and cached results match the requested logic, expected totals, and cell types. Check required unchanged sheets, styles, and data. Recalculation does not validate business logic or guarantee Excel-specific feature compatibility.\n\nIf no supported recalculation engine is available or the command fails, preserve the workbook and explain that calculated values could not be refreshed. Do not replace requested formulas with constants or present stale/absent caches as fresh results. Deliver the verified output through `present` when available, keeping the file in place.\n\nLibreOffice Kit is disabled in this deployment.\n</skill_instructions>\n</skill_content>"}],"isError":false,"id":"{{message:10}}"}},"sourceEventSeqs":[25],"surfaceOp":"append"}
|
||||
{"type":"step/end","data":{"turn":1,"step":3}}
|
||||
{"type":"step/start","data":{"turn":1,"step":4}}
|
||||
{"type":"assistant/message","data":{"turn":1,"step":4,"message":{"role":"assistant","content":[{"type":"tool-call","id":"call_office_4","name":"read","arguments":"{\"file_path\":\"office-skills/office/references/sidecar.md\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{message:11}}"},"stream":[{"type":"chunk","time":1790753571694,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}},{"type":"tool-call-chunks","time0":1790753571694,"index":0,"dt":[],"id":"call_office_4","name":"read","args":["{\"file_path\":\"office-skills/office/references/sidecar.md\"}"]},{"type":"chunk","time":1790753571695,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"call_office_4","name":"read","arguments":"{\"file_path\":\"office-skills/office/references/sidecar.md\"}"}}},{"type":"chunk","time":1790753571695,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}]},"surfaceOp":"append"}
|
||||
|
||||
@@ -21,16 +21,11 @@
|
||||
disabled: false
|
||||
config:
|
||||
assetRoot: !!js process.cwd() + '/office-skills'
|
||||
node: !!js process.cwd() + '/office-node'
|
||||
cli: !!js process.cwd() + '/render-cli.cjs'
|
||||
|
||||
- id: tool-bash
|
||||
disabled: true
|
||||
|
||||
- id: tool-pwsh
|
||||
disabled: true
|
||||
|
||||
- insert:
|
||||
- id: office-commands
|
||||
name: '@deepseek-ai/dsh-skill-office/commands'
|
||||
disabled: false
|
||||
config:
|
||||
command: false
|
||||
@@ -3,6 +3,8 @@
|
||||
name: '@deepseek-ai/dsh-skill-office'
|
||||
config:
|
||||
assetRoot: !!js process.cwd() + '/office-skills'
|
||||
node: !!js process.cwd() + '/office-node'
|
||||
cli: !!js process.cwd() + '/render-cli.cjs'
|
||||
|
||||
- id: llm-deepseek
|
||||
config:
|
||||
@@ -17,9 +19,3 @@
|
||||
|
||||
- id: tool-pwsh
|
||||
disabled: true
|
||||
|
||||
- insert:
|
||||
- id: office-commands
|
||||
name: '@deepseek-ai/dsh-skill-office/commands'
|
||||
config:
|
||||
command: false
|
||||
@@ -15,11 +15,11 @@
|
||||
{"type":"session/title","data":{"title":"请先加载 office-docx、office-pptx","messageSeqs":[8],"source":{"kind":"fallback"}}}
|
||||
{"type":"assistant/message","data":{"turn":1,"step":1,"message":{"role":"assistant","content":[{"type":"reasoning","text":"The user asks me to load three skills and answer workflow questions only. Let me load them."},{"type":"tool-call","id":"call_00_2jAvhW74YFzV34o6WcLH6654","name":"skill","arguments":"{\"name\": \"office-docx\"}"},{"type":"tool-call","id":"call_01_I6imo0g6ZL4X4MdJjbZ71052","name":"skill","arguments":"{\"name\": \"office-pptx\"}"},{"type":"tool-call","id":"call_02_uzWu2TTyXsHOQJ6OzTiz1019","name":"skill","arguments":"{\"name\": \"office-xlsx\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{message:5}}"},"usage":{"inputTokens":7253,"outputTokens":118,"totalTokens":7371,"cacheReadTokens":0,"reasoningTokens":19},"stream":[{"type":"chunk","time":1791559904623,"chunk":{"type":"block-start","index":0,"blockType":"reasoning"}},{"type":"reasoning-chunks","time0":1791559904624,"index":0,"dt":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"texts":["The"," user"," asks"," me"," to"," load"," three"," skills"," and"," answer"," workflow"," questions"," only","."," Let"," me"," load"," them","."]},{"type":"chunk","time":1791559904624,"chunk":{"type":"block-start","index":1,"blockType":"tool-call"}},{"type":"tool-call-chunks","time0":1791559904624,"index":1,"dt":[0,0,0,0,0,0,0,0,0,0,0,0],"id":"call_00_2jAvhW74YFzV34o6WcLH6654","name":"skill","args":["","{","\"","name","\"",": ","\"","office","-d","oc","x","\"","}"]},{"type":"chunk","time":1791559904624,"chunk":{"type":"block-start","index":2,"blockType":"tool-call"}},{"type":"tool-call-chunks","time0":1791559904624,"index":2,"dt":[0,0,0,0,0,0,0,0,0,0,0,0],"id":"call_01_I6imo0g6ZL4X4MdJjbZ71052","name":"skill","args":["","{","\"","name","\"",": ","\"","office","-","pp","tx","\"","}"]},{"type":"chunk","time":1791559904624,"chunk":{"type":"block-start","index":3,"blockType":"tool-call"}},{"type":"tool-call-chunks","time0":1791559904624,"index":3,"dt":[0,0,0,0,0,0,0,0,0,0,0],"id":"call_02_uzWu2TTyXsHOQJ6OzTiz1019","name":"skill","args":["","{","\"","name","\"",": ","\"","office","-x","lsx","\"","}"]},{"type":"chunk","time":1791559904624,"chunk":{"type":"block-end","index":0,"block":{"type":"reasoning","text":"The user asks me to load three skills and answer workflow questions only. Let me load them."}}},{"type":"chunk","time":1791559904624,"chunk":{"type":"block-end","index":1,"block":{"type":"tool-call","id":"call_00_2jAvhW74YFzV34o6WcLH6654","name":"skill","arguments":"{\"name\": \"office-docx\"}"}}},{"type":"chunk","time":1791559904624,"chunk":{"type":"block-end","index":2,"block":{"type":"tool-call","id":"call_01_I6imo0g6ZL4X4MdJjbZ71052","name":"skill","arguments":"{\"name\": \"office-pptx\"}"}}},{"type":"chunk","time":1791559904624,"chunk":{"type":"block-end","index":3,"block":{"type":"tool-call","id":"call_02_uzWu2TTyXsHOQJ6OzTiz1019","name":"skill","arguments":"{\"name\": \"office-xlsx\"}"}}},{"type":"chunk","time":1791559904624,"chunk":{"type":"usage","usage":{"inputTokens":7253,"outputTokens":118,"totalTokens":7371,"cacheReadTokens":0,"reasoningTokens":19}}},{"type":"chunk","time":1791559904624,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}]},"surfaceOp":"append"}
|
||||
{"type":"tool/call","data":{"turn":1,"step":1,"callId":"call_00_2jAvhW74YFzV34o6WcLH6654","name":"skill","arguments":"{\"name\": \"office-docx\"}"}}
|
||||
{"type":"tool/result","data":{"turn":1,"step":1,"message":{"role":"tool","source":{"kind":"tool","callId":"call_00_2jAvhW74YFzV34o6WcLH6654"},"toolCallId":"call_00_2jAvhW74YFzV34o6WcLH6654","content":[{"type":"text","text":"<skill_content name=\"office-docx\">\n<skill_resources>\nBase directory for this skill: {{cwd}}/office-skills/office-docx\nResolve relative paths mentioned by this skill against the base directory before using them. Load referenced resources only as needed.\n</skill_resources>\n\n<skill_instructions>\n# Word documents\n\nUse `python-docx` for DOCX creation and ordinary edits. Follow an explicit user or applicable AGENTS.md requirement for a project environment or another library. Otherwise call `load_workspace_dependencies` and execute the returned Python path with its bundled libraries. Do not install packages or discover a system Python for the default workflow. If the tool is unavailable, use an already configured environment and report a missing dependency only when it prevents the requested operation.\n\nKeep source scripts, intermediate files, and final documents in the task workspace; the runtime and this skill directory are read-only resources. Use the user's requested language and preserve an existing document's design unless a redesign is requested.\n\n## Create and edit\n\nFor existing files, inspect paragraphs, runs, tables, sections, headers, and footers before changing the affected content. Save to a new file unless the user requests an in-place edit. Replacing a paragraph's `.text` destroys its run formatting; change the relevant runs when formatting must survive. Reconstructing the whole document can lose features outside python-docx's supported editing API.\n\nUse paragraph styles for headings and body text. Size tables for the section that contains them, and account for merged cells and nested tables. Chinese, Japanese, and Korean text may need an explicit `w:eastAsia` font assignment in addition to `run.font.name`; font names alone do not establish glyph availability or rendered appearance.\n\nFor a new document, use the selected Python executable:\n\n```python\nfrom docx import Document\n\ndocument = Document()\ndocument.add_heading(\"Project report\", level=0)\ndocument.add_paragraph(\"Summary\", style=\"Heading 1\")\ndocument.add_paragraph(\"The requested findings go here.\")\ndocument.save(\"report.docx\")\n```\n\npython-docx does not paginate or render documents. Do not represent ordinary replacement, colored text, or comments as tracked changes. When real revisions or unsupported OOXML features matter, preserve their package parts and verify the requested operation rather than silently discarding them.\n\n## Check and deliver\n\nRun the shared structural checker when `office-check` is available:\n\n```text\noffice-check <document.docx> --out <checks.json>\n```\n\nIt checks ZIP/XML integrity and internal relationships, and reports paragraphs, logical table dimensions, and sections. Optional `--contains TEXT` arguments assert required text. A successful structural check does not verify pagination, clipping, fonts, or visual appearance. Compare the summary and reopened document with the user's request, including unchanged content that matters to an edit.\n\nIf `office-check` is unavailable, use an already configured environment to check the ZIP/XML package and internal relationships. Report the missing environment if those checks cannot run; do not claim structural validation.\n\nDeliver after the requested content and structural checks pass. Creating a file or changing content with incidental basic formatting does not require additional operations. Load `office-render` for requested images or visual inspection and for appearance-focused styling, spacing, sizing, or alignment changes unless the user explicitly skips rendering. For PDF output load `office-export-pdf`.\n\nCall `present({\"files\":[{\"path\":\"report.docx\"}]})` with the actual final DOCX path. It exposes the current source file without copying or preserving its bytes, so keep that file in place and do not present temporary QA reports unless requested. If `present` is unavailable, provide the final workspace path using the session's supported file delivery method.\n</skill_instructions>\n</skill_content>"}],"isError":false,"id":"{{message:6}}"}},"sourceEventSeqs":[15],"surfaceOp":"append"}
|
||||
{"type":"tool/result","data":{"turn":1,"step":1,"message":{"role":"tool","source":{"kind":"tool","callId":"call_00_2jAvhW74YFzV34o6WcLH6654"},"toolCallId":"call_00_2jAvhW74YFzV34o6WcLH6654","content":[{"type":"text","text":"<skill_content name=\"office-docx\">\n<skill_resources>\nBase directory for this skill: {{cwd}}/office-skills/office-docx\nResolve relative paths mentioned by this skill against the base directory before using them. Load referenced resources only as needed.\n</skill_resources>\n\n<skill_instructions>\n# Word documents\n\nUse `python-docx` for DOCX creation and ordinary edits. Follow an explicit user or applicable AGENTS.md requirement for a project environment or another library. Otherwise call `load_workspace_dependencies` and execute the returned Python path with its bundled libraries. Do not install packages or discover a system Python for the default workflow. If the tool is unavailable, use an already configured environment and report a missing dependency only when it prevents the requested operation.\n\nKeep source scripts, intermediate files, and final documents in the task workspace; the runtime and this skill directory are read-only resources. Use the user's requested language and preserve an existing document's design unless a redesign is requested.\n\n## Create and edit\n\nFor existing files, inspect paragraphs, runs, tables, sections, headers, and footers before changing the affected content. Save to a new file unless the user requests an in-place edit. Replacing a paragraph's `.text` destroys its run formatting; change the relevant runs when formatting must survive. Reconstructing the whole document can lose features outside python-docx's supported editing API.\n\nUse paragraph styles for headings and body text. Size tables for the section that contains them, and account for merged cells and nested tables. Chinese, Japanese, and Korean text may need an explicit `w:eastAsia` font assignment in addition to `run.font.name`; font names alone do not establish glyph availability or rendered appearance.\n\nFor a new document, use the selected Python executable:\n\n```python\nfrom docx import Document\n\ndocument = Document()\ndocument.add_heading(\"Project report\", level=0)\ndocument.add_paragraph(\"Summary\", style=\"Heading 1\")\ndocument.add_paragraph(\"The requested findings go here.\")\ndocument.save(\"report.docx\")\n```\n\npython-docx does not paginate or render documents. Do not represent ordinary replacement, colored text, or comments as tracked changes. When real revisions or unsupported OOXML features matter, preserve their package parts and verify the requested operation rather than silently discarding them.\n\n## Check and deliver\n\nRun the shared structural checker when `office-check` is available:\n\nIn PowerShell, prefix the quoted Python executable with `&`. Resolve the checker path relative to this skill directory.\n\n```text\n\"<python>\" \"<skill-directory>/../scripts/check_office.py\" <document.docx> --out <checks.json>\n```\n\nIt checks ZIP/XML integrity and internal relationships, and reports paragraphs, logical table dimensions, and sections. Optional `--contains TEXT` arguments assert required text. A successful structural check does not verify pagination, clipping, fonts, or visual appearance. Compare the summary and reopened document with the user's request, including unchanged content that matters to an edit.\n\nIf the Python checker cannot run, use an already configured environment to check the ZIP/XML package and internal relationships. Report the missing environment if those checks cannot run; do not claim structural validation.\n\nDeliver after the requested content and structural checks pass. Creating a file or changing content with incidental basic formatting does not require additional operations. Load `office-render` for requested images or visual inspection. When styling, font color, spacing, sizing, or text alignment is the requested edit, load `office-render` and inspect the changed page even without a separate visual-check request, unless the user explicitly skips rendering. For PDF output load `office-export-pdf`.\n\nCall `present({\"files\":[{\"path\":\"report.docx\"}]})` with the actual final DOCX path. It exposes the current source file without copying or preserving its bytes, so keep that file in place and do not present temporary QA reports unless requested. If `present` is unavailable, provide the final workspace path using the session's supported file delivery method.\n</skill_instructions>\n</skill_content>"}],"isError":false,"id":"{{message:6}}"}},"sourceEventSeqs":[15],"surfaceOp":"append"}
|
||||
{"type":"tool/call","data":{"turn":1,"step":1,"callId":"call_01_I6imo0g6ZL4X4MdJjbZ71052","name":"skill","arguments":"{\"name\": \"office-pptx\"}"}}
|
||||
{"type":"tool/result","data":{"turn":1,"step":1,"message":{"role":"tool","source":{"kind":"tool","callId":"call_01_I6imo0g6ZL4X4MdJjbZ71052"},"toolCallId":"call_01_I6imo0g6ZL4X4MdJjbZ71052","content":[{"type":"text","text":"<skill_content name=\"office-pptx\">\n<skill_resources>\nBase directory for this skill: {{cwd}}/office-skills/office-pptx\nResolve relative paths mentioned by this skill against the base directory before using them. Load referenced resources only as needed.\n</skill_resources>\n\n<skill_instructions>\n# PowerPoint presentations\n\nFollow an explicit user or applicable AGENTS.md requirement for an environment or library. Otherwise call `load_workspace_dependencies` and use its Python executable and bundled presentation libraries. Do not install npm or pip packages or locate a system interpreter for the default workflow. If the tool is unavailable, use an already configured environment and report a missing dependency only when it prevents the requested operation.\n\nKeep scripts and output files in the task workspace. The runtime and skill directory contain shared read-only resources. Match the requested slide language and the supplied presentation's design when editing it.\n\n## Create and edit\n\nUse `python-pptx` to inspect or modify an existing presentation. Inspect slide layouts, text runs, images, tables, and charts before editing. Change only the requested content, preserve mixed text formatting, and save to a new file unless the user requests an in-place edit. Rebuilding slides can discard unsupported animation, SmartArt, or other extension content.\n\nFor a new deck, use `python-pptx` with editable text, tables, and charts. Use local image assets rather than network-dependent image URLs. Set slide dimensions, text sizes, and chart data explicitly.\n\nA minimal editable deck, run with the selected Python executable:\n\n```python\nfrom pptx import Presentation\nfrom pptx.chart.data import CategoryChartData\nfrom pptx.enum.chart import XL_CHART_TYPE\nfrom pptx.util import Inches, Pt\n\npresentation = Presentation()\npresentation.slide_width = Inches(13.333)\npresentation.slide_height = Inches(7.5)\nslide = presentation.slides.add_slide(presentation.slide_layouts[6])\ntitle = slide.shapes.add_textbox(Inches(0.6), Inches(0.4), Inches(12), Inches(0.8))\nrun = title.text_frame.paragraphs[0].add_run()\nrun.text = \"Quarterly report\"\nrun.font.size = Pt(30)\ndata = CategoryChartData()\ndata.categories = [\"Q1\", \"Q2\"]\ndata.add_series(\"Revenue\", [12, 18])\nslide.shapes.add_chart(XL_CHART_TYPE.COLUMN_CLUSTERED,\n Inches(0.8), Inches(1.6), Inches(11.5), Inches(4.8), data)\npresentation.save(\"report.pptx\")\n```\n\nUse `Inches` or `Cm` for positions and sizes and `Pt` for font sizes. To edit a generated title while retaining its other slides and charts:\n\n```python\nfrom pptx import Presentation\n\npresentation = Presentation(\"report.pptx\")\nfor shape in presentation.slides[0].shapes:\n if shape.has_text_frame and shape.text == \"Quarterly report\":\n shape.text_frame.paragraphs[0].runs[0].text = \"Quarterly results\"\npresentation.save(\"report-edited.pptx\")\n```\n\nCheck that text and images fit the slide dimensions, titles form a useful sequence, and chart labels agree with source values. Paragraph alignment does not move a text box: when a title must be centered on the slide, center both its paragraph and the text box against `presentation.slide_width`, then reopen to verify both. A native chart's embedded workbook is part of the deliverable and must contain the intended data. Library support for writing PPTX is not a rendering engine or a guarantee that every PowerPoint feature survives editing.\n\n## Check and deliver\n\nRun the shared structural checker when `office-check` is available:\n\n```text\noffice-check <presentation.pptx> --out <checks.json>\n```\n\nIt checks ZIP/XML integrity and internal relationships and reports slide count and extracted text. Use repeated `--contains TEXT` arguments for required slide text and `--count N` for a requested slide count; `--contains` excludes chart text and speaker notes. Reopen the file to check the requested edits, chart data, and notes. Structural success does not establish text fit, alignment, readable contrast, or rendering fidelity.\n\nIf `office-check` is unavailable, use an already configured environment to check the ZIP/XML package and internal relationships. Report the missing environment if those checks cannot run; do not claim structural validation.\n\nDeliver after the requested content and structural checks pass. Creating a file or changing content with incidental basic formatting does not require additional operations. Load `office-render` for requested images or visual inspection and for appearance-focused styling, spacing, sizing, or alignment changes unless the user explicitly skips rendering. For PDF output load `office-export-pdf`.\n\nCall `present({\"files\":[{\"path\":\"report-edLine truncated
|
||||
{"type":"tool/result","data":{"turn":1,"step":1,"message":{"role":"tool","source":{"kind":"tool","callId":"call_01_I6imo0g6ZL4X4MdJjbZ71052"},"toolCallId":"call_01_I6imo0g6ZL4X4MdJjbZ71052","content":[{"type":"text","text":"<skill_content name=\"office-pptx\">\n<skill_resources>\nBase directory for this skill: {{cwd}}/office-skills/office-pptx\nResolve relative paths mentioned by this skill against the base directory before using them. Load referenced resources only as needed.\n</skill_resources>\n\n<skill_instructions>\n# PowerPoint presentations\n\nFollow an explicit user or applicable AGENTS.md requirement for an environment or library. Otherwise call `load_workspace_dependencies` and use its Python executable and bundled presentation libraries. Do not install npm or pip packages or locate a system interpreter for the default workflow. If the tool is unavailable, use an already configured environment and report a missing dependency only when it prevents the requested operation.\n\nKeep scripts and output files in the task workspace. The runtime and skill directory contain shared read-only resources. Match the requested slide language and the supplied presentation's design when editing it.\n\n## Create and edit\n\nUse `python-pptx` to inspect or modify an existing presentation. Inspect slide layouts, text runs, images, tables, and charts before editing. Change only the requested content, preserve mixed text formatting, and save to a new file unless the user requests an in-place edit. Rebuilding slides can discard unsupported animation, SmartArt, or other extension content.\n\nFor a new deck, use `python-pptx` with editable text, tables, and charts. Use local image assets rather than network-dependent image URLs. Set slide dimensions, text sizes, and chart data explicitly.\n\nA minimal editable deck, run with the selected Python executable:\n\n```python\nfrom pptx import Presentation\nfrom pptx.chart.data import CategoryChartData\nfrom pptx.enum.chart import XL_CHART_TYPE\nfrom pptx.util import Inches, Pt\n\npresentation = Presentation()\npresentation.slide_width = Inches(13.333)\npresentation.slide_height = Inches(7.5)\nslide = presentation.slides.add_slide(presentation.slide_layouts[6])\ntitle = slide.shapes.add_textbox(Inches(0.6), Inches(0.4), Inches(12), Inches(0.8))\nrun = title.text_frame.paragraphs[0].add_run()\nrun.text = \"Quarterly report\"\nrun.font.size = Pt(30)\ndata = CategoryChartData()\ndata.categories = [\"Q1\", \"Q2\"]\ndata.add_series(\"Revenue\", [12, 18])\nslide.shapes.add_chart(XL_CHART_TYPE.COLUMN_CLUSTERED,\n Inches(0.8), Inches(1.6), Inches(11.5), Inches(4.8), data)\npresentation.save(\"report.pptx\")\n```\n\nUse `Inches` or `Cm` for positions and sizes and `Pt` for font sizes. To edit a generated title while retaining its other slides and charts:\n\n```python\nfrom pptx import Presentation\n\npresentation = Presentation(\"report.pptx\")\nfor shape in presentation.slides[0].shapes:\n if shape.has_text_frame and shape.text == \"Quarterly report\":\n shape.text_frame.paragraphs[0].runs[0].text = \"Quarterly results\"\npresentation.save(\"report-edited.pptx\")\n```\n\nCheck that text and images fit the slide dimensions, titles form a useful sequence, and chart labels agree with source values. Paragraph alignment does not move a text box: when a title must be centered on the slide, center both its paragraph and the text box against `presentation.slide_width`, then reopen to verify both. A native chart's embedded workbook is part of the deliverable and must contain the intended data. Library support for writing PPTX is not a rendering engine or a guarantee that every PowerPoint feature survives editing.\n\n## Check and deliver\n\nRun the shared structural checker when `office-check` is available:\n\nIn PowerShell, prefix the quoted Python executable with `&`. Resolve the checker path relative to this skill directory.\n\n```text\n\"<python>\" \"<skill-directory>/../scripts/check_office.py\" <presentation.pptx> --out <checks.json>\n```\n\nIt checks ZIP/XML integrity and internal relationships and reports slide count and extracted text. Use repeated `--contains TEXT` arguments for required slide text and `--count N` for a requested slide count; `--contains` excludes chart text and speaker notes. Reopen the file to check the requested edits, chart data, and notes. Structural success does not establish text fit, alignment, readable contrast, or rendering fidelity.\n\nIf the Python checker cannot run, use an already configured environment to check the ZIP/XML package and internal relationships. Report the missing environment if those checks cannot run; do not claim structural validation.\n\nDeliver after the requested content and structural checks pass. Creating a file or changing content with incidental basic formatting does not require additional operations. Load `office-render` for requested images or visual inspection and for appearance-focused styling, sLine truncated
|
||||
{"type":"tool/call","data":{"turn":1,"step":1,"callId":"call_02_uzWu2TTyXsHOQJ6OzTiz1019","name":"skill","arguments":"{\"name\": \"office-xlsx\"}"}}
|
||||
{"type":"tool/result","data":{"turn":1,"step":1,"message":{"role":"tool","source":{"kind":"tool","callId":"call_02_uzWu2TTyXsHOQJ6OzTiz1019"},"toolCallId":"call_02_uzWu2TTyXsHOQJ6OzTiz1019","content":[{"type":"text","text":"<skill_content name=\"office-xlsx\">\n<skill_resources>\nBase directory for this skill: {{cwd}}/office-skills/office-xlsx\nResolve relative paths mentioned by this skill against the base directory before using them. Load referenced resources only as needed.\n</skill_resources>\n\n<skill_instructions>\n# Excel workbooks\n\nFollow an explicit user or applicable AGENTS.md requirement for an environment or library. Otherwise call `load_workspace_dependencies` and run its Python executable with bundled `openpyxl` and `pandas`. Do not install packages or search for a system Python for the default workflow. If the tool is unavailable, use an already configured environment and report a missing dependency only when it prevents the requested operation.\n\nKeep scripts, working files, and outputs in the task workspace. The runtime and skill directory are shared read-only resources. Save to a new workbook unless the user requests an in-place edit.\n\n## Read and modify\n\nUse `openpyxl` for existing XLSX workbooks and targeted cell or style changes. Load with `data_only=False` when formulas must survive. Inspect sheet names, the affected cell types, formulas, styles, merged ranges, and referenced ranges before editing. Check the saved file by reopening it, including unchanged content that the request requires preserving.\n\nUse pandas for data analysis and transformations. A DataFrame is not the workbook: exporting it over an existing file can lose sheets, formulas, charts, and formatting. Write analysis results back to the intended ranges with openpyxl. `XlsxWriter` can create new workbooks, but cannot read or modify existing ones.\n\nFor a new workbook, the selected Python environment can write editable values, styles, and formulas directly:\n\n```python\nfrom openpyxl import Workbook\nfrom openpyxl.styles import Font\n\nworkbook = Workbook()\nsheet = workbook.active\nsheet.title = \"Revenue\"\nfor row in [(\"Quarter\", \"Revenue\"), (\"Q1\", 12), (\"Q2\", 18), (\"Total\", \"=SUM(B2:B3)\")]:\n sheet.append(row)\nfor cell in sheet[1]:\n cell.font = Font(bold=True)\nsheet.column_dimensions[\"A\"].width = 18\nsheet.column_dimensions[\"B\"].width = 18\nworkbook.save(\"report.xlsx\")\n```\n\nPreserve numbers, dates, booleans, and identifiers as the intended cell types; formatting is not a type conversion. For modifications, load the existing file with `openpyxl.load_workbook(\"input.xlsx\", data_only=False)`, change the requested ranges, and save a separate result. Avoid a DataFrame round trip when workbook features must survive.\n\nWriting a formula does not calculate its result. openpyxl and XlsxWriter do not evaluate formulas; `data_only=True` returns cached values that may be absent or stale. When calculated results must be refreshed, load `office-recalculate`. Do not replace requested formulas with constants or report stale values as newly calculated results.\n\nDo not rename `.xls`, `.xlsb`, encrypted files, or macro-enabled files to `.xlsx`. They need an appropriate supported operation. `keep_vba=True` can preserve VBA package content in an XLSM workflow, but does not execute or edit macros and does not guarantee every advanced workbook feature survives. Preserve the original and verify such requirements explicitly.\n\n## Check and deliver\n\nRun the shared structural checker when `office-check` is available:\n\n```text\noffice-check <workbook.xlsx> --out <checks.json>\n```\n\nIt checks ZIP/XML integrity and internal relationships, and reports sheet names, populated-cell counts, and formula counts. Repeated `--contains TEXT` arguments check string cells and sheet names, and `--count N` checks sheet count. `--contains` excludes numeric cells and does not validate formula results; verify those separately with openpyxl. The checker does not calculate formulas or judge workbook appearance. Compare relevant values, types, formulas, styles, and totals with the task's source data.\n\nIf `office-check` is unavailable, use an already configured environment to check the ZIP/XML package and internal relationships. Report the missing environment if those checks cannot run; do not claim structural validation.\n\nLoad `office-render` for requested images or visual inspection and whenever the user's primary task targets appearance, including cell fill colors, text alignment, spacing, or sizing. These appearance changes require rendering even without a separate visual-check request, unless the user explicitly skips it. New workbooks and data or formula edits do not require rendering solely because they include incidental basic formatting. In particular, bold headers and number formats accompanying data edits do not require loading `office-render` or running its commands.\n\nLoad `office-recalculate` whenLine truncated
|
||||
{"type":"tool/result","data":{"turn":1,"step":1,"message":{"role":"tool","source":{"kind":"tool","callId":"call_02_uzWu2TTyXsHOQJ6OzTiz1019"},"toolCallId":"call_02_uzWu2TTyXsHOQJ6OzTiz1019","content":[{"type":"text","text":"<skill_content name=\"office-xlsx\">\n<skill_resources>\nBase directory for this skill: {{cwd}}/office-skills/office-xlsx\nResolve relative paths mentioned by this skill against the base directory before using them. Load referenced resources only as needed.\n</skill_resources>\n\n<skill_instructions>\n# Excel workbooks\n\nFollow an explicit user or applicable AGENTS.md requirement for an environment or library. Otherwise call `load_workspace_dependencies` and run its Python executable with bundled `openpyxl` and `pandas`. Do not install packages or search for a system Python for the default workflow. If the tool is unavailable, use an already configured environment and report a missing dependency only when it prevents the requested operation.\n\nKeep scripts, working files, and outputs in the task workspace. The runtime and skill directory are shared read-only resources. Save to a new workbook unless the user requests an in-place edit.\n\n## Read and modify\n\nUse `openpyxl` for existing XLSX workbooks and targeted cell or style changes. Load with `data_only=False` when formulas must survive. Inspect sheet names, the affected cell types, formulas, styles, merged ranges, and referenced ranges before editing. Check the saved file by reopening it, including unchanged content that the request requires preserving.\n\nUse pandas for data analysis and transformations. A DataFrame is not the workbook: exporting it over an existing file can lose sheets, formulas, charts, and formatting. Write analysis results back to the intended ranges with openpyxl. `XlsxWriter` can create new workbooks, but cannot read or modify existing ones.\n\nFor a new workbook, the selected Python environment can write editable values, styles, and formulas directly:\n\n```python\nfrom openpyxl import Workbook\nfrom openpyxl.styles import Font\n\nworkbook = Workbook()\nsheet = workbook.active\nsheet.title = \"Revenue\"\nfor row in [(\"Quarter\", \"Revenue\"), (\"Q1\", 12), (\"Q2\", 18), (\"Total\", \"=SUM(B2:B3)\")]:\n sheet.append(row)\nfor cell in sheet[1]:\n cell.font = Font(bold=True)\nsheet.column_dimensions[\"A\"].width = 18\nsheet.column_dimensions[\"B\"].width = 18\nworkbook.save(\"report.xlsx\")\n```\n\nPreserve numbers, dates, booleans, and identifiers as the intended cell types; formatting is not a type conversion. For modifications, load the existing file with `openpyxl.load_workbook(\"input.xlsx\", data_only=False)`, change the requested ranges, and save a separate result. Avoid a DataFrame round trip when workbook features must survive.\n\nWriting a formula does not calculate its result. openpyxl and XlsxWriter do not evaluate formulas; `data_only=True` returns cached values that may be absent or stale. When calculated results must be refreshed, load `office-recalculate`. Do not replace requested formulas with constants or report stale values as newly calculated results.\n\nDo not rename `.xls`, `.xlsb`, encrypted files, or macro-enabled files to `.xlsx`. They need an appropriate supported operation. `keep_vba=True` can preserve VBA package content in an XLSM workflow, but does not execute or edit macros and does not guarantee every advanced workbook feature survives. Preserve the original and verify such requirements explicitly.\n\n## Check and deliver\n\nRun the shared structural checker when `office-check` is available:\n\nIn PowerShell, prefix the quoted Python executable with `&`. Resolve the checker path relative to this skill directory.\n\n```text\n\"<python>\" \"<skill-directory>/../scripts/check_office.py\" <workbook.xlsx> --out <checks.json>\n```\n\nIt checks ZIP/XML integrity and internal relationships, and reports sheet names, populated-cell counts, and formula counts. Repeated `--contains TEXT` arguments check string cells and sheet names, and `--count N` checks sheet count. `--contains` excludes numeric cells and does not validate formula results; verify those separately with openpyxl. The checker does not calculate formulas or judge workbook appearance. Compare relevant values, types, formulas, styles, and totals with the task's source data.\n\nIf the Python checker cannot run, use an already configured environment to check the ZIP/XML package and internal relationships. Report the missing environment if those checks cannot run; do not claim structural validation.\n\nLoad `office-render` for requested images or visual inspection and whenever the user's primary task targets appearance, including cell fill colors, text alignment, spacing, or sizing. These appearance changes require rendering even without a separate visual-check request, unless the user explicitly skips it. New workbooks and data or formula edits do not require rendering solely because they include incidental basic formattiLine truncated
|
||||
{"type":"step/end","data":{"turn":1,"step":1}}
|
||||
{"type":"step/start","data":{"turn":1,"step":2}}
|
||||
{"type":"assistant/message","data":{"turn":1,"step":2,"message":{"role":"assistant","content":[{"type":"reasoning","text":"The user wants workflow-only answer. Note: skill instructions mention `load_workspace_dependencies` and `render_document` and `present` — but current tool list doesn't include those. The user says \"仅根据 skill 指令及当前工具清单确认工作流\" — based on skill instructions and current tool list. Current tools: bash, create_goal, edit, exit_plan_mode, get_goal, glob, grep, interrupt_agent, job_kill, job_list, job_output, list_agents, read, read_image, send_message, skill, subagent, subagent_fork, todo_write, update_goal, web_fetch, web_search, workflow, write.\n\nSo `load_workspace_dependencies`, `render_document`, `present` are NOT available. The user premise: Desktop environment already configured with packaging Python and Office libs. So missing renderer does not block delivery — skills say if rendering unavailable, deliver and report the inspection limit. Explicitly \"do not require the user to install a renderer\".\n\nPPTX create and edit: both python-pptx (create new deck python-pptx; edit existing python-pptx).\n\nChecks before delivery: run shared checker `check_office.py` via Python executable: ZIP/XML integrity, relationships, counts; --contains, --count; reopen file. Does the checker script exist? User said don't check host env, don't run commands. So just workflow.\n\nCannot claim visual inspection: only if render_document available and read_image done; here render tool unavailable → must state visual layout was not inspected. Cannot claim Excel formula recalculation: openpyxl doesn't evaluate; checker doesn't calculate; LibreOffice preview doesn't update cached formulas; must state results require recalculation in a spreadsheet app. Must not report cached values as newly calculated.\n\nAlso note: since load_workspace_dependencies is unavailable, use the already-configured Desktop environment's Python (per skill fallback: \"If the tool is unavailable, use an already configured environment\").\n\nAnswer in Chinese, brief, workflow only. No commands run.\n\nStructure:\n1. 工作流确认前提\n2. 缺渲染工具是否阻止交付 - no\n3. PPTX 库\n4. 交付前检查\n5. 能声称什么/不能\n\nKeep concise."},{"type":"text","text":"已加载三个 skill。仅依据 skill 指令与当前会话工具清单(无 `load_workspace_dependencies`、无 `render_document`、无 `present`,仅有 bash / read / read_image / write / edit / glob / grep / subagent 等)确认工作流如下。\n\n## 1. 缺渲染工具是否阻止交付\n不阻止。三个 skill 一致规定:渲染/视觉检查是可选增强项;渲染工具不可用或失败时,应保留可用的成品、完成结构与内容检查,并简要说明\"未做视觉布局检查\",且不得要求用户去安装渲染器。\n- 因此 DOCX / PPTX / XLSX 均可正常交付。\n- 默认交付方式:`present` 不可用,改用当前会话支持的文件交付方式(提供工作区内最终文件的真实路径)。\n- 因 `load_workspace_dependencies` 不可用,按 skill 的兜底规则,使用\"已配置好的\"Desktop Python 环境,不安装依赖、不搜寻系统 Python。\n\n## 2. PPTX 新建与编辑分别用什么库\n两者都是 `python-pptx`:\n- 新建:`Presentation()`,显式设置 `slide_width/slide_height`、字号(`Pt`)、位置尺寸(`Inches`/`Cm`);表格、图表用可编辑的原生对象,图片用本地资源而非网络 URL;图表数据写进内嵌 workbook。\n- 编辑:打开已有文件后先检查 slide layouts、text runs、图片、表格、图表,只改请求的内容,保留混合格式,另存为新文件(除非用户要求原地修改);不整片重建,以免丢失动画/SmartArt 等扩展内容。\n\n## 3. 交付前的结构与内容检查\n统一先跑共享检查器:\n`<python> <skill-directory>/../scripts/check_office.py <file> --out <checks.json>`\n- 三者共通:ZIP/XML 完整性、内部关系。\n- DOCX:`--contains TEXT`;报告段落、逻辑表格尺寸、节;再重开文档核对请求内容及需保留的未改动内容。\n- PPTX:`--contains TEXT`(不含图表文本与备注)、`--count N` 核对页数;报告页数与提取文本;重开核对改动、图表数据、备注;抽查文字/图片是否超出页面尺寸、标题顺序、图表标签与源数据一致。\n- XLSX:`--contains TEXT`(仅字符串单元格与表名,不含数值)、`--count N`;报告表名、非空单元格数、公式数;另用 openpyxl 单独核对数值、类型、公式、样式与合计;含公式时用 `data_only=False` 保存。\n- 结论:结构检查通过 ≠ 排版/视觉通过,不能互相替代。\n\n## 4. 能否声称做了视觉检查\n不能。本会话没有 `render_document`,无法产出 `pages[].imagePath`,也就无法用 `read_image` 看图。交付时只能做结构+内容检查Line truncated
|
||||
|
||||
@@ -50,16 +50,11 @@
|
||||
disabled: false
|
||||
config:
|
||||
assetRoot: !!js process.cwd() + '/office-skills'
|
||||
node: !!js process.cwd() + '/office-node'
|
||||
cli: !!js process.cwd() + '/office-cli.js'
|
||||
|
||||
- id: tool-bash
|
||||
disabled: true
|
||||
|
||||
- id: tool-pwsh
|
||||
disabled: true
|
||||
|
||||
- insert:
|
||||
- id: office-commands
|
||||
name: '@deepseek-ai/dsh-skill-office/commands'
|
||||
disabled: false
|
||||
config:
|
||||
command: !!js "[process.cwd() + '/office-node', process.cwd() + '/office-cli.js']"
|
||||
@@ -3,15 +3,11 @@
|
||||
name: '@deepseek-ai/dsh-skill-office'
|
||||
config:
|
||||
assetRoot: !!js process.cwd() + '/office-skills'
|
||||
node: !!js process.cwd() + '/office-node'
|
||||
cli: !!js process.cwd() + '/office-cli.js'
|
||||
|
||||
- id: tool-bash
|
||||
disabled: true
|
||||
|
||||
- id: tool-pwsh
|
||||
disabled: true
|
||||
|
||||
- insert:
|
||||
- id: office-commands
|
||||
name: '@deepseek-ai/dsh-skill-office/commands'
|
||||
config:
|
||||
command: !!js "[process.cwd() + '/office-node', process.cwd() + '/office-cli.js']"
|
||||
@@ -15,9 +15,9 @@
|
||||
{"type":"session/title","data":{"title":"Load the office-pptx and office-xlsx","messageSeqs":[8],"source":{"kind":"fallback"}}}
|
||||
{"type":"assistant/message","data":{"turn":1,"step":1,"message":{"role":"assistant","content":[{"type":"reasoning","text":"Load the requested skill."},{"type":"tool-call","id":"call_skill_load","name":"skill","arguments":"{\"name\":\"office-pptx\"}"},{"type":"tool-call","id":"call_skill_xlsx","name":"skill","arguments":"{\"name\":\"office-xlsx\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{message:5}}"},"usage":{"inputTokens":100,"outputTokens":20,"cacheReadTokens":0,"reasoningTokens":5},"stream":[{"type":"chunk","time":1791559903809,"chunk":{"type":"block-start","index":0,"blockType":"reasoning"}},{"type":"reasoning-chunks","time0":1791559903809,"index":0,"dt":[],"texts":["Load the requested skill."]},{"type":"chunk","time":1791559903809,"chunk":{"type":"block-start","index":1,"blockType":"tool-call"}},{"type":"tool-call-chunks","time0":1791559903809,"index":1,"dt":[],"id":"call_skill_load","name":"skill","args":["{\"name\":\"office-pptx\"}"]},{"type":"chunk","time":1791559903809,"chunk":{"type":"block-end","index":0,"block":{"type":"reasoning","text":"Load the requested skill."}}},{"type":"chunk","time":1791559903809,"chunk":{"type":"block-end","index":1,"block":{"type":"tool-call","id":"call_skill_load","name":"skill","arguments":"{\"name\":\"office-pptx\"}"}}},{"type":"chunk","time":1791559903809,"chunk":{"type":"block-start","index":2,"blockType":"tool-call"}},{"type":"tool-call-chunks","time0":1791559903809,"index":2,"dt":[],"id":"call_skill_xlsx","name":"skill","args":["{\"name\":\"office-xlsx\"}"]},{"type":"chunk","time":1791559903809,"chunk":{"type":"block-end","index":2,"block":{"type":"tool-call","id":"call_skill_xlsx","name":"skill","arguments":"{\"name\":\"office-xlsx\"}"}}},{"type":"chunk","time":1791559903809,"chunk":{"type":"usage","usage":{"inputTokens":100,"outputTokens":20,"cacheReadTokens":0,"reasoningTokens":5}}},{"type":"chunk","time":1791559903809,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}]},"surfaceOp":"append"}
|
||||
{"type":"tool/call","data":{"turn":1,"step":1,"callId":"call_skill_load","name":"skill","arguments":"{\"name\":\"office-pptx\"}"}}
|
||||
{"type":"tool/result","data":{"turn":1,"step":1,"message":{"role":"tool","source":{"kind":"tool","callId":"call_skill_load"},"toolCallId":"call_skill_load","content":[{"type":"text","text":"<skill_content name=\"office-pptx\">\n<skill_resources>\nBase directory for this skill: {{cwd}}/office-skills/office-pptx\nResolve relative paths mentioned by this skill against the base directory before using them. Load referenced resources only as needed.\n</skill_resources>\n\n<skill_instructions>\n# PowerPoint presentations\n\nFollow an explicit user or applicable AGENTS.md requirement for an environment or library. Otherwise call `load_workspace_dependencies` and use its Python executable and bundled presentation libraries. Do not install npm or pip packages or locate a system interpreter for the default workflow. If the tool is unavailable, use an already configured environment and report a missing dependency only when it prevents the requested operation.\n\nKeep scripts and output files in the task workspace. The runtime and skill directory contain shared read-only resources. Match the requested slide language and the supplied presentation's design when editing it.\n\n## Create and edit\n\nUse `python-pptx` to inspect or modify an existing presentation. Inspect slide layouts, text runs, images, tables, and charts before editing. Change only the requested content, preserve mixed text formatting, and save to a new file unless the user requests an in-place edit. Rebuilding slides can discard unsupported animation, SmartArt, or other extension content.\n\nFor a new deck, use `python-pptx` with editable text, tables, and charts. Use local image assets rather than network-dependent image URLs. Set slide dimensions, text sizes, and chart data explicitly.\n\nA minimal editable deck, run with the selected Python executable:\n\n```python\nfrom pptx import Presentation\nfrom pptx.chart.data import CategoryChartData\nfrom pptx.enum.chart import XL_CHART_TYPE\nfrom pptx.util import Inches, Pt\n\npresentation = Presentation()\npresentation.slide_width = Inches(13.333)\npresentation.slide_height = Inches(7.5)\nslide = presentation.slides.add_slide(presentation.slide_layouts[6])\ntitle = slide.shapes.add_textbox(Inches(0.6), Inches(0.4), Inches(12), Inches(0.8))\nrun = title.text_frame.paragraphs[0].add_run()\nrun.text = \"Quarterly report\"\nrun.font.size = Pt(30)\ndata = CategoryChartData()\ndata.categories = [\"Q1\", \"Q2\"]\ndata.add_series(\"Revenue\", [12, 18])\nslide.shapes.add_chart(XL_CHART_TYPE.COLUMN_CLUSTERED,\n Inches(0.8), Inches(1.6), Inches(11.5), Inches(4.8), data)\npresentation.save(\"report.pptx\")\n```\n\nUse `Inches` or `Cm` for positions and sizes and `Pt` for font sizes. To edit a generated title while retaining its other slides and charts:\n\n```python\nfrom pptx import Presentation\n\npresentation = Presentation(\"report.pptx\")\nfor shape in presentation.slides[0].shapes:\n if shape.has_text_frame and shape.text == \"Quarterly report\":\n shape.text_frame.paragraphs[0].runs[0].text = \"Quarterly results\"\npresentation.save(\"report-edited.pptx\")\n```\n\nCheck that text and images fit the slide dimensions, titles form a useful sequence, and chart labels agree with source values. Paragraph alignment does not move a text box: when a title must be centered on the slide, center both its paragraph and the text box against `presentation.slide_width`, then reopen to verify both. A native chart's embedded workbook is part of the deliverable and must contain the intended data. Library support for writing PPTX is not a rendering engine or a guarantee that every PowerPoint feature survives editing.\n\n## Check and deliver\n\nRun the shared structural checker when `office-check` is available:\n\n```text\noffice-check <presentation.pptx> --out <checks.json>\n```\n\nIt checks ZIP/XML integrity and internal relationships and reports slide count and extracted text. Use repeated `--contains TEXT` arguments for required slide text and `--count N` for a requested slide count; `--contains` excludes chart text and speaker notes. Reopen the file to check the requested edits, chart data, and notes. Structural success does not establish text fit, alignment, readable contrast, or rendering fidelity.\n\nIf `office-check` is unavailable, use an already configured environment to check the ZIP/XML package and internal relationships. Report the missing environment if those checks cannot run; do not claim structural validation.\n\nDeliver after the requested content and structural checks pass. Creating a file or changing content with incidental basic formatting does not require additional operations. Load `office-render` for requested images or visual inspection and for appearance-focused styling, spacing, sizing, or alignment changes unless the user explicitly skips rendering. For PDF output load `office-export-pdf`.\n\nCall `present({\"files\":[{\"path\":\"report-edited.pptx\"}]})` with the actual fLine truncated
|
||||
{"type":"tool/result","data":{"turn":1,"step":1,"message":{"role":"tool","source":{"kind":"tool","callId":"call_skill_load"},"toolCallId":"call_skill_load","content":[{"type":"text","text":"<skill_content name=\"office-pptx\">\n<skill_resources>\nBase directory for this skill: {{cwd}}/office-skills/office-pptx\nResolve relative paths mentioned by this skill against the base directory before using them. Load referenced resources only as needed.\n</skill_resources>\n\n<skill_instructions>\n# PowerPoint presentations\n\nFollow an explicit user or applicable AGENTS.md requirement for an environment or library. Otherwise call `load_workspace_dependencies` and use its Python executable and bundled presentation libraries. Do not install npm or pip packages or locate a system interpreter for the default workflow. If the tool is unavailable, use an already configured environment and report a missing dependency only when it prevents the requested operation.\n\nKeep scripts and output files in the task workspace. The runtime and skill directory contain shared read-only resources. Match the requested slide language and the supplied presentation's design when editing it.\n\n## Create and edit\n\nUse `python-pptx` to inspect or modify an existing presentation. Inspect slide layouts, text runs, images, tables, and charts before editing. Change only the requested content, preserve mixed text formatting, and save to a new file unless the user requests an in-place edit. Rebuilding slides can discard unsupported animation, SmartArt, or other extension content.\n\nFor a new deck, use `python-pptx` with editable text, tables, and charts. Use local image assets rather than network-dependent image URLs. Set slide dimensions, text sizes, and chart data explicitly.\n\nA minimal editable deck, run with the selected Python executable:\n\n```python\nfrom pptx import Presentation\nfrom pptx.chart.data import CategoryChartData\nfrom pptx.enum.chart import XL_CHART_TYPE\nfrom pptx.util import Inches, Pt\n\npresentation = Presentation()\npresentation.slide_width = Inches(13.333)\npresentation.slide_height = Inches(7.5)\nslide = presentation.slides.add_slide(presentation.slide_layouts[6])\ntitle = slide.shapes.add_textbox(Inches(0.6), Inches(0.4), Inches(12), Inches(0.8))\nrun = title.text_frame.paragraphs[0].add_run()\nrun.text = \"Quarterly report\"\nrun.font.size = Pt(30)\ndata = CategoryChartData()\ndata.categories = [\"Q1\", \"Q2\"]\ndata.add_series(\"Revenue\", [12, 18])\nslide.shapes.add_chart(XL_CHART_TYPE.COLUMN_CLUSTERED,\n Inches(0.8), Inches(1.6), Inches(11.5), Inches(4.8), data)\npresentation.save(\"report.pptx\")\n```\n\nUse `Inches` or `Cm` for positions and sizes and `Pt` for font sizes. To edit a generated title while retaining its other slides and charts:\n\n```python\nfrom pptx import Presentation\n\npresentation = Presentation(\"report.pptx\")\nfor shape in presentation.slides[0].shapes:\n if shape.has_text_frame and shape.text == \"Quarterly report\":\n shape.text_frame.paragraphs[0].runs[0].text = \"Quarterly results\"\npresentation.save(\"report-edited.pptx\")\n```\n\nCheck that text and images fit the slide dimensions, titles form a useful sequence, and chart labels agree with source values. Paragraph alignment does not move a text box: when a title must be centered on the slide, center both its paragraph and the text box against `presentation.slide_width`, then reopen to verify both. A native chart's embedded workbook is part of the deliverable and must contain the intended data. Library support for writing PPTX is not a rendering engine or a guarantee that every PowerPoint feature survives editing.\n\n## Check and deliver\n\nRun the shared structural checker when `office-check` is available:\n\nIn PowerShell, prefix the quoted Python executable with `&`. Resolve the checker path relative to this skill directory.\n\n```text\n\"<python>\" \"<skill-directory>/../scripts/check_office.py\" <presentation.pptx> --out <checks.json>\n```\n\nIt checks ZIP/XML integrity and internal relationships and reports slide count and extracted text. Use repeated `--contains TEXT` arguments for required slide text and `--count N` for a requested slide count; `--contains` excludes chart text and speaker notes. Reopen the file to check the requested edits, chart data, and notes. Structural success does not establish text fit, alignment, readable contrast, or rendering fidelity.\n\nIf the Python checker cannot run, use an already configured environment to check the ZIP/XML package and internal relationships. Report the missing environment if those checks cannot run; do not claim structural validation.\n\nDeliver after the requested content and structural checks pass. Creating a file or changing content with incidental basic formatting does not require additional operations. Load `office-render` for requested images or visual inspection and for appearance-focused styling, spacing, sizing, or alignment changLine truncated
|
||||
{"type":"tool/call","data":{"turn":1,"step":1,"callId":"call_skill_xlsx","name":"skill","arguments":"{\"name\":\"office-xlsx\"}"}}
|
||||
{"type":"tool/result","data":{"turn":1,"step":1,"message":{"role":"tool","source":{"kind":"tool","callId":"call_skill_xlsx"},"toolCallId":"call_skill_xlsx","content":[{"type":"text","text":"<skill_content name=\"office-xlsx\">\n<skill_resources>\nBase directory for this skill: {{cwd}}/office-skills/office-xlsx\nResolve relative paths mentioned by this skill against the base directory before using them. Load referenced resources only as needed.\n</skill_resources>\n\n<skill_instructions>\n# Excel workbooks\n\nFollow an explicit user or applicable AGENTS.md requirement for an environment or library. Otherwise call `load_workspace_dependencies` and run its Python executable with bundled `openpyxl` and `pandas`. Do not install packages or search for a system Python for the default workflow. If the tool is unavailable, use an already configured environment and report a missing dependency only when it prevents the requested operation.\n\nKeep scripts, working files, and outputs in the task workspace. The runtime and skill directory are shared read-only resources. Save to a new workbook unless the user requests an in-place edit.\n\n## Read and modify\n\nUse `openpyxl` for existing XLSX workbooks and targeted cell or style changes. Load with `data_only=False` when formulas must survive. Inspect sheet names, the affected cell types, formulas, styles, merged ranges, and referenced ranges before editing. Check the saved file by reopening it, including unchanged content that the request requires preserving.\n\nUse pandas for data analysis and transformations. A DataFrame is not the workbook: exporting it over an existing file can lose sheets, formulas, charts, and formatting. Write analysis results back to the intended ranges with openpyxl. `XlsxWriter` can create new workbooks, but cannot read or modify existing ones.\n\nFor a new workbook, the selected Python environment can write editable values, styles, and formulas directly:\n\n```python\nfrom openpyxl import Workbook\nfrom openpyxl.styles import Font\n\nworkbook = Workbook()\nsheet = workbook.active\nsheet.title = \"Revenue\"\nfor row in [(\"Quarter\", \"Revenue\"), (\"Q1\", 12), (\"Q2\", 18), (\"Total\", \"=SUM(B2:B3)\")]:\n sheet.append(row)\nfor cell in sheet[1]:\n cell.font = Font(bold=True)\nsheet.column_dimensions[\"A\"].width = 18\nsheet.column_dimensions[\"B\"].width = 18\nworkbook.save(\"report.xlsx\")\n```\n\nPreserve numbers, dates, booleans, and identifiers as the intended cell types; formatting is not a type conversion. For modifications, load the existing file with `openpyxl.load_workbook(\"input.xlsx\", data_only=False)`, change the requested ranges, and save a separate result. Avoid a DataFrame round trip when workbook features must survive.\n\nWriting a formula does not calculate its result. openpyxl and XlsxWriter do not evaluate formulas; `data_only=True` returns cached values that may be absent or stale. When calculated results must be refreshed, load `office-recalculate`. Do not replace requested formulas with constants or report stale values as newly calculated results.\n\nDo not rename `.xls`, `.xlsb`, encrypted files, or macro-enabled files to `.xlsx`. They need an appropriate supported operation. `keep_vba=True` can preserve VBA package content in an XLSM workflow, but does not execute or edit macros and does not guarantee every advanced workbook feature survives. Preserve the original and verify such requirements explicitly.\n\n## Check and deliver\n\nRun the shared structural checker when `office-check` is available:\n\n```text\noffice-check <workbook.xlsx> --out <checks.json>\n```\n\nIt checks ZIP/XML integrity and internal relationships, and reports sheet names, populated-cell counts, and formula counts. Repeated `--contains TEXT` arguments check string cells and sheet names, and `--count N` checks sheet count. `--contains` excludes numeric cells and does not validate formula results; verify those separately with openpyxl. The checker does not calculate formulas or judge workbook appearance. Compare relevant values, types, formulas, styles, and totals with the task's source data.\n\nIf `office-check` is unavailable, use an already configured environment to check the ZIP/XML package and internal relationships. Report the missing environment if those checks cannot run; do not claim structural validation.\n\nLoad `office-render` for requested images or visual inspection and whenever the user's primary task targets appearance, including cell fill colors, text alignment, spacing, or sizing. These appearance changes require rendering even without a separate visual-check request, unless the user explicitly skips it. New workbooks and data or formula edits do not require rendering solely because they include incidental basic formatting. In particular, bold headers and number formats accompanying data edits do not require loading `office-render` or running its commands.\n\nLoad `office-recalculate` when refreshed calculated values are nLine truncated
|
||||
{"type":"tool/result","data":{"turn":1,"step":1,"message":{"role":"tool","source":{"kind":"tool","callId":"call_skill_xlsx"},"toolCallId":"call_skill_xlsx","content":[{"type":"text","text":"<skill_content name=\"office-xlsx\">\n<skill_resources>\nBase directory for this skill: {{cwd}}/office-skills/office-xlsx\nResolve relative paths mentioned by this skill against the base directory before using them. Load referenced resources only as needed.\n</skill_resources>\n\n<skill_instructions>\n# Excel workbooks\n\nFollow an explicit user or applicable AGENTS.md requirement for an environment or library. Otherwise call `load_workspace_dependencies` and run its Python executable with bundled `openpyxl` and `pandas`. Do not install packages or search for a system Python for the default workflow. If the tool is unavailable, use an already configured environment and report a missing dependency only when it prevents the requested operation.\n\nKeep scripts, working files, and outputs in the task workspace. The runtime and skill directory are shared read-only resources. Save to a new workbook unless the user requests an in-place edit.\n\n## Read and modify\n\nUse `openpyxl` for existing XLSX workbooks and targeted cell or style changes. Load with `data_only=False` when formulas must survive. Inspect sheet names, the affected cell types, formulas, styles, merged ranges, and referenced ranges before editing. Check the saved file by reopening it, including unchanged content that the request requires preserving.\n\nUse pandas for data analysis and transformations. A DataFrame is not the workbook: exporting it over an existing file can lose sheets, formulas, charts, and formatting. Write analysis results back to the intended ranges with openpyxl. `XlsxWriter` can create new workbooks, but cannot read or modify existing ones.\n\nFor a new workbook, the selected Python environment can write editable values, styles, and formulas directly:\n\n```python\nfrom openpyxl import Workbook\nfrom openpyxl.styles import Font\n\nworkbook = Workbook()\nsheet = workbook.active\nsheet.title = \"Revenue\"\nfor row in [(\"Quarter\", \"Revenue\"), (\"Q1\", 12), (\"Q2\", 18), (\"Total\", \"=SUM(B2:B3)\")]:\n sheet.append(row)\nfor cell in sheet[1]:\n cell.font = Font(bold=True)\nsheet.column_dimensions[\"A\"].width = 18\nsheet.column_dimensions[\"B\"].width = 18\nworkbook.save(\"report.xlsx\")\n```\n\nPreserve numbers, dates, booleans, and identifiers as the intended cell types; formatting is not a type conversion. For modifications, load the existing file with `openpyxl.load_workbook(\"input.xlsx\", data_only=False)`, change the requested ranges, and save a separate result. Avoid a DataFrame round trip when workbook features must survive.\n\nWriting a formula does not calculate its result. openpyxl and XlsxWriter do not evaluate formulas; `data_only=True` returns cached values that may be absent or stale. When calculated results must be refreshed, load `office-recalculate`. Do not replace requested formulas with constants or report stale values as newly calculated results.\n\nDo not rename `.xls`, `.xlsb`, encrypted files, or macro-enabled files to `.xlsx`. They need an appropriate supported operation. `keep_vba=True` can preserve VBA package content in an XLSM workflow, but does not execute or edit macros and does not guarantee every advanced workbook feature survives. Preserve the original and verify such requirements explicitly.\n\n## Check and deliver\n\nRun the shared structural checker when `office-check` is available:\n\nIn PowerShell, prefix the quoted Python executable with `&`. Resolve the checker path relative to this skill directory.\n\n```text\n\"<python>\" \"<skill-directory>/../scripts/check_office.py\" <workbook.xlsx> --out <checks.json>\n```\n\nIt checks ZIP/XML integrity and internal relationships, and reports sheet names, populated-cell counts, and formula counts. Repeated `--contains TEXT` arguments check string cells and sheet names, and `--count N` checks sheet count. `--contains` excludes numeric cells and does not validate formula results; verify those separately with openpyxl. The checker does not calculate formulas or judge workbook appearance. Compare relevant values, types, formulas, styles, and totals with the task's source data.\n\nIf the Python checker cannot run, use an already configured environment to check the ZIP/XML package and internal relationships. Report the missing environment if those checks cannot run; do not claim structural validation.\n\nLoad `office-render` for requested images or visual inspection and whenever the user's primary task targets appearance, including cell fill colors, text alignment, spacing, or sizing. These appearance changes require rendering even without a separate visual-check request, unless the user explicitly skips it. New workbooks and data or formula edits do not require rendering solely because they include incidental basic formatting. In particular, bold headers anLine truncated
|
||||
{"type":"step/end","data":{"turn":1,"step":1}}
|
||||
{"type":"step/start","data":{"turn":1,"step":2}}
|
||||
{"type":"assistant/message","data":{"turn":1,"step":2,"message":{"role":"assistant","content":[{"type":"reasoning","text":"The skill is loaded."},{"type":"text","text":"DONE"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{message:8}}"},"usage":{"inputTokens":180,"outputTokens":10,"cacheReadTokens":0,"reasoningTokens":4},"stream":[{"type":"chunk","time":1791559903840,"chunk":{"type":"block-start","index":0,"blockType":"reasoning"}},{"type":"reasoning-chunks","time0":1791559903840,"index":0,"dt":[],"texts":["The skill is loaded."]},{"type":"chunk","time":1791559903840,"chunk":{"type":"block-start","index":1,"blockType":"text"}},{"type":"text-chunks","time0":1791559903840,"index":1,"dt":[],"texts":["DONE"]},{"type":"chunk","time":1791559903840,"chunk":{"type":"block-end","index":0,"block":{"type":"reasoning","text":"The skill is loaded."}}},{"type":"chunk","time":1791559903840,"chunk":{"type":"block-end","index":1,"block":{"type":"text","text":"DONE"}}},{"type":"chunk","time":1791559903840,"chunk":{"type":"usage","usage":{"inputTokens":180,"outputTokens":10,"cacheReadTokens":0,"reasoningTokens":4}}},{"type":"chunk","time":1791559903840,"chunk":{"type":"finish","reason":{"kind":"stop"}}}]},"surfaceOp":"append"}
|
||||
|
||||
@@ -79,14 +79,6 @@
|
||||
name: '@deepseek-ai/dsh-skill-filesystem'
|
||||
disabled: true
|
||||
|
||||
- id: skill-office
|
||||
name: '@deepseek-ai/dsh-skill-office'
|
||||
disabled: true
|
||||
|
||||
- id: workspace-dependencies
|
||||
name: '@deepseek-ai/dsh-tool-workspace-dependencies'
|
||||
disabled: true
|
||||
|
||||
- id: tool-skill
|
||||
name: '@deepseek-ai/dsh-tool-skill'
|
||||
disabled: true
|
||||
|
||||
@@ -71,14 +71,6 @@
|
||||
name: '@deepseek-ai/dsh-skill-filesystem'
|
||||
disabled: true
|
||||
|
||||
- id: skill-office
|
||||
name: '@deepseek-ai/dsh-skill-office'
|
||||
disabled: true
|
||||
|
||||
- id: workspace-dependencies
|
||||
name: '@deepseek-ai/dsh-tool-workspace-dependencies'
|
||||
disabled: true
|
||||
|
||||
- id: tool-skill
|
||||
name: '@deepseek-ai/dsh-tool-skill'
|
||||
disabled: true
|
||||
|
||||
@@ -82,14 +82,6 @@
|
||||
name: '@deepseek-ai/dsh-skill-filesystem'
|
||||
disabled: true
|
||||
|
||||
- id: skill-office
|
||||
name: '@deepseek-ai/dsh-skill-office'
|
||||
disabled: true
|
||||
|
||||
- id: workspace-dependencies
|
||||
name: '@deepseek-ai/dsh-tool-workspace-dependencies'
|
||||
disabled: true
|
||||
|
||||
- id: tool-skill
|
||||
name: '@deepseek-ai/dsh-tool-skill'
|
||||
disabled: true
|
||||
|
||||
@@ -74,14 +74,6 @@
|
||||
name: '@deepseek-ai/dsh-skill-filesystem'
|
||||
disabled: true
|
||||
|
||||
- id: skill-office
|
||||
name: '@deepseek-ai/dsh-skill-office'
|
||||
disabled: true
|
||||
|
||||
- id: workspace-dependencies
|
||||
name: '@deepseek-ai/dsh-tool-workspace-dependencies'
|
||||
disabled: true
|
||||
|
||||
- id: tool-skill
|
||||
name: '@deepseek-ai/dsh-tool-skill'
|
||||
disabled: true
|
||||
|
||||
@@ -72,14 +72,6 @@
|
||||
name: '@deepseek-ai/dsh-skill-filesystem'
|
||||
disabled: true
|
||||
|
||||
- id: skill-office
|
||||
name: '@deepseek-ai/dsh-skill-office'
|
||||
disabled: true
|
||||
|
||||
- id: workspace-dependencies
|
||||
name: '@deepseek-ai/dsh-tool-workspace-dependencies'
|
||||
disabled: true
|
||||
|
||||
- id: tool-skill
|
||||
name: '@deepseek-ai/dsh-tool-skill'
|
||||
disabled: true
|
||||
|
||||
@@ -64,14 +64,6 @@
|
||||
name: '@deepseek-ai/dsh-skill-filesystem'
|
||||
disabled: true
|
||||
|
||||
- id: skill-office
|
||||
name: '@deepseek-ai/dsh-skill-office'
|
||||
disabled: true
|
||||
|
||||
- id: workspace-dependencies
|
||||
name: '@deepseek-ai/dsh-tool-workspace-dependencies'
|
||||
disabled: true
|
||||
|
||||
- id: tool-skill
|
||||
name: '@deepseek-ai/dsh-tool-skill'
|
||||
disabled: true
|
||||
|
||||
@@ -78,8 +78,6 @@
|
||||
"@deepseek-ai/dsh-experimental-browser-use-runtime/mcp": ["./packages/experimental/browser-use-runtime/src/mcp.ts"],
|
||||
|
||||
"@deepseek-ai/dsh-office-to-pdf/types": ["./packages/document/office-to-pdf/src/types.ts"],
|
||||
"@deepseek-ai/dsh-skill-office/commands": ["./packages/skill/skill-office/src/commands.ts"],
|
||||
"@deepseek-ai/dsh-skill-office/check": ["./packages/skill/skill-office/src/check.ts"],
|
||||
"@deepseek-ai/dsh-api-terminal-controller": ["./packages/api/terminal-controller/src/index.ts"],
|
||||
"@deepseek-ai/dsh-api-terminal-controller/types": ["./packages/api/terminal-controller/src/types.ts"],
|
||||
"@deepseek-ai/dsh-api-terminal-controller/client": ["./packages/api/terminal-controller/src/client/index.ts"],
|
||||
|
||||
Reference in new issue
Block a user