agent-folder-workspace 0.1.2__tar.gz → 0.1.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/PKG-INFO +33 -20
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/README.md +32 -19
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/docs/architecture.md +15 -6
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/docs/formats.md +6 -0
- agent_folder_workspace-0.1.4/docs/superpowers/plans/2026-07-24-workspace-local-cache.md +300 -0
- agent_folder_workspace-0.1.4/docs/superpowers/specs/2026-07-24-workspace-local-cache-design.md +108 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/docs/windows.md +14 -7
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/pyproject.toml +1 -1
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/scripts/check_wheel.py +18 -1
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/src/agent_folder_workspace/__init__.py +1 -1
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/src/agent_folder_workspace/cache.py +35 -7
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/src/agent_folder_workspace/installer.py +7 -6
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/src/agent_folder_workspace/mcp_server.py +8 -3
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/src/agent_folder_workspace/models.py +1 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/src/agent_folder_workspace/opencode/skill/SKILL.md +3 -1
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/src/agent_folder_workspace/registry.py +11 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/src/agent_folder_workspace/schemas/WorkspaceHandleV1.schema.json +13 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/src/agent_folder_workspace/schemas/WorkspaceListV1.schema.json +13 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/src/agent_folder_workspace/workspace.py +21 -6
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/src/agent_folder_workspace/workspace_manager.py +52 -5
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/tests/test_alternative_backends.py +2 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/tests/test_contracts.py +2 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/tests/test_distribution.py +8 -2
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/tests/test_mcp_cli_installer.py +50 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/tests/test_search_cache.py +64 -1
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/tests/test_windows_reparse_security.py +2 -4
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/tests/test_workspace_manager.py +67 -3
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/.github/workflows/ci.yml +0 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/.gitignore +0 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/CONTRIBUTING.md +0 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/LICENSE +0 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/SECURITY.md +0 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/docs/acceptance.md +0 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/docs/superpowers/plans/2026-07-22-console-logging.md +0 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/docs/superpowers/plans/2026-07-23-runtime-workspace-selection.md +0 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/docs/superpowers/specs/2026-07-22-console-logging-design.md +0 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/docs/superpowers/specs/2026-07-23-runtime-workspace-selection-design.md +0 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/scripts/generate_json_schemas.py +0 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/scripts/generate_probe_fixtures.py +0 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/src/agent_folder_workspace/__main__.py +0 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/src/agent_folder_workspace/adapters/__init__.py +0 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/src/agent_folder_workspace/adapters/base.py +0 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/src/agent_folder_workspace/adapters/legacy_office.py +0 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/src/agent_folder_workspace/adapters/manager.py +0 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/src/agent_folder_workspace/adapters/odf.py +0 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/src/agent_folder_workspace/adapters/ooxml.py +0 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/src/agent_folder_workspace/adapters/pdf.py +0 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/src/agent_folder_workspace/adapters/sqlite.py +0 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/src/agent_folder_workspace/adapters/structured.py +0 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/src/agent_folder_workspace/adapters/text.py +0 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/src/agent_folder_workspace/alternative_backends.py +0 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/src/agent_folder_workspace/backend_conversion_worker.py +0 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/src/agent_folder_workspace/backend_probe_worker.py +0 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/src/agent_folder_workspace/backends.py +0 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/src/agent_folder_workspace/cfb.py +0 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/src/agent_folder_workspace/cli.py +0 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/src/agent_folder_workspace/config.py +0 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/src/agent_folder_workspace/console_logging.py +0 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/src/agent_folder_workspace/cursors.py +0 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/src/agent_folder_workspace/errors.py +0 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/src/agent_folder_workspace/ids.py +0 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/src/agent_folder_workspace/legacy.py +0 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/src/agent_folder_workspace/opencode/plugin/agent-folder-workspace.ts.tmpl +0 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/src/agent_folder_workspace/parser_workers.py +0 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/src/agent_folder_workspace/path_safety.py +0 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/src/agent_folder_workspace/probe_fixtures/probe.doc +0 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/src/agent_folder_workspace/probe_fixtures/probe.ppt +0 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/src/agent_folder_workspace/probe_fixtures/probe.xls +0 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/src/agent_folder_workspace/py.typed +0 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/src/agent_folder_workspace/schemas/CapabilityReportV1.schema.json +0 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/src/agent_folder_workspace/schemas/ContentPageV1.schema.json +0 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/src/agent_folder_workspace/schemas/DiagnosticV1.schema.json +0 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/src/agent_folder_workspace/schemas/NodePageV1.schema.json +0 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/src/agent_folder_workspace/schemas/NodeV1.schema.json +0 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/src/agent_folder_workspace/schemas/SearchPageV1.schema.json +0 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/src/agent_folder_workspace/schemas/WorkspaceCloseV1.schema.json +0 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/tests/__init__.py +0 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/tests/cfb_fixture.py +0 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/tests/test_backends.py +0 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/tests/test_cfb.py +0 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/tests/test_console_logging.py +0 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/tests/test_content_adapters.py +0 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/tests/test_legacy_adapters.py +0 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/tests/test_legacy_fuzz.py +0 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/tests/test_legacy_parsers.py +0 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/tests/test_mcp_pdf_survival.py +0 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/tests/test_odf_pdf_adapters.py +0 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/tests/test_ooxml_adapters.py +0 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/tests/test_package.py +0 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/tests/test_parser_workers.py +0 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/tests/test_structured_text.py +0 -0
- {agent_folder_workspace-0.1.2 → agent_folder_workspace-0.1.4}/tests/test_workspace_registry.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agent-folder-workspace
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.4
|
|
4
4
|
Summary: Offline, lazy, agent-oriented exploration of heterogeneous folders
|
|
5
5
|
Author-email: Dark Light <darklight@noreply.com>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -37,7 +37,7 @@ hierarchies for agents. It discovers file metadata first and opens document
|
|
|
37
37
|
bodies only when a caller expands or reads a node. The default parser path is
|
|
38
38
|
local Python code: Microsoft Office and LibreOffice are not required.
|
|
39
39
|
|
|
40
|
-
> **Project status:** `0.1.
|
|
40
|
+
> **Project status:** `0.1.4` is an alpha contract. Read-only exploration and
|
|
41
41
|
> byte access are implemented; editing, rendering, OCR, and complete semantic
|
|
42
42
|
> coverage of every supported container are not.
|
|
43
43
|
|
|
@@ -91,7 +91,7 @@ adapters, and caching:
|
|
|
91
91
|
4. Parser workers block Python socket/DNS entry points before importing risky
|
|
92
92
|
adapters and enforce one deadline across startup, queueing, IPC, and parsing.
|
|
93
93
|
5. `SizedLru` retains bounded decoded pages in memory. `ContentIndex` stores an
|
|
94
|
-
optional
|
|
94
|
+
optional SQLite search index in each workspace's owned local cache.
|
|
95
95
|
6. `WorkspaceManager` gives one FastMCP process a bounded registry of active and
|
|
96
96
|
explicitly addressed workspace roots.
|
|
97
97
|
7. The Python API, Typer CLI, and FastMCP stdio server share the same workspace
|
|
@@ -175,9 +175,15 @@ The server exposes exactly these tools:
|
|
|
175
175
|
- `probe_backends`
|
|
176
176
|
|
|
177
177
|
`open_workspace(path)` accepts an explicit absolute directory, returns an opaque,
|
|
178
|
-
process-lifetime `workspace_id`, and makes that workspace active.
|
|
179
|
-
|
|
180
|
-
|
|
178
|
+
process-lifetime `workspace_id`, and makes that workspace active. The compatible
|
|
179
|
+
extended form `open_workspace(path, cache_directory=None)` accepts an optional
|
|
180
|
+
absolute cache directory for that document basis. Without it, MCP checks for and
|
|
181
|
+
reuses an existing owned cache at
|
|
182
|
+
`path/.agent-folder-workspace-cache`; a foreign directory with that name is
|
|
183
|
+
rejected. The selected path is returned as `workspace_info.cache_directory`.
|
|
184
|
+
Existing tools accept an optional `workspace_id`; omission uses the active
|
|
185
|
+
workspace. Opening the same canonical root again reuses its ID; attempting to
|
|
186
|
+
reopen it with a different cache returns an input error. `list_workspaces`,
|
|
181
187
|
`activate_workspace`, and `close_workspace` manage the registry. One process
|
|
182
188
|
holds at most eight workspaces and never evicts one silently.
|
|
183
189
|
|
|
@@ -221,7 +227,7 @@ folderws doctor --probe-office --json --timeout-seconds 10
|
|
|
221
227
|
# Build the complete semantic content index
|
|
222
228
|
folderws index --root DIR
|
|
223
229
|
|
|
224
|
-
# Remove
|
|
230
|
+
# Remove the current document directory's owned cache, or an explicit cache
|
|
225
231
|
folderws clear-cache [--cache-dir PATH]
|
|
226
232
|
|
|
227
233
|
# Materialize the bundled, managed OpenCode skill and plugin
|
|
@@ -236,9 +242,10 @@ two ownership-marked resources atomically and always refuses foreign files,
|
|
|
236
242
|
symbolic links, and Windows reparse points. The compatibility `--force` flag
|
|
237
243
|
never bypasses ownership checks.
|
|
238
244
|
|
|
239
|
-
`clear-cache`
|
|
240
|
-
|
|
241
|
-
|
|
245
|
+
Without `--cache-dir`, `clear-cache` selects
|
|
246
|
+
`./.agent-folder-workspace-cache`. It removes only a non-link directory
|
|
247
|
+
containing the package's cache ownership marker; an arbitrary directory
|
|
248
|
+
supplied through `--cache-dir` is refused.
|
|
242
249
|
|
|
243
250
|
## Lazy loading and cache
|
|
244
251
|
|
|
@@ -270,13 +277,16 @@ Decoded `ContentPageV1` values use a byte-sized in-memory LRU capped by
|
|
|
270
277
|
best-effort basis. `index_content()` performs a full supported semantic walk
|
|
271
278
|
without retaining all decoded bodies in RAM.
|
|
272
279
|
|
|
273
|
-
The persistent index is an application-owned SQLite database below
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
+
The persistent index is an application-owned SQLite database below
|
|
281
|
+
`WORKSPACE_ROOT/.agent-folder-workspace-cache`, separated by a hash of the
|
|
282
|
+
workspace root. Existing owned caches are reused, while the cache subtree is
|
|
283
|
+
excluded from document discovery. `WorkspaceConfig.cache_directory` and MCP's
|
|
284
|
+
optional `cache_directory` argument can select another cache root explicitly.
|
|
285
|
+
The index uses FTS5 when available and a plain-table fallback otherwise.
|
|
286
|
+
`max_disk_cache_bytes` is checked after read-through chunks and completed
|
|
287
|
+
files; least-recently-used indexed files are evicted and SQLite WAL/database
|
|
288
|
+
pages are compacted. Embedded and alternative views enforce the same cache
|
|
289
|
+
budget at their own materialization boundaries.
|
|
280
290
|
Read-through index failures do not make an otherwise successful content read
|
|
281
291
|
fail. Embedded mounting, by contrast, requires a writable bounded cache. Use
|
|
282
292
|
`folderws clear-cache` to remove an explicitly selected cache tree safely.
|
|
@@ -308,8 +318,8 @@ successfully discovered file has been indexed. The affected directory node is
|
|
|
308
318
|
Optional conversion is performed by a timeout-bounded child Python process.
|
|
309
319
|
The result is verified as OOXML and mounted through the normal OOXML adapter.
|
|
310
320
|
Its cache key includes the backend, adapter version, and SHA-256 of the source,
|
|
311
|
-
and both conversion scratch and the retained result stay below the
|
|
312
|
-
|
|
321
|
+
and both conversion scratch and the retained result stay below the selected
|
|
322
|
+
workspace cache rather than `%TEMP%` or `/tmp`.
|
|
313
323
|
Microsoft automation disables macros, UI, events, external-link updates, and
|
|
314
324
|
recent-file writes where the application API exposes those controls.
|
|
315
325
|
LibreOffice uses a disposable cache-local profile, headless/safe-mode flags,
|
|
@@ -324,6 +334,9 @@ documents and does not execute document macros. Important controls include:
|
|
|
324
334
|
- roots that are symbolic links or reparse points are rejected;
|
|
325
335
|
- external roots are opened only by an explicit `open_workspace` call, are
|
|
326
336
|
bounded to eight per process, and receive process-lifetime opaque IDs;
|
|
337
|
+
- workspace caches default to an owned `.agent-folder-workspace-cache` below
|
|
338
|
+
the selected root, are excluded from source discovery, and can be overridden
|
|
339
|
+
only with an explicit absolute MCP path;
|
|
327
340
|
- child links are not followed by default, and resolved sources must remain
|
|
328
341
|
under the selected root;
|
|
329
342
|
- SQLite files are opened with `mode=ro` and `PRAGMA query_only=ON`;
|
|
@@ -410,7 +423,7 @@ The detailed coverage and per-format caveats are in
|
|
|
410
423
|
rendering. A hard parent timeout cannot guarantee cleanup of a vendor process
|
|
411
424
|
that is itself stuck below COM or LibreOffice process control.
|
|
412
425
|
- The stated 100,000-node and warm p95 performance figures are design targets,
|
|
413
|
-
not certified guarantees in `0.1.
|
|
426
|
+
not certified guarantees in `0.1.4`; CI covers correctness across Windows,
|
|
414
427
|
Linux, and macOS but does not emulate a specific Windows-x64 SSD workload.
|
|
415
428
|
|
|
416
429
|
## Development
|
|
@@ -5,7 +5,7 @@ hierarchies for agents. It discovers file metadata first and opens document
|
|
|
5
5
|
bodies only when a caller expands or reads a node. The default parser path is
|
|
6
6
|
local Python code: Microsoft Office and LibreOffice are not required.
|
|
7
7
|
|
|
8
|
-
> **Project status:** `0.1.
|
|
8
|
+
> **Project status:** `0.1.4` is an alpha contract. Read-only exploration and
|
|
9
9
|
> byte access are implemented; editing, rendering, OCR, and complete semantic
|
|
10
10
|
> coverage of every supported container are not.
|
|
11
11
|
|
|
@@ -59,7 +59,7 @@ adapters, and caching:
|
|
|
59
59
|
4. Parser workers block Python socket/DNS entry points before importing risky
|
|
60
60
|
adapters and enforce one deadline across startup, queueing, IPC, and parsing.
|
|
61
61
|
5. `SizedLru` retains bounded decoded pages in memory. `ContentIndex` stores an
|
|
62
|
-
optional
|
|
62
|
+
optional SQLite search index in each workspace's owned local cache.
|
|
63
63
|
6. `WorkspaceManager` gives one FastMCP process a bounded registry of active and
|
|
64
64
|
explicitly addressed workspace roots.
|
|
65
65
|
7. The Python API, Typer CLI, and FastMCP stdio server share the same workspace
|
|
@@ -143,9 +143,15 @@ The server exposes exactly these tools:
|
|
|
143
143
|
- `probe_backends`
|
|
144
144
|
|
|
145
145
|
`open_workspace(path)` accepts an explicit absolute directory, returns an opaque,
|
|
146
|
-
process-lifetime `workspace_id`, and makes that workspace active.
|
|
147
|
-
|
|
148
|
-
|
|
146
|
+
process-lifetime `workspace_id`, and makes that workspace active. The compatible
|
|
147
|
+
extended form `open_workspace(path, cache_directory=None)` accepts an optional
|
|
148
|
+
absolute cache directory for that document basis. Without it, MCP checks for and
|
|
149
|
+
reuses an existing owned cache at
|
|
150
|
+
`path/.agent-folder-workspace-cache`; a foreign directory with that name is
|
|
151
|
+
rejected. The selected path is returned as `workspace_info.cache_directory`.
|
|
152
|
+
Existing tools accept an optional `workspace_id`; omission uses the active
|
|
153
|
+
workspace. Opening the same canonical root again reuses its ID; attempting to
|
|
154
|
+
reopen it with a different cache returns an input error. `list_workspaces`,
|
|
149
155
|
`activate_workspace`, and `close_workspace` manage the registry. One process
|
|
150
156
|
holds at most eight workspaces and never evicts one silently.
|
|
151
157
|
|
|
@@ -189,7 +195,7 @@ folderws doctor --probe-office --json --timeout-seconds 10
|
|
|
189
195
|
# Build the complete semantic content index
|
|
190
196
|
folderws index --root DIR
|
|
191
197
|
|
|
192
|
-
# Remove
|
|
198
|
+
# Remove the current document directory's owned cache, or an explicit cache
|
|
193
199
|
folderws clear-cache [--cache-dir PATH]
|
|
194
200
|
|
|
195
201
|
# Materialize the bundled, managed OpenCode skill and plugin
|
|
@@ -204,9 +210,10 @@ two ownership-marked resources atomically and always refuses foreign files,
|
|
|
204
210
|
symbolic links, and Windows reparse points. The compatibility `--force` flag
|
|
205
211
|
never bypasses ownership checks.
|
|
206
212
|
|
|
207
|
-
`clear-cache`
|
|
208
|
-
|
|
209
|
-
|
|
213
|
+
Without `--cache-dir`, `clear-cache` selects
|
|
214
|
+
`./.agent-folder-workspace-cache`. It removes only a non-link directory
|
|
215
|
+
containing the package's cache ownership marker; an arbitrary directory
|
|
216
|
+
supplied through `--cache-dir` is refused.
|
|
210
217
|
|
|
211
218
|
## Lazy loading and cache
|
|
212
219
|
|
|
@@ -238,13 +245,16 @@ Decoded `ContentPageV1` values use a byte-sized in-memory LRU capped by
|
|
|
238
245
|
best-effort basis. `index_content()` performs a full supported semantic walk
|
|
239
246
|
without retaining all decoded bodies in RAM.
|
|
240
247
|
|
|
241
|
-
The persistent index is an application-owned SQLite database below
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
+
The persistent index is an application-owned SQLite database below
|
|
249
|
+
`WORKSPACE_ROOT/.agent-folder-workspace-cache`, separated by a hash of the
|
|
250
|
+
workspace root. Existing owned caches are reused, while the cache subtree is
|
|
251
|
+
excluded from document discovery. `WorkspaceConfig.cache_directory` and MCP's
|
|
252
|
+
optional `cache_directory` argument can select another cache root explicitly.
|
|
253
|
+
The index uses FTS5 when available and a plain-table fallback otherwise.
|
|
254
|
+
`max_disk_cache_bytes` is checked after read-through chunks and completed
|
|
255
|
+
files; least-recently-used indexed files are evicted and SQLite WAL/database
|
|
256
|
+
pages are compacted. Embedded and alternative views enforce the same cache
|
|
257
|
+
budget at their own materialization boundaries.
|
|
248
258
|
Read-through index failures do not make an otherwise successful content read
|
|
249
259
|
fail. Embedded mounting, by contrast, requires a writable bounded cache. Use
|
|
250
260
|
`folderws clear-cache` to remove an explicitly selected cache tree safely.
|
|
@@ -276,8 +286,8 @@ successfully discovered file has been indexed. The affected directory node is
|
|
|
276
286
|
Optional conversion is performed by a timeout-bounded child Python process.
|
|
277
287
|
The result is verified as OOXML and mounted through the normal OOXML adapter.
|
|
278
288
|
Its cache key includes the backend, adapter version, and SHA-256 of the source,
|
|
279
|
-
and both conversion scratch and the retained result stay below the
|
|
280
|
-
|
|
289
|
+
and both conversion scratch and the retained result stay below the selected
|
|
290
|
+
workspace cache rather than `%TEMP%` or `/tmp`.
|
|
281
291
|
Microsoft automation disables macros, UI, events, external-link updates, and
|
|
282
292
|
recent-file writes where the application API exposes those controls.
|
|
283
293
|
LibreOffice uses a disposable cache-local profile, headless/safe-mode flags,
|
|
@@ -292,6 +302,9 @@ documents and does not execute document macros. Important controls include:
|
|
|
292
302
|
- roots that are symbolic links or reparse points are rejected;
|
|
293
303
|
- external roots are opened only by an explicit `open_workspace` call, are
|
|
294
304
|
bounded to eight per process, and receive process-lifetime opaque IDs;
|
|
305
|
+
- workspace caches default to an owned `.agent-folder-workspace-cache` below
|
|
306
|
+
the selected root, are excluded from source discovery, and can be overridden
|
|
307
|
+
only with an explicit absolute MCP path;
|
|
295
308
|
- child links are not followed by default, and resolved sources must remain
|
|
296
309
|
under the selected root;
|
|
297
310
|
- SQLite files are opened with `mode=ro` and `PRAGMA query_only=ON`;
|
|
@@ -378,7 +391,7 @@ The detailed coverage and per-format caveats are in
|
|
|
378
391
|
rendering. A hard parent timeout cannot guarantee cleanup of a vendor process
|
|
379
392
|
that is itself stuck below COM or LibreOffice process control.
|
|
380
393
|
- The stated 100,000-node and warm p95 performance figures are design targets,
|
|
381
|
-
not certified guarantees in `0.1.
|
|
394
|
+
not certified guarantees in `0.1.4`; CI covers correctness across Windows,
|
|
382
395
|
Linux, and macOS but does not emulate a specific Windows-x64 SSD workload.
|
|
383
396
|
|
|
384
397
|
## Development
|
|
@@ -18,7 +18,7 @@ flowchart LR
|
|
|
18
18
|
Workspace --> Index["ContentIndex SQLite cache"]
|
|
19
19
|
Registry --> Files["Selected local root"]
|
|
20
20
|
Adapters --> Files
|
|
21
|
-
Index --> Cache["
|
|
21
|
+
Index --> Cache["Workspace-local owned cache"]
|
|
22
22
|
CLI["folderws doctor --probe-office --json"] --> Probe["Isolated backend probe worker"]
|
|
23
23
|
Probe --> Apps["Office COM or LibreOffice"]
|
|
24
24
|
```
|
|
@@ -143,9 +143,13 @@ offset, limit, and representation. It estimates serialized page bytes and
|
|
|
143
143
|
evicts least-recently-used values until `max_content_cache_bytes` is respected.
|
|
144
144
|
The cache disappears with the workspace process or refresh.
|
|
145
145
|
|
|
146
|
-
`ContentIndex` is created on first content-index/search use beneath
|
|
147
|
-
|
|
148
|
-
directory named with a truncated SHA-256 of the normalized absolute root.
|
|
146
|
+
`ContentIndex` is created on first content-index/search use beneath
|
|
147
|
+
`WORKSPACE_ROOT/.agent-folder-workspace-cache` by default. Each root gets a
|
|
148
|
+
directory named with a truncated SHA-256 of the normalized absolute root. An
|
|
149
|
+
existing owned cache is reused; a same-named directory without the ownership
|
|
150
|
+
marker is rejected, and `NodeRegistry` excludes the cache subtree from source
|
|
151
|
+
discovery. An explicit `WorkspaceConfig.cache_directory` or MCP
|
|
152
|
+
`open_workspace(..., cache_directory=...)` selects another cache root. The
|
|
149
153
|
index records relative path, modification time, size, completion, content byte
|
|
150
154
|
count, and last access. Synchronization removes entries whose source metadata
|
|
151
155
|
changed.
|
|
@@ -159,7 +163,7 @@ filesystem inventory. If any directory scan failed, the unknown denominator
|
|
|
159
163
|
forces `coverage=0` and `complete=false`; the partial directory node contains a
|
|
160
164
|
`directory_scan_failed` diagnostic.
|
|
161
165
|
|
|
162
|
-
After every read-through chunk and completed file, the physical
|
|
166
|
+
After every read-through chunk and completed file, the physical workspace
|
|
163
167
|
cache size is checked. Least-recently-used indexed files are evicted and the
|
|
164
168
|
SQLite WAL/database is checkpointed and compacted. Embedded and optional
|
|
165
169
|
alternative materializers separately check the same total cache root before
|
|
@@ -181,7 +185,7 @@ replaces a hash-derived target. The target is accepted only below a cache path
|
|
|
181
185
|
whose relevant components are not symbolic links.
|
|
182
186
|
|
|
183
187
|
`max_embedded_depth` and `max_embedded_files` bound recursive mounts per
|
|
184
|
-
workspace. `max_disk_cache_bytes` accounts for the
|
|
188
|
+
workspace. `max_disk_cache_bytes` accounts for the selected cache before a
|
|
185
189
|
new materialization and evicts inactive derived files by modification time;
|
|
186
190
|
materializations in active use are protected. The target retains only the
|
|
187
191
|
embedded suffix, while node metadata records nested adapter path, depth, and
|
|
@@ -200,6 +204,11 @@ workspace ID and otherwise route to the active root. Its capability dispatcher
|
|
|
200
204
|
resolves workspace methods at call time so reduced injected implementations
|
|
201
205
|
return a structured `capability_unavailable` error.
|
|
202
206
|
|
|
207
|
+
`open_workspace` also accepts an optional absolute `cache_directory`. Omission
|
|
208
|
+
uses and validates the fixed workspace-local cache; an explicit path belongs
|
|
209
|
+
only to the new workspace. Reopening a live root with a conflicting cache is
|
|
210
|
+
rejected rather than migrating active indexes or materialized nodes.
|
|
211
|
+
|
|
203
212
|
MCP tool boundaries translate public workspace errors to stable error codes and
|
|
204
213
|
sanitize unexpected failures behind a correlation ID. This leaves the stdio
|
|
205
214
|
transport usable for a later request. Risky PDF and container semantics remain
|
|
@@ -67,6 +67,12 @@ package/attachment roles, and mounted semantic content is not included in the
|
|
|
67
67
|
outer format's default full-index branches. Cached copies can outlive a
|
|
68
68
|
workspace instance until eviction or `folderws clear-cache`.
|
|
69
69
|
|
|
70
|
+
By default, indexes and derived copies live below
|
|
71
|
+
`WORKSPACE_ROOT/.agent-folder-workspace-cache`. The owned directory is excluded
|
|
72
|
+
from the document inventory, so split or converted artifacts do not reappear
|
|
73
|
+
as source files. `WorkspaceConfig.cache_directory` or MCP's optional absolute
|
|
74
|
+
`cache_directory` can select a different cache for one document basis.
|
|
75
|
+
|
|
70
76
|
## Resource controls
|
|
71
77
|
|
|
72
78
|
Defaults from `WorkspaceConfig` that have active enforcement paths include:
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
# Workspace-Local Cache Implementation Plan
|
|
2
|
+
|
|
3
|
+
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
|
4
|
+
|
|
5
|
+
**Goal:** Store split and derived document data in an owned cache beside each document basis by default and let MCP choose an absolute cache path per newly opened workspace.
|
|
6
|
+
|
|
7
|
+
**Architecture:** Resolve every real `FolderWorkspace` to one explicit cache root during open, defaulting to `WORKSPACE_ROOT/.agent-folder-workspace-cache`, and exclude that root from the source inventory. Extend `open_workspace` with one backward-compatible optional cache argument; validate and pass it through `WorkspaceManager`, while reporting the selected cache in `WorkspaceInfoV1`.
|
|
8
|
+
|
|
9
|
+
**Tech Stack:** Python 3.11-3.14, Pydantic v2, FastMCP, pytest, Ruff, strict Mypy, Hatchling/build, Twine.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
### Task 1: Cache path resolution and source-inventory exclusion
|
|
14
|
+
|
|
15
|
+
**Files:**
|
|
16
|
+
- Modify: `src/agent_folder_workspace/cache.py`
|
|
17
|
+
- Modify: `src/agent_folder_workspace/workspace.py`
|
|
18
|
+
- Modify: `src/agent_folder_workspace/registry.py`
|
|
19
|
+
- Modify: `src/agent_folder_workspace/installer.py`
|
|
20
|
+
- Modify: `src/agent_folder_workspace/cli.py`
|
|
21
|
+
- Modify: `tests/test_search_cache.py`
|
|
22
|
+
- Modify: `tests/test_mcp_cli_installer.py`
|
|
23
|
+
|
|
24
|
+
- [ ] **Step 1: Write failing default, reuse, collision, and exclusion tests**
|
|
25
|
+
|
|
26
|
+
Add tests that open a real workspace and assert:
|
|
27
|
+
|
|
28
|
+
```python
|
|
29
|
+
expected = root / ".agent-folder-workspace-cache"
|
|
30
|
+
assert workspace.config.cache_directory == expected
|
|
31
|
+
assert workspace.workspace_info().cache_directory == str(expected)
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Create an owned `expected` directory with `.agent-folder-workspace-cache-v1`, verify it is reused,
|
|
35
|
+
and create an unowned collision to verify `FolderWorkspace.open` raises `InputValidationError`.
|
|
36
|
+
After indexing, refresh and assert `.agent-folder-workspace-cache` is absent from the root node's
|
|
37
|
+
children. Add a CLI test proving `clear-cache` defaults to the selected root's local cache.
|
|
38
|
+
|
|
39
|
+
- [ ] **Step 2: Run the focused tests and verify RED**
|
|
40
|
+
|
|
41
|
+
Run:
|
|
42
|
+
|
|
43
|
+
```console
|
|
44
|
+
.venv/bin/python -m pytest tests/test_search_cache.py tests/test_mcp_cli_installer.py -q
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Expected: failures because the current default uses `platformdirs`, `WorkspaceInfoV1` has no cache
|
|
48
|
+
field, and the registry inventories a cache nested below the workspace.
|
|
49
|
+
|
|
50
|
+
- [ ] **Step 3: Implement deterministic local cache resolution**
|
|
51
|
+
|
|
52
|
+
In `cache.py`, add:
|
|
53
|
+
|
|
54
|
+
```python
|
|
55
|
+
DEFAULT_CACHE_DIRECTORY_NAME = ".agent-folder-workspace-cache"
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def default_cache_directory(workspace_root: Path) -> Path:
|
|
59
|
+
return workspace_root / DEFAULT_CACHE_DIRECTORY_NAME
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def validate_cache_directory(cache_root: Path, workspace_root: Path) -> Path:
|
|
63
|
+
...
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
The validator returns a normalized absolute path, rejects link/reparse components, rejects a cache
|
|
67
|
+
that equals or contains the workspace root, and requires the regular ownership marker when the
|
|
68
|
+
target already exists. Missing targets remain lazy.
|
|
69
|
+
|
|
70
|
+
Resolve `WorkspaceConfig.cache_directory` in `FolderWorkspace.open` before constructing the
|
|
71
|
+
workspace. In `NodeRegistry`, normalize the configured cache path once and skip the exact matching
|
|
72
|
+
entry during scans. Make `installer.default_cache_dir(root=Path("."))` return the same fixed local
|
|
73
|
+
path and let `clear-cache` accept that resolved default through the CLI.
|
|
74
|
+
|
|
75
|
+
- [ ] **Step 4: Run focused tests and verify GREEN**
|
|
76
|
+
|
|
77
|
+
Run:
|
|
78
|
+
|
|
79
|
+
```console
|
|
80
|
+
.venv/bin/python -m pytest tests/test_search_cache.py tests/test_mcp_cli_installer.py -q
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Expected: all selected tests pass.
|
|
84
|
+
|
|
85
|
+
- [ ] **Step 5: Commit the cache slice**
|
|
86
|
+
|
|
87
|
+
Stage the listed source and test files and commit through the repository commit policy with title
|
|
88
|
+
`Store document caches beside sources`.
|
|
89
|
+
|
|
90
|
+
### Task 2: Per-workspace MCP cache selection
|
|
91
|
+
|
|
92
|
+
**Files:**
|
|
93
|
+
- Modify: `src/agent_folder_workspace/models.py`
|
|
94
|
+
- Modify: `src/agent_folder_workspace/workspace_manager.py`
|
|
95
|
+
- Modify: `src/agent_folder_workspace/mcp_server.py`
|
|
96
|
+
- Modify: `src/agent_folder_workspace/__init__.py`
|
|
97
|
+
- Modify: `src/agent_folder_workspace/schemas/WorkspaceInfoV1.schema.json`
|
|
98
|
+
- Modify: `src/agent_folder_workspace/schemas/WorkspaceHandleV1.schema.json`
|
|
99
|
+
- Modify: `src/agent_folder_workspace/schemas/WorkspaceListV1.schema.json`
|
|
100
|
+
- Modify: `tests/test_workspace_manager.py`
|
|
101
|
+
- Modify: `tests/test_mcp_cli_installer.py`
|
|
102
|
+
- Modify: `tests/test_contracts.py`
|
|
103
|
+
|
|
104
|
+
- [ ] **Step 1: Write failing manager and MCP contract tests**
|
|
105
|
+
|
|
106
|
+
Extend the fake factory to accept an optional `WorkspaceConfig` and record it. Prove:
|
|
107
|
+
|
|
108
|
+
```python
|
|
109
|
+
opened = manager.open_workspace(documents, cache_directory=cache)
|
|
110
|
+
assert factory.configs[-1].cache_directory == cache
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Add failures for relative cache paths and for reopening one root with a different cache. Assert the
|
|
114
|
+
active workspace remains unchanged after failure. Inspect the FastMCP schema and assert
|
|
115
|
+
`cache_directory` is optional on `open_workspace`, then call it and verify the returned
|
|
116
|
+
`workspace_info.cache_directory`.
|
|
117
|
+
|
|
118
|
+
- [ ] **Step 2: Run manager and MCP tests and verify RED**
|
|
119
|
+
|
|
120
|
+
Run:
|
|
121
|
+
|
|
122
|
+
```console
|
|
123
|
+
.venv/bin/python -m pytest tests/test_workspace_manager.py tests/test_mcp_cli_installer.py -q
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Expected: failures because `open_workspace` does not accept or route `cache_directory`.
|
|
127
|
+
|
|
128
|
+
- [ ] **Step 3: Implement the optional cache argument**
|
|
129
|
+
|
|
130
|
+
Change the manager method to:
|
|
131
|
+
|
|
132
|
+
```python
|
|
133
|
+
def open_workspace(
|
|
134
|
+
self,
|
|
135
|
+
path: str | Path,
|
|
136
|
+
cache_directory: str | Path | None = None,
|
|
137
|
+
) -> WorkspaceHandleV1:
|
|
138
|
+
...
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Require an explicit cache to be absolute. When present, call the factory with
|
|
142
|
+
`WorkspaceConfig(cache_directory=requested_cache)`; otherwise retain the single-argument factory
|
|
143
|
+
call for compatibility. Compare the selected cache when the root is already open and reject
|
|
144
|
+
conflicts with `InputValidationError`.
|
|
145
|
+
|
|
146
|
+
Change the FastMCP handler to:
|
|
147
|
+
|
|
148
|
+
```python
|
|
149
|
+
@server.tool(name="open_workspace")
|
|
150
|
+
def open_workspace(path: str, cache_directory: str | None = None) -> object:
|
|
151
|
+
return _call_safely(
|
|
152
|
+
lambda: workspace_manager.open_workspace(path, cache_directory=cache_directory)
|
|
153
|
+
)
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Add `cache_directory: str | None = None` to `WorkspaceInfoV1` and populate it for real workspaces.
|
|
157
|
+
Regenerate JSON schemas with `scripts/generate_json_schemas.py`.
|
|
158
|
+
|
|
159
|
+
- [ ] **Step 4: Run focused tests and schema checks**
|
|
160
|
+
|
|
161
|
+
Run:
|
|
162
|
+
|
|
163
|
+
```console
|
|
164
|
+
.venv/bin/python -m pytest tests/test_workspace_manager.py tests/test_mcp_cli_installer.py tests/test_contracts.py -q
|
|
165
|
+
.venv/bin/python scripts/generate_json_schemas.py --check
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Expected: all selected tests pass and all committed schemas are current.
|
|
169
|
+
|
|
170
|
+
- [ ] **Step 5: Commit the MCP slice**
|
|
171
|
+
|
|
172
|
+
Stage the listed source, schema, and test files and commit through the repository commit policy
|
|
173
|
+
with title `Select cache paths per MCP workspace`.
|
|
174
|
+
|
|
175
|
+
### Task 3: Documentation, version, and package assertions
|
|
176
|
+
|
|
177
|
+
**Files:**
|
|
178
|
+
- Modify: `README.md`
|
|
179
|
+
- Modify: `docs/architecture.md`
|
|
180
|
+
- Modify: `docs/formats.md`
|
|
181
|
+
- Modify: `docs/windows.md`
|
|
182
|
+
- Modify: `src/agent_folder_workspace/opencode/skill/SKILL.md`
|
|
183
|
+
- Modify: `pyproject.toml`
|
|
184
|
+
- Modify: `src/agent_folder_workspace/__init__.py`
|
|
185
|
+
- Modify: `scripts/check_wheel.py`
|
|
186
|
+
- Modify: `tests/test_distribution.py`
|
|
187
|
+
|
|
188
|
+
- [ ] **Step 1: Write failing distribution assertions for version 0.1.3 and cache docs**
|
|
189
|
+
|
|
190
|
+
Update distribution tests to require version `0.1.3` and the terms:
|
|
191
|
+
|
|
192
|
+
```python
|
|
193
|
+
for term in (
|
|
194
|
+
".agent-folder-workspace-cache",
|
|
195
|
+
"cache_directory",
|
|
196
|
+
"existing owned cache",
|
|
197
|
+
):
|
|
198
|
+
assert term in metadata.get_payload()
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Update `scripts/check_wheel.py` to expect `0.1.3` and all currently exported schemas.
|
|
202
|
+
|
|
203
|
+
- [ ] **Step 2: Run the focused distribution tests and verify RED**
|
|
204
|
+
|
|
205
|
+
Run:
|
|
206
|
+
|
|
207
|
+
```console
|
|
208
|
+
.venv/bin/python -m pytest tests/test_distribution.py -q
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
Expected: failures because metadata, version, and documentation still describe `0.1.2` and the
|
|
212
|
+
platform cache.
|
|
213
|
+
|
|
214
|
+
- [ ] **Step 3: Update user and architecture documentation**
|
|
215
|
+
|
|
216
|
+
Document the local default, ownership-based reuse, scanner exclusion, optional absolute MCP cache
|
|
217
|
+
path, conflict behavior, and `clear-cache` default. Update the bundled OpenCode skill to pass
|
|
218
|
+
`cache_directory` only when the user explicitly supplies or approves it.
|
|
219
|
+
|
|
220
|
+
Set both package versions to `0.1.3`:
|
|
221
|
+
|
|
222
|
+
```toml
|
|
223
|
+
version = "0.1.3"
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
```python
|
|
227
|
+
__version__ = "0.1.3"
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
- [ ] **Step 4: Run the focused distribution tests and verify GREEN**
|
|
231
|
+
|
|
232
|
+
Run:
|
|
233
|
+
|
|
234
|
+
```console
|
|
235
|
+
.venv/bin/python -m pytest tests/test_distribution.py -q
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
Expected: all distribution tests pass.
|
|
239
|
+
|
|
240
|
+
- [ ] **Step 5: Commit the release slice**
|
|
241
|
+
|
|
242
|
+
Stage the documentation, version, script, and test files and commit through the repository commit
|
|
243
|
+
policy with title `Prepare agent folder workspace 0.1.3`.
|
|
244
|
+
|
|
245
|
+
### Task 4: Full verification and PyPI-only release
|
|
246
|
+
|
|
247
|
+
**Files:**
|
|
248
|
+
- Verify: entire repository
|
|
249
|
+
- Build: temporary clean output outside tracked `dist/`
|
|
250
|
+
|
|
251
|
+
- [ ] **Step 1: Run all quality gates**
|
|
252
|
+
|
|
253
|
+
Run:
|
|
254
|
+
|
|
255
|
+
```console
|
|
256
|
+
.venv/bin/python -m pytest -q
|
|
257
|
+
.venv/bin/ruff format --check .
|
|
258
|
+
.venv/bin/ruff check --no-cache .
|
|
259
|
+
.venv/bin/mypy src
|
|
260
|
+
.venv/bin/python scripts/generate_json_schemas.py --check
|
|
261
|
+
.venv/bin/python scripts/check_wheel.py --reproducible --install-smoke
|
|
262
|
+
git diff --check
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
Expected: every command exits zero.
|
|
266
|
+
|
|
267
|
+
- [ ] **Step 2: Build and inspect clean release artifacts**
|
|
268
|
+
|
|
269
|
+
Build wheel and sdist into a new temporary directory:
|
|
270
|
+
|
|
271
|
+
```console
|
|
272
|
+
SOURCE_DATE_EPOCH=315532800 .venv/bin/python -m build --no-isolation --outdir <temporary>
|
|
273
|
+
.venv/bin/python -m twine check <temporary>/*
|
|
274
|
+
.venv/bin/python scripts/check_wheel.py <temporary> --install-smoke
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
Expected: one `0.1.3` wheel and one `0.1.3` sdist, valid metadata, successful isolated import and
|
|
278
|
+
CLI/MCP smoke checks.
|
|
279
|
+
|
|
280
|
+
- [ ] **Step 3: Commit any deterministic generated correction and tag**
|
|
281
|
+
|
|
282
|
+
Require a clean worktree, create annotated tag `v0.1.3`, and verify the tag points at the release
|
|
283
|
+
commit. Do not create any GitHub release or publish to another registry.
|
|
284
|
+
|
|
285
|
+
- [ ] **Step 4: Upload only to production PyPI**
|
|
286
|
+
|
|
287
|
+
Use the environment's configured production PyPI credentials:
|
|
288
|
+
|
|
289
|
+
```console
|
|
290
|
+
.venv/bin/python -m twine upload --repository-url https://upload.pypi.org/legacy/ <temporary>/*
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
Expected: PyPI accepts both `agent_folder_workspace-0.1.3` artifacts.
|
|
294
|
+
|
|
295
|
+
- [ ] **Step 5: Verify the public release**
|
|
296
|
+
|
|
297
|
+
Query PyPI's JSON endpoint and download the published wheel into a fresh temporary directory.
|
|
298
|
+
Verify version `0.1.3`, SHA-256 against the locally uploaded wheel, package import,
|
|
299
|
+
`agent_folder_workspace.__version__`, MCP tool schema, and the local-cache behavior. Confirm no
|
|
300
|
+
TestPyPI or other publication was performed.
|