flowjet 2.1.1__tar.gz → 2.1.2__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.
- {flowjet-2.1.1 → flowjet-2.1.2}/CHANGELOG.md +8 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/PKG-INFO +2 -2
- {flowjet-2.1.1 → flowjet-2.1.2}/docs/specs/RFC-005-arcbox-tool-sandbox.md +7 -2
- {flowjet-2.1.1 → flowjet-2.1.2}/pyproject.toml +2 -2
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/core/runtime/isolation/workspace.py +109 -20
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/core/sandbox/arbox.py +36 -3
- {flowjet-2.1.1 → flowjet-2.1.2}/.gitignore +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/LICENSE +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/README.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/config/nano-local.yml +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/config/nano-sandbox-soothe.yml +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/config/nano.yml +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/deploy/README.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/docs/completion-design.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/docs/impl/IG-001-openai-compatible-server.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/docs/impl/IG-002-isolated-thread-pool-runtime.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/docs/impl/IG-003-production-isolation-hardening.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/docs/specs/RFC-001-openai-compatible-api.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/docs/specs/RFC-002-isolated-thread-pool-runtime.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/docs/specs/RFC-003-production-isolation-hardening.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/docs/specs/RFC-004-unified-package.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/docs/specs/rfc-history.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/docs/specs/rfc-index.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/docs/specs/rfc-namings.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/examples/README.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/__init__.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/__main__.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/README.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/gws-drive/SKILL.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/gws-drive-upload/SKILL.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/logo-generator-skill/.env.example +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/logo-generator-skill/README.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/logo-generator-skill/SKILL.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/logo-generator-skill/assets/background_library.html +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/logo-generator-skill/assets/showcase_template.html +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/logo-generator-skill/references/background_styles.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/logo-generator-skill/references/design_patterns.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/logo-generator-skill/references/webgl_backgrounds.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/logo-generator-skill/requirements.txt +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/logo-generator-skill/scripts/generate_showcase.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/logo-generator-skill/scripts/svg_to_png.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/SKILL.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/assets/brainstorming/spec-document-reviewer-prompt.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/assets/implementation/coding-plan-template.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/assets/implementation/impl-guide-template.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/assets/review/pr-review-template.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/assets/review/review-checklist.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/assets/specs/rfc-template.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/assets/specs/template-architecture-design.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/assets/specs/template-conceptual-design.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/assets/specs/template-impl-interface-design.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/assets/templates/template-drafts-readme.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/assets/templates/template-impl-readme.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/assets/templates/template-platonic.yml +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/assets/templates/template-rfc-history.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/assets/templates/template-rfc-index.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/assets/templates/template-rfc-namings.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/assets/templates/template-rfc-standard.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/references/BRAINSTORM/brainstorm.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/references/IMPL/impl-code.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/references/IMPL/impl-create-guide.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/references/IMPL/impl-full.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/references/IMPL/impl-update-guide.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/references/IMPL/impl-validate-guide.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/references/INIT/init-plan-modular-specs.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/references/INIT/init-recover-architecture.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/references/INIT/init-recover-conceptual.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/references/INIT/init-recover-impl-interface.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/references/INIT/init-scaffold.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/references/INIT/init-scan.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/references/REFERENCE.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/references/REVIEW/review-spec-compliance.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/references/SPECS/specs-check-compliance.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/references/SPECS/specs-check-taxonomy.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/references/SPECS/specs-generate-history.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/references/SPECS/specs-generate-index.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/references/SPECS/specs-generate-namings.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/references/SPECS/specs-refine.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/references/SPECS/specs-validate-consistency.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/references/WORKFLOW/workflow-overview.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/references/WORKFLOW/workflow-phase-1.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/references/WORKFLOW/workflow-phase-2.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/references/WORKFLOW/workflow-phase-3.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/research-bootstrap/SKILL.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/research-bootstrap/patterns/evidence-deep.json +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/research-bootstrap/patterns/evidence-first.json +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/research-bootstrap/patterns/idea-first.json +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/research-bootstrap/patterns/loop.json +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/research-bootstrap/patterns/paper-pipeline.json +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/research-bootstrap/patterns/rapid.json +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/research-bootstrap/patterns/rigor-first.json +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/research-bootstrap/patterns/stance-first.json +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/research-bootstrap/patterns/systematic-review.json +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/research-bootstrap/patterns/verify-loop.json +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/research-bootstrap/references/backends.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/research-bootstrap/references/handoff-ars-omr.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/research-bootstrap/references/handoff-omr-ars.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/research-bootstrap/references/routing.md +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/research-bootstrap/scripts/csljson_to_omr.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/research-bootstrap/scripts/papers_index_to_csljson.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/cli/__init__.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/cli/__main__.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/cli/agent.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/cli/cli.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/cli/completion/__init__.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/cli/completion/context.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/cli/completion/engine.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/cli/doctor_cmd.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/cli/doctor_fix_cmd.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/cli/progress.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/cli/serve_cmd.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/cli/setup_cmd.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/cli/shell/__init__.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/cli/shell/_fj.zsh +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/cli/shell/fj.bash +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/cli/stream.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/cli/threads.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/cli/tool_stream.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/core/__init__.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/core/_warnings.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/core/agent/__init__.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/core/agent/config.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/core/agent/factory.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/core/agent/skills.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/core/agent/wiring.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/core/agent/workspace.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/core/backend_config.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/core/bridges/base.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/core/bridges/nano/__init__.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/core/bridges/nano/adapter.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/core/bridges/nano/backend.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/core/bridges/nano/mapping.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/core/bridges/soothe/__init__.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/core/bridges/soothe/adapter.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/core/bridges/soothe/backend.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/core/events.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/core/identity.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/core/modes.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/core/protocol.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/core/runtime/__init__.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/core/runtime/direct.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/core/runtime/fake.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/core/runtime/isolation/__init__.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/core/runtime/isolation/adapter.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/core/runtime/isolation/admission.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/core/runtime/isolation/backend.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/core/runtime/isolation/errors.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/core/runtime/isolation/mode_gate.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/core/runtime/isolation/pool.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/core/runtime/isolation/request.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/core/sandbox/__init__.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/core/sandbox/resolver.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/core/sandbox/settings.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/core/streaming/__init__.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/core/streaming/presentation.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/core/streaming/tool_results.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/core/streaming/tool_stream.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/home.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/server/__init__.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/server/__main__.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/server/acp/__init__.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/server/acp/agent.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/server/acp/routes.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/server/config.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/server/http/__init__.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/server/http/app.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/server/http/auth.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/server/openai_compat/__init__.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/server/openai_compat/errors.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/server/openai_compat/projection.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/server/openai_compat/routes.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/server/openai_compat/schemas.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/server/openai_compat/service.py +0 -0
- {flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/server/openai_compat/store.py +0 -0
|
@@ -10,6 +10,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
10
10
|
|
|
11
11
|
## [Unreleased]
|
|
12
12
|
|
|
13
|
+
## [2.1.2] — 2026-10-21
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
- **Bump `soothe` to 1.2.1.** The runtime dependency floor moves from
|
|
18
|
+
`>=1.2.0` to `>=1.2.1,<2.0.0` to track the upstream fix release. No flowjet
|
|
19
|
+
API or behavior changes; the locked dependency set is otherwise unchanged.
|
|
20
|
+
|
|
13
21
|
## [2.1.1] — 2026-10-21
|
|
14
22
|
|
|
15
23
|
### Fixed
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: flowjet
|
|
3
|
-
Version: 2.1.
|
|
3
|
+
Version: 2.1.2
|
|
4
4
|
Summary: FlowJet — agent CLI (fj) and server (ACP + OpenAI-compatible HTTP) powered by Soothe
|
|
5
5
|
Project-URL: Homepage, https://github.com/caesar0301/flowjet
|
|
6
6
|
Project-URL: Repository, https://github.com/caesar0301/flowjet
|
|
@@ -22,7 +22,7 @@ Classifier: Programming Language :: Python :: 3.14
|
|
|
22
22
|
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
23
23
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
24
24
|
Requires-Python: <3.15,>=3.11
|
|
25
|
-
Requires-Dist: soothe<2.0.0,>=1.2.
|
|
25
|
+
Requires-Dist: soothe<2.0.0,>=1.2.1
|
|
26
26
|
Provides-Extra: dev
|
|
27
27
|
Requires-Dist: httpx>=0.27.0; extra == 'dev'
|
|
28
28
|
Requires-Dist: mypy>=1.0.0; extra == 'dev'
|
|
@@ -38,11 +38,16 @@ microVM duplicated soothe-nano's sandbox capability at the wrong layer.
|
|
|
38
38
|
- Per-session guest isolation: the sandbox is **per workspace**. Concurrent
|
|
39
39
|
sessions sharing one workspace share one guest (staged serially; a peer
|
|
40
40
|
mid-run skips the host push so live guest state is never clobbered).
|
|
41
|
-
- Guest-side deletion propagation: a host file deleted between sessions is
|
|
42
|
-
not removed from the guest (the pull direction is authoritative at close).
|
|
43
41
|
- Incremental (delta) transfers: staging is a full-tree push/pull with a
|
|
44
42
|
`(size, mtime_ns)` manifest skip for unchanged files.
|
|
45
43
|
|
|
44
|
+
> **Revision (2026-10-21, RFC-RD-607)**: guest-side deletion propagation is no
|
|
45
|
+
> longer a non-goal — `pull` now removes host files that were recorded in the
|
|
46
|
+
> last push manifest but disappeared from the guest tree (so agent-side
|
|
47
|
+
> deletes flow guest → host → sync checkpoint → content tree). Host files
|
|
48
|
+
> created after the push are never in the manifest and can never be deleted
|
|
49
|
+
> by this path.
|
|
50
|
+
|
|
46
51
|
## 4. Configuration
|
|
47
52
|
|
|
48
53
|
Enabled by a `sandbox:` section in the flowjet nano.yml. Flowjet owns the
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "flowjet"
|
|
7
|
-
version = "2.1.
|
|
7
|
+
version = "2.1.2"
|
|
8
8
|
description = "FlowJet — agent CLI (fj) and server (ACP + OpenAI-compatible HTTP) powered by Soothe"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { text = "MIT" }
|
|
@@ -27,7 +27,7 @@ classifiers = [
|
|
|
27
27
|
]
|
|
28
28
|
# Single-dependency CLI wheel; HTTP service deps live in the `server` extra.
|
|
29
29
|
dependencies = [
|
|
30
|
-
"soothe>=1.2.
|
|
30
|
+
"soothe>=1.2.1,<2.0.0",
|
|
31
31
|
]
|
|
32
32
|
|
|
33
33
|
[project.optional-dependencies]
|
|
@@ -7,6 +7,7 @@ import hashlib
|
|
|
7
7
|
import logging
|
|
8
8
|
import re
|
|
9
9
|
import shutil
|
|
10
|
+
from dataclasses import dataclass
|
|
10
11
|
from pathlib import Path
|
|
11
12
|
from typing import Any
|
|
12
13
|
|
|
@@ -110,6 +111,29 @@ class WorkspaceResolver:
|
|
|
110
111
|
return path == self._home
|
|
111
112
|
|
|
112
113
|
|
|
114
|
+
@dataclass
|
|
115
|
+
class _OpenWorkspaceEntry:
|
|
116
|
+
"""One open workspace — shared by all concurrent turns of the same run_id.
|
|
117
|
+
|
|
118
|
+
``active_runs`` counts turns currently mid-run on this workspace; the
|
|
119
|
+
lifecycle (``manager.close``) belongs to the last run out. ``manifest``
|
|
120
|
+
caches the recovered engine manifest so the per-turn refresh can protect
|
|
121
|
+
agent artifacts from deletion reconcile.
|
|
122
|
+
"""
|
|
123
|
+
|
|
124
|
+
ws: Any
|
|
125
|
+
active_runs: int = 0
|
|
126
|
+
manifest: Any | None = None
|
|
127
|
+
restored: bool = False
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def _manifest_artifact_paths(manifest: Any | None) -> list[str]:
|
|
131
|
+
"""Relative paths of the manifest's artifacts (reconcile protection set)."""
|
|
132
|
+
if manifest is None:
|
|
133
|
+
return []
|
|
134
|
+
return [entry.path for entry in (getattr(manifest, "artifacts", None) or [])]
|
|
135
|
+
|
|
136
|
+
|
|
113
137
|
class SyncAwareWorkspaceResolver(WorkspaceResolver):
|
|
114
138
|
"""Workspace resolver backed by soothe's fsspec workspace sync.
|
|
115
139
|
|
|
@@ -150,7 +174,7 @@ class SyncAwareWorkspaceResolver(WorkspaceResolver):
|
|
|
150
174
|
self._manager: Any | None = None
|
|
151
175
|
self._sync_backend: Any | None = None
|
|
152
176
|
self._restore_cas: Any | None = None
|
|
153
|
-
self._open_workspaces: dict[str,
|
|
177
|
+
self._open_workspaces: dict[str, _OpenWorkspaceEntry] = {}
|
|
154
178
|
|
|
155
179
|
@property
|
|
156
180
|
def is_sync_enabled(self) -> bool:
|
|
@@ -263,7 +287,17 @@ class SyncAwareWorkspaceResolver(WorkspaceResolver):
|
|
|
263
287
|
return path
|
|
264
288
|
|
|
265
289
|
async def open_session(self, session: str, workspace: Path) -> None:
|
|
266
|
-
"""
|
|
290
|
+
"""Refresh the workspace from the object store + start dirty tracking.
|
|
291
|
+
|
|
292
|
+
RFC-RD-607 §4.3: the sync boundary is the agent turn (one pair of
|
|
293
|
+
open/close hooks per prompt). Every turn unconditionally materializes
|
|
294
|
+
the content tree — including the reuse path where a peer session's
|
|
295
|
+
turn already holds the workspace open (sha-skip keeps repeat turns
|
|
296
|
+
cheap). Deletion reconcile runs only while this turn is the sole
|
|
297
|
+
active run on the workspace: deleting files under a peer's feet is
|
|
298
|
+
worse than a delayed delete, so peer-occupied turns skip it (logged).
|
|
299
|
+
Prior agent artifacts are restored once, on the opening turn.
|
|
300
|
+
"""
|
|
267
301
|
manager = self._ensure_manager()
|
|
268
302
|
if manager is None:
|
|
269
303
|
return
|
|
@@ -273,18 +307,39 @@ class SyncAwareWorkspaceResolver(WorkspaceResolver):
|
|
|
273
307
|
# for perfect consistency across resolve/open/close.
|
|
274
308
|
run_id = workspace.name
|
|
275
309
|
|
|
276
|
-
|
|
277
|
-
if
|
|
278
|
-
|
|
310
|
+
entry = self._open_workspaces.get(run_id)
|
|
311
|
+
if entry is None:
|
|
312
|
+
ws = await manager.open(run_id)
|
|
313
|
+
entry = _OpenWorkspaceEntry(ws=ws)
|
|
314
|
+
self._open_workspaces[run_id] = entry
|
|
315
|
+
else:
|
|
316
|
+
ws = entry.ws
|
|
317
|
+
entry.active_runs += 1
|
|
318
|
+
|
|
319
|
+
if entry.manifest is None:
|
|
320
|
+
try:
|
|
321
|
+
entry.manifest = await self._recover_manifest(ws)
|
|
322
|
+
except Exception:
|
|
323
|
+
logger.warning("Manifest recovery failed for run %s", run_id, exc_info=True)
|
|
279
324
|
|
|
280
|
-
ws = await manager.open(run_id)
|
|
281
325
|
# Dual-source sync, read path: materialize the content root (e.g.
|
|
282
326
|
# triarch workspace materials) into the workspace BEFORE replaying
|
|
283
327
|
# checkpoint state, so the agent sees both its prior outputs and the
|
|
284
|
-
# latest backend-uploaded files.
|
|
328
|
+
# latest backend-uploaded files. The dirty tracker only watches
|
|
329
|
+
# input/working/output + root files, so content-tree writes never
|
|
330
|
+
# pollute the dirty set.
|
|
285
331
|
if hasattr(ws, "materialize_content"):
|
|
286
332
|
try:
|
|
287
|
-
|
|
333
|
+
if self._supports_content_reconcile(ws):
|
|
334
|
+
await ws.materialize_content(
|
|
335
|
+
protected=_manifest_artifact_paths(entry.manifest),
|
|
336
|
+
reconcile=entry.active_runs == 1,
|
|
337
|
+
)
|
|
338
|
+
else:
|
|
339
|
+
# soothe < 2.0: no protected/reconcile kwargs — degrade to
|
|
340
|
+
# a plain materialize (no reconcile; deletes stay until
|
|
341
|
+
# the soothe 2.0.0 release train lands).
|
|
342
|
+
await ws.materialize_content()
|
|
288
343
|
except Exception:
|
|
289
344
|
logger.warning(
|
|
290
345
|
"Content materialization failed for run %s; continuing with "
|
|
@@ -292,19 +347,43 @@ class SyncAwareWorkspaceResolver(WorkspaceResolver):
|
|
|
292
347
|
run_id,
|
|
293
348
|
exc_info=True,
|
|
294
349
|
)
|
|
295
|
-
|
|
296
|
-
|
|
350
|
+
|
|
351
|
+
if entry.manifest is not None and not entry.restored:
|
|
352
|
+
await self._restore_prior_state(ws, entry.manifest)
|
|
353
|
+
entry.restored = True
|
|
297
354
|
|
|
298
355
|
# Start dirty tracking + background uploader for incremental persistence.
|
|
299
356
|
await ws.start_tracking()
|
|
300
357
|
logger.info("Opened sync workspace for session %s at %s", session, workspace)
|
|
301
358
|
|
|
302
|
-
|
|
303
|
-
|
|
359
|
+
@staticmethod
|
|
360
|
+
def _supports_content_reconcile(ws: Any) -> bool:
|
|
361
|
+
"""True when the workspace's ``materialize_content`` takes RFC-RD-607 kwargs.
|
|
362
|
+
|
|
363
|
+
soothe < 2.0 lacks ``protected``/``reconcile``; probing the signature
|
|
364
|
+
keeps flowjet runnable against both release trains.
|
|
365
|
+
"""
|
|
366
|
+
import inspect
|
|
367
|
+
|
|
368
|
+
try:
|
|
369
|
+
params = inspect.signature(ws.materialize_content).parameters
|
|
370
|
+
except (TypeError, ValueError):
|
|
371
|
+
return False
|
|
372
|
+
return "protected" in params and "reconcile" in params
|
|
373
|
+
|
|
374
|
+
async def _recover_manifest(self, ws: Any) -> Any | None:
|
|
375
|
+
"""Recover the prior engine manifest snapshot (single call per open).
|
|
304
376
|
|
|
305
377
|
Round-trip half of workspace sync: ``close_session`` checkpoints and
|
|
306
|
-
uploads dirty files; this
|
|
307
|
-
|
|
378
|
+
uploads dirty files; this reads back the manifest so the per-turn
|
|
379
|
+
materialize can protect agent artifacts and the opening turn can
|
|
380
|
+
restore them.
|
|
381
|
+
"""
|
|
382
|
+
payload = await ws.recover() # reads the latest checkpoint payload
|
|
383
|
+
return payload.manifest_snapshot if payload is not None else None
|
|
384
|
+
|
|
385
|
+
async def _restore_prior_state(self, ws: Any, manifest: Any | None) -> None:
|
|
386
|
+
"""Materialize the recovered manifest's files locally.
|
|
308
387
|
|
|
309
388
|
- Agent-written files live in ``manifest.artifacts`` (path → sha256,
|
|
310
389
|
blobs under ``<root>/blobs/``) and are restored in place at their
|
|
@@ -312,8 +391,6 @@ class SyncAwareWorkspaceResolver(WorkspaceResolver):
|
|
|
312
391
|
- Declared input resources (``manifest.resources``) are materialized
|
|
313
392
|
under ``<root>/input/`` via the soothe Materializer.
|
|
314
393
|
"""
|
|
315
|
-
payload = await ws.recover() # restores checkpoint state, returns snapshot payload
|
|
316
|
-
manifest = payload.manifest_snapshot if payload is not None else None
|
|
317
394
|
if manifest is None:
|
|
318
395
|
return
|
|
319
396
|
|
|
@@ -363,20 +440,32 @@ class SyncAwareWorkspaceResolver(WorkspaceResolver):
|
|
|
363
440
|
return self._restore_cas
|
|
364
441
|
|
|
365
442
|
async def close_session(self, session: str, workspace: Path) -> None:
|
|
366
|
-
"""Checkpoint dirty files + upload to object store
|
|
443
|
+
"""Checkpoint dirty files + upload to object store; close when last run ends.
|
|
444
|
+
|
|
445
|
+
Concurrent turns of the same workspace share one open workspace:
|
|
446
|
+
a mid-run peer's close checkpoints the shared state but keeps the
|
|
447
|
+
workspace open — the lifecycle (``manager.close``) belongs to the
|
|
448
|
+
last run out (RFC-RD-607 §4.3).
|
|
449
|
+
"""
|
|
367
450
|
if self._manager is None:
|
|
368
451
|
return
|
|
369
452
|
|
|
370
453
|
run_id = workspace.name
|
|
371
454
|
|
|
372
|
-
|
|
373
|
-
if
|
|
455
|
+
entry = self._open_workspaces.get(run_id)
|
|
456
|
+
if entry is None:
|
|
374
457
|
return
|
|
375
458
|
|
|
459
|
+
if entry.active_runs > 0:
|
|
460
|
+
entry.active_runs -= 1
|
|
376
461
|
try:
|
|
377
|
-
await ws.checkpoint()
|
|
462
|
+
await entry.ws.checkpoint()
|
|
378
463
|
except Exception:
|
|
379
464
|
logger.warning("Checkpoint failed for session %s", session, exc_info=True)
|
|
465
|
+
if entry.active_runs > 0:
|
|
466
|
+
return
|
|
467
|
+
|
|
468
|
+
self._open_workspaces.pop(run_id, None)
|
|
380
469
|
try:
|
|
381
470
|
await self._manager.close(run_id)
|
|
382
471
|
except Exception:
|
|
@@ -116,12 +116,18 @@ class WorkspaceStager:
|
|
|
116
116
|
) -> dict[str, tuple[int, int]]:
|
|
117
117
|
"""Download the guest workspace tree back to the host (skip identical).
|
|
118
118
|
|
|
119
|
-
|
|
119
|
+
Deletion propagation (RFC-RD-607 §4.4): files the agent deleted inside
|
|
120
|
+
the guest are absent from its tree and are removed from the host too.
|
|
121
|
+
Only paths recorded in the push manifest are eligible — host files
|
|
122
|
+
created after the push are never in it, so they can never be deleted
|
|
123
|
+
by this path. Returns the manifest for the next push.
|
|
120
124
|
"""
|
|
121
125
|
root = Path(workspace)
|
|
122
126
|
guest_root = PurePosixPath(self._settings.workspace_root)
|
|
123
127
|
pulled = 0
|
|
128
|
+
deleted = 0
|
|
124
129
|
next_manifest: dict[str, tuple[int, int]] = {}
|
|
130
|
+
guest_files: set[str] = set()
|
|
125
131
|
|
|
126
132
|
async def walk(guest_dir: PurePosixPath, rel_dir: PurePosixPath) -> None:
|
|
127
133
|
nonlocal pulled
|
|
@@ -142,6 +148,7 @@ class WorkspaceStager:
|
|
|
142
148
|
continue
|
|
143
149
|
if entry.kind != "file":
|
|
144
150
|
continue
|
|
151
|
+
guest_files.add(rel_entry.as_posix())
|
|
145
152
|
data = await sandbox.files.read_bytes(guest_path)
|
|
146
153
|
dest = root / Path(*rel_entry.parts)
|
|
147
154
|
if dest.is_file():
|
|
@@ -157,8 +164,34 @@ class WorkspaceStager:
|
|
|
157
164
|
pulled += 1
|
|
158
165
|
|
|
159
166
|
await walk(guest_root, PurePosixPath("."))
|
|
160
|
-
|
|
161
|
-
|
|
167
|
+
for rel in manifest:
|
|
168
|
+
if rel in guest_files:
|
|
169
|
+
continue
|
|
170
|
+
dest = root / Path(*PurePosixPath(rel).parts)
|
|
171
|
+
if not dest.is_file() or dest.is_symlink():
|
|
172
|
+
continue
|
|
173
|
+
try:
|
|
174
|
+
await asyncio.to_thread(dest.unlink)
|
|
175
|
+
except OSError:
|
|
176
|
+
logger.warning("Sandbox pull: host delete failed for %s in %s", rel, workspace)
|
|
177
|
+
continue
|
|
178
|
+
deleted += 1
|
|
179
|
+
parent = dest.parent
|
|
180
|
+
while parent != root and parent.is_relative_to(root):
|
|
181
|
+
if any(parent.iterdir()):
|
|
182
|
+
break
|
|
183
|
+
try:
|
|
184
|
+
parent.rmdir()
|
|
185
|
+
except OSError:
|
|
186
|
+
break
|
|
187
|
+
parent = parent.parent
|
|
188
|
+
if pulled or deleted:
|
|
189
|
+
logger.info(
|
|
190
|
+
"Sandbox pull for %s: %d files pulled, %d guest deletions propagated",
|
|
191
|
+
workspace,
|
|
192
|
+
pulled,
|
|
193
|
+
deleted,
|
|
194
|
+
)
|
|
162
195
|
return next_manifest
|
|
163
196
|
|
|
164
197
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/logo-generator-skill/.env.example
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/logo-generator-skill/requirements.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/references/REFERENCE.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/research-bootstrap/patterns/loop.json
RENAMED
|
File without changes
|
|
File without changes
|
{flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/research-bootstrap/patterns/rapid.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/research-bootstrap/references/backends.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{flowjet-2.1.1 → flowjet-2.1.2}/src/flowjet/builtin_skills/research-bootstrap/references/routing.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|