Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,9 @@ wordcraft-doc = { git = "https://github.com/ymote/wordcraft.git", rev = "7584b9b
deckcraft-engine = { git = "https://github.com/ymote/deckcraft.git", rev = "d0e57d7e25f9852179cc66be12dd6188f1c05535" }
deckcraft-format = { git = "https://github.com/ymote/deckcraft.git", rev = "d0e57d7e25f9852179cc66be12dd6188f1c05535" }
deckcraft-model = { git = "https://github.com/ymote/deckcraft.git", rev = "d0e57d7e25f9852179cc66be12dd6188f1c05535" }
deckcraft-anim = { git = "https://github.com/ymote/deckcraft.git", rev = "d0e57d7e25f9852179cc66be12dd6188f1c05535" }
deckcraft-fonts = { git = "https://github.com/ymote/deckcraft.git", rev = "d0e57d7e25f9852179cc66be12dd6188f1c05535" }
deckcraft-pptx = { git = "https://github.com/ymote/deckcraft.git", rev = "d0e57d7e25f9852179cc66be12dd6188f1c05535" }
# The cadcraft drafting engine (ADR 0013): the pinned ymote fork, one revision.
cadcraft-engine = { git = "https://github.com/ymote/cadcraft.git", rev = "59631c8d4f9ffe6c08c5c2065ea17504e53bf821" }
cadcraft-io = { git = "https://github.com/ymote/cadcraft.git", rev = "59631c8d4f9ffe6c08c5c2065ea17504e53bf821" }
Expand Down
75 changes: 75 additions & 0 deletions apps/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,81 @@ app's own agent and `tools.json`, the system toolbox, `glance.publish` and
Deck, `apps/quickdeck/bundle`, desktop only, whose own `deck.*` calls work
in its storage; its dev fixture is in apps/README.md):
`apps/deck/host-service` and `cargo test --locked -p octosense-deck-service`.
Besides the file methods (`info`, `text`, `render`, `new`, `convert`,
`run`; the system agent's two tools, `deck.info` and `deck.run`, stay as
they are), it serves Quick Deck v2's open documents to apps' own
requests, as `apps/quickdeck/design/SERVICE.md` specifies; change that
contract and the service together. `deck.open` and `deck.create` keep
the engine's session for a deck, its edits and undo history, under a
handle, on the pdf service's terms (`src/docs.rs`): a document belongs to
the caller app, its storage scope and the handle (anyone else's is
`unknown_doc:`), a caller keeps at most 8 open and the process 32, the
table is a `thread_local` on the UI thread, the listener on App Hub's
`services::on_isolate_closed` releases a closing isolate's documents and
their renders, every call sweeps for a changed storage scope, and a
caller with no isolate gets a 15-minute idle bound. Each method builds
every engine command and its parameters itself and refuses a key it does
not take, then runs them through one gate (`src/gate.rs`): the door
`deck.run` uses, with the same `REVIEWED` limits, held commands and run
ceilings, admits the whole call before any command runs
(`Door::admit_method` in `crates/engine-area`, with the method's own most
commands a call, its reason beside its constant), the ceilings on the
session hold after every command, and a refused command puts the
document back as it was. `shape.fill` and `design.background` (`file`)
run for a method only without `picture` or `path` (`UNREAD`,
`door::Unread`), so the service never has them read a file, and
`deck.run` still refuses them; `insert.picture` and `picture.change`
read a picture inside the storage only, checked first
(`src/pictures.rs`). A change method is one undo step, labelled, of at
most 100: the engine's own steps for its commands are folded through its
`History`, and a call that changes nothing adds none. `rev` and
`changed` come from the engine's copy-on-write slide pointers, compared
by content where the engine copied a slide it did not change. Text is
exact (the session's autocorrect and smart quotes are off), and
`deck.set_text` replaces only the span that changed, so the rest keeps
its formatting. Before the engine reads a byte of a file (`deck.open`,
`deck.cover`, the file methods, the agent's tools), the import guard
(`src/guard.rs`, #448) reads the zip's central directory within bounds
(10,000 entries, names of 1,024 bytes, 64 MiB an entry, 256 MiB in all,
100:1 past 100 KiB) and only in a shape the engine's own zip reader
takes the same way (one end record, ending the file; entry counts that
agree; a directory filling exactly the space it declares; nothing before
the first entry; every extra field as that reader reads it, refusing
whatever it would refuse), then has that reader, the `zip` crate
deckcraft opens decks with, read the directory too and refuses any
difference (`damaged:`), so the guard checks exactly what the engine
will read. Its verdict (a native deck by deckcraft's own marker, an
Office package by its `[Content_Types].xml` entry, which LibreOffice
writes late, past where the engine's own sniff looks) picks the
engine's reader (`engine_read`, the steps of the pinned
`open_presentation` after its sniff, compared by a test). It inflates
every entry against its declared size and
refuses a nested zip or an audio or video part (`held:`), an encrypted
`.pptx` (`protected:`) and a legacy `.ppt` or any other file it does not
know (`unsupported:`); engine-side bounds stay with #448. The one nested
zip it lets through is an Office package's embedded object under
`ppt/embeddings/` (a chart's workbook, an embedded document), which
neither the service nor deckcraft ever unzips; it still counts against
every bound, and a zip anywhere else stays `held:`. Present's order
and build steps (`deck.show`, `deck.view {step}`) come from
deckcraft-anim at the engine's pin. Caps: drawing 48–3840 px wide, 4096
a side and 16 MP, 500 shapes or slides named a call, 1,024 table cells
filled, 20,000 characters of notes, 50 MP a picture, a PDF ≤ 160 MP and
an image export ≤ 64 slides and 256 MP (checked before anything is
written), and a render cache of 16 MiB and 64 files: slide drawings in
`.cache/slides/<handle>/`, and, from `deck.cover` (a file method for
apps, no agent tool), each deck's first slide in `.cache/covers/`, at
most 32, kept across closes and named by the file's name, size and
modification time (`src/covers.rs`). Slide drawings go before covers,
each oldest first, and the whole cache is cleared before a write would
fail with `storage_full:`. Errors start with a stable code
(`src/codes.rs`). Every call first waits for a warm-up that is still
running (`src/warm.rs`): deckcraft's font database cannot load one
family on two threads at once, and a slide drawn during that race kept
the last-resort face. `src/doc_tests.rs` holds its tests, and
`cargo test --release --locked -p octosense-deck-service --lib --
--ignored timings` times a 30-slide deck's open, first drawing and
edits.
The cad engine's (cadcraft behind `cad.*`, same ADR, no bundle yet):
`apps/cad/host-service` and `cargo test --locked -p octosense-cad-service`.
The light engine's (lightcraft behind `light.*`, same ADR, no bundle yet):
Expand Down
2 changes: 1 addition & 1 deletion apps/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ them. They live in `apps/` of the [OctoSense repository](../README.md); until
speech, embedding and asynchronous video requests. Apps declare `model` and
exact host API versions; provider entitlement is checked when used. See the
[media contract and validation limits](ai-providers/host-service/MEDIA.md).
- **The `deck` host service** (`deck/host-service`, ADR 0013) is the deckcraft presentation engine behind `deck.*`: decks inspected, read as outline text, rendered to PNG, created from titles and bullets, and converted (pptx, native, outline, PDF), confined to the caller's own folder. Its app is Quick Deck (`quickdeck/bundle`), whose calls work in Quick Deck's own storage.
- **The `deck` host service** (`deck/host-service`, ADR 0013) is the deckcraft presentation engine behind `deck.*`: decks inspected, read as outline text, rendered to PNG, created from titles and bullets, and converted (pptx, native, outline, PDF), confined to the caller's own folder. Its app is Quick Deck (`quickdeck/bundle`), whose calls work in Quick Deck's own storage. For Quick Deck v2 it also keeps open documents (`apps/quickdeck/design/SERVICE.md`): `deck.open` and `deck.create` return a handle, and the methods on it (slides, objects, text, formatting, design, notes, transitions, undo and redo, drawing a slide into a render cache, Present's order and build steps, save and export) each run reviewed engine commands through the same gate as the system agent's `deck.run`, as one undo step. Every file the service opens first passes its own import guard, which refuses a zip beyond its bounds, audio and video, an encrypted `.pptx` and a legacy `.ppt` before the engine reads it.
- **The `cad` engine service** (`cad/host-service`): the cadcraft drafting engine behind `cad.*` (ADR 0013, no bundle yet) — inspect, query, measure, render and convert DXF/DWG drawings, every path inside the caller's own folder.
- **The `light` engine service** (`light/host-service`) is lightcraft's RAW
develop engine behind `light.*` (ADR 0013): EXIF/XMP metadata, the develop
Expand Down
2 changes: 1 addition & 1 deletion apps/README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ OctoSense-System-Apps 仓库(已归档)。
- **`model` 媒体 API** 使用宿主持有的供应商配置,执行有上限的图片、语音、向量和异步
视频请求。应用声明 `model` 和精确宿主 API 版本;调用时检查供应商权益。见
[媒体契约与验证范围](ai-providers/host-service/MEDIA.zh-CN.md)。
- **`deck` 宿主服务**(`deck/host-service`,ADR 0013)把 deckcraft 演示文稿引擎放在 `deck.*` 之后:检查幻灯片、提取大纲文本、渲染 PNG、按标题和要点新建演示文稿,以及格式转换(pptx、原生格式、大纲、PDF),全部限制在调用方自己的文件夹内。它的应用是 Quick Deck(`quickdeck/bundle`),其调用在 Quick Deck 自己的存储中运行。
- **`deck` 宿主服务**(`deck/host-service`,ADR 0013)把 deckcraft 演示文稿引擎放在 `deck.*` 之后:检查幻灯片、提取大纲文本、渲染 PNG、按标题和要点新建演示文稿,以及格式转换(pptx、原生格式、大纲、PDF),全部限制在调用方自己的文件夹内。它的应用是 Quick Deck(`quickdeck/bundle`),其调用在 Quick Deck 自己的存储中运行。它还为 Quick Deck v2 保持打开的文档(`apps/quickdeck/design/SERVICE.md`):`deck.open` 和 `deck.create` 返回一个句柄,作用于它的方法(幻灯片、对象、文本、格式、设计、备注、切换效果、撤销与重做、把幻灯片绘制到渲染缓存、放映的顺序与动画步骤、保存与导出)都通过与系统代理的 `deck.run` 相同的入口运行经过审查的引擎命令,每次调用合为一个撤销步骤。服务打开的每个文件都先通过它自己的导入检查:在引擎读取之前,拒绝超出界限的 zip、音频和视频、加密的 `.pptx` 以及旧版 `.ppt`。
- **`cad` 引擎服务**(`cad/host-service`):cadcraft 制图引擎,提供 `cad.*` 方法(ADR 0013,暂无 bundle)——在调用方自己的文件夹内检查、查询、测量、渲染和转换 DXF/DWG 图纸。
- **`light` 引擎服务**(`light/host-service`)把 lightcraft 的 RAW 显影引擎
放在 `light.*` 方法之后(ADR 0013):EXIF/XMP 元数据、显影控制目录、单张与
Expand Down
31 changes: 28 additions & 3 deletions apps/deck/host-service/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@
# text and PDF — all file I/O done by the service itself, confined to
# the call's area: the caller's own folder from the shell's resolver,
# else the legacy `deck/` corner of the caller's host directory.
# Headless by design: agents build and read decks with no deck UI
# existing yet.
# Quick Deck v2's open documents keep the engine's session, its edits and
# undo history between calls (apps/quickdeck/design/SERVICE.md), and every
# file is checked by the service's own import guard before the engine
# reads a byte of it.
[package]
name = "octosense-deck-service"
version = "0.1.0"
Expand All @@ -17,7 +19,9 @@ license = "Apache-2.0"
publish = false

[dependencies]
# The same App Hub rev as Mail and News: one appstore, one service registry.
# The same App Hub rev as Mail and News: one appstore, one service registry
# (and, through it, Makepad's per-isolate storage scope an open document is
# bound to).
octosense-appstore = { workspace = true }
# Where a call works: the caller's area and its write rules (ADR 0013).
octosense-engine-area = { workspace = true }
Expand All @@ -26,10 +30,31 @@ serde_json = { workspace = true }
deckcraft-engine = { workspace = true }
deckcraft-format = { workspace = true }
deckcraft-model = { workspace = true }
# Present: the show order and a slide's build steps (src/reading.rs).
deckcraft-anim = { workspace = true }
# The font families the engine can draw (deck.fonts, deck.open's
# missing_fonts).
deckcraft-fonts = { workspace = true }
# The import guard inflates every zip entry, bounded, to check it is no
# bigger than its directory says before the engine reads it (src/guard.rs).
flate2 = "1"
# The engine's own zip reader, which the import guard asks to read every
# directory it passes, so the two never read a zip differently
# (src/guard.rs `read_alike`): deckcraft's own version and features
# (its root Cargo.toml), which a test keeps the same crate in Cargo.lock.
zip = { version = "3", default-features = false, features = ["deflate"] }
# The engine's Office package reader, which the service calls itself for a
# package the import guard classified (src/lib.rs `engine_read`, the steps
# of the engine's `open_presentation`), since the engine's own sniff misses
# a package whose content-type list comes late, as LibreOffice writes them.
deckcraft-pptx = { workspace = true }

[dev-dependencies]
# Generates and checks the skill's references (tests/skill.rs).
octosense-skill-gen = { workspace = true }
# Its tool manifest is checked with App Hub's own loader (tools.json).
octosense-app-policy = { workspace = true }
# A real app isolate with a storage scope, whose closing releases the
# documents it opened (src/doc_tests.rs).
makepad-widgets = { workspace = true }
tempfile = "3"
Loading
Loading