my-durable 0.0.0-stage → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +7 -0
- package/LICENSE +21 -0
- package/README.md +328 -2
- package/ai_docs/durable_pi/announcement.md +860 -0
- package/ai_docs/durable_pi/changelog.md +51 -0
- package/ai_docs/durable_pi/chord-delta-findings.md +362 -0
- package/ai_docs/durable_pi/coding-agent-integration.md +70 -0
- package/ai_docs/durable_pi/pico-v5-chord-usage.md +391 -0
- package/ai_docs/durable_pi/pico-v5-handoff.md +921 -0
- package/ai_docs/durable_pi/readme.md +617 -0
- package/ai_docs/durable_pi/sources.md +22 -0
- package/ai_docs/durable_pi/spec.md +4696 -0
- package/ai_docs/durable_pi/vacation-planner.md +57 -0
- package/ai_docs/pi/chord.md +268 -0
- package/ai_docs/pi/cli-integration.md +110 -0
- package/ai_docs/pi/cli.md +325 -0
- package/ai_docs/pi/codemode.md +211 -0
- package/ai_docs/pi/compaction.md +467 -0
- package/ai_docs/pi/configuration.md +51 -0
- package/ai_docs/pi/containerization.md +187 -0
- package/ai_docs/pi/custom-provider.md +177 -0
- package/ai_docs/pi/environment-variables.md +102 -0
- package/ai_docs/pi/extensions.md +278 -0
- package/ai_docs/pi/how-pi-works.md +53 -0
- package/ai_docs/pi/index.md +43 -0
- package/ai_docs/pi/json.md +230 -0
- package/ai_docs/pi/keybindings.md +198 -0
- package/ai_docs/pi/llama-cpp.md +118 -0
- package/ai_docs/pi/mcp.md +274 -0
- package/ai_docs/pi/message-types.md +265 -0
- package/ai_docs/pi/models.md +209 -0
- package/ai_docs/pi/overview.md +166 -0
- package/ai_docs/pi/packages.md +133 -0
- package/ai_docs/pi/pi-agent-core.md +568 -0
- package/ai_docs/pi/pi-ai.md +1942 -0
- package/ai_docs/pi/prompt-templates.md +63 -0
- package/ai_docs/pi/providers.md +204 -0
- package/ai_docs/pi/quickstart.md +140 -0
- package/ai_docs/pi/readme.md +99 -0
- package/ai_docs/pi/rpc-commands.md +864 -0
- package/ai_docs/pi/rpc-extension-ui.md +204 -0
- package/ai_docs/pi/rpc.md +197 -0
- package/ai_docs/pi/sdk.md +151 -0
- package/ai_docs/pi/security.md +103 -0
- package/ai_docs/pi/session-format.md +297 -0
- package/ai_docs/pi/sessions.md +70 -0
- package/ai_docs/pi/settings.md +173 -0
- package/ai_docs/pi/shell-aliases.md +97 -0
- package/ai_docs/pi/skills.md +97 -0
- package/ai_docs/pi/slash-commands.md +64 -0
- package/ai_docs/pi/sources.md +57 -0
- package/ai_docs/pi/terminal-setup.md +223 -0
- package/ai_docs/pi/termux.md +121 -0
- package/ai_docs/pi/themes.md +140 -0
- package/ai_docs/pi/tmux.md +59 -0
- package/ai_docs/pi/toolkit.md +168 -0
- package/ai_docs/pi/tui.md +129 -0
- package/ai_docs/pi/usage.md +98 -0
- package/ai_docs/pi/virtual-models.md +118 -0
- package/ai_docs/pi/windows.md +71 -0
- package/apps/dpi-backend/.nvmrc +1 -0
- package/apps/dpi-backend/API.md +99 -0
- package/apps/dpi-backend/README.md +119 -0
- package/apps/dpi-backend/deploy/backend.env.example +9 -0
- package/apps/dpi-backend/deploy/dpi-backend.plist +26 -0
- package/apps/dpi-backend/deploy/dpi-backend.service +22 -0
- package/apps/dpi-backend/package.json +33 -0
- package/apps/dpi-backend/prompts/one_sentence.md +3 -0
- package/apps/dpi-backend/prompts/smart_ass_opus_fix.md +169 -0
- package/apps/dpi-backend/scripts/check-contract.mjs +151 -0
- package/apps/dpi-backend/scripts/migrate-playground.ts +66 -0
- package/apps/dpi-backend/scripts/record-nested-fixture.mts +154 -0
- package/apps/dpi-backend/scripts/token.ts +57 -0
- package/apps/dpi-backend/src/addons.ts +139 -0
- package/apps/dpi-backend/src/auth.ts +20 -0
- package/apps/dpi-backend/src/config.ts +54 -0
- package/apps/dpi-backend/src/contract-check.ts +118 -0
- package/apps/dpi-backend/src/errors.ts +50 -0
- package/apps/dpi-backend/src/extensions.ts +510 -0
- package/apps/dpi-backend/src/faux.ts +80 -0
- package/apps/dpi-backend/src/history.ts +165 -0
- package/apps/dpi-backend/src/idempotency.ts +20 -0
- package/apps/dpi-backend/src/jev.ts +43 -0
- package/apps/dpi-backend/src/jobs.ts +790 -0
- package/apps/dpi-backend/src/main.ts +76 -0
- package/apps/dpi-backend/src/model-catalog.ts +180 -0
- package/apps/dpi-backend/src/pairing-files.ts +142 -0
- package/apps/dpi-backend/src/pairing.ts +459 -0
- package/apps/dpi-backend/src/routes.ts +217 -0
- package/apps/dpi-backend/src/shared-state.ts +85 -0
- package/apps/dpi-backend/src/store.ts +1240 -0
- package/apps/dpi-backend/src/streams.ts +256 -0
- package/apps/dpi-backend/src/tunnel.ts +955 -0
- package/apps/dpi-backend/tsconfig.json +13 -0
- package/apps/dpi-playground/README.md +83 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/dist/assets/index-CFGc7lHT.js +77 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/dist/assets/index-DFdKpwm_.css +1 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/dist/icons/anthropic.png +0 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/dist/icons/deepseek.png +0 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/dist/icons/durable-pi.svg +14 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/dist/icons/gemini.png +0 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/dist/icons/grok.png +0 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/dist/icons/kimi.png +0 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/dist/icons/lab.png +0 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/dist/icons/meta.png +0 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/dist/icons/minimax.png +0 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/dist/icons/openai.png +0 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/dist/icons/qwen.png +0 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/dist/icons/xiaomi.png +0 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/dist/icons/zai.png +0 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/dist/index.html +16 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/index.html +15 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/package.json +5 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/public/icons/anthropic.png +0 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/public/icons/deepseek.png +0 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/public/icons/durable-pi.svg +14 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/public/icons/gemini.png +0 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/public/icons/grok.png +0 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/public/icons/kimi.png +0 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/public/icons/lab.png +0 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/public/icons/meta.png +0 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/public/icons/minimax.png +0 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/public/icons/openai.png +0 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/public/icons/qwen.png +0 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/public/icons/xiaomi.png +0 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/public/icons/zai.png +0 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/App.vue +180 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/client/commands.ts +119 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/client/composables.ts +129 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/client/hub.ts +40 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/client/icon-path.ts +7 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/client/ids.ts +2 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/client/jobs.ts +80 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/client/link-policy.ts +16 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/client/markdown-policy.ts +115 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/client/markdown.ts +60 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/client/pair-close.ts +23 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/client/pair-handoff.ts +56 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/client/pair.ts +166 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/client/qrcode.ts +323 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/client/signature.ts +146 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/client/store.ts +373 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/client/stream.ts +183 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/components/AgentView.vue +342 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/components/Composer.vue +198 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/components/ContextBar.vue +254 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/components/DeviceCredentialsDialog.vue +40 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/components/DeviceIcon.vue +56 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/components/DirBrowser.vue +95 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/components/ExtensionsPanel.vue +96 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/components/HelpDialog.vue +69 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/components/Inspector.vue +425 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/components/JobCard.vue +221 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/components/MobileNav.vue +39 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/components/ModelPicker.vue +71 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/components/NetworkSidebar.vue +236 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/components/NewSessionDialog.vue +114 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/components/OfflinePanel.vue +128 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/components/PairDeviceWizard.vue +433 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/components/PromptDialog.vue +89 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/components/StateEditor.vue +179 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/components/TasksPanel.vue +280 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/components/Toast.vue +11 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/components/TokenManager.vue +175 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/components/TopBar.vue +114 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/components/TranscriptItem.vue +152 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/components/TreeRow.vue +195 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/components/TunnelStatusBar.vue +107 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/extensions.css +105 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/jobs.css +655 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/main.ts +22 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/network.css +675 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/src/style.css +3203 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/tsconfig.json +16 -0
- package/apps/dpi-playground/apps/dpi-playground-fe/vite.config.ts +14 -0
- package/apps/dpi-playground/apps/dpi-playground-hub/package.json +5 -0
- package/apps/dpi-playground/apps/dpi-playground-hub/src/audit.ts +406 -0
- package/apps/dpi-playground/apps/dpi-playground-hub/src/client-ip.ts +72 -0
- package/apps/dpi-playground/apps/dpi-playground-hub/src/credentials.ts +265 -0
- package/apps/dpi-playground/apps/dpi-playground-hub/src/guard.ts +43 -0
- package/apps/dpi-playground/apps/dpi-playground-hub/src/http-errors.ts +156 -0
- package/apps/dpi-playground/apps/dpi-playground-hub/src/identity.ts +60 -0
- package/apps/dpi-playground/apps/dpi-playground-hub/src/limiter.ts +165 -0
- package/apps/dpi-playground/apps/dpi-playground-hub/src/main.ts +460 -0
- package/apps/dpi-playground/apps/dpi-playground-hub/src/monitor.ts +320 -0
- package/apps/dpi-playground/apps/dpi-playground-hub/src/mux.ts +277 -0
- package/apps/dpi-playground/apps/dpi-playground-hub/src/pairing.ts +816 -0
- package/apps/dpi-playground/apps/dpi-playground-hub/src/proxy.ts +128 -0
- package/apps/dpi-playground/apps/dpi-playground-hub/src/rotation.ts +583 -0
- package/apps/dpi-playground/apps/dpi-playground-hub/src/seed.ts +11 -0
- package/apps/dpi-playground/apps/dpi-playground-hub/src/transport.ts +108 -0
- package/apps/dpi-playground/apps/dpi-playground-hub/src/tunnel-token.ts +11 -0
- package/apps/dpi-playground/apps/dpi-playground-hub/src/tunnel-transport.ts +560 -0
- package/apps/dpi-playground/apps/dpi-playground-hub/src/tunnel.ts +873 -0
- package/apps/dpi-playground/apps/dpi-playground-hub/tsconfig.json +13 -0
- package/apps/dpi-playground/package.json +37 -0
- package/apps/dpi-sdk/README.md +74 -0
- package/apps/dpi-sdk/package.json +20 -0
- package/apps/dpi-sdk/scripts/net.ts +73 -0
- package/apps/dpi-sdk/src/api.ts +631 -0
- package/apps/dpi-sdk/src/app-state.ts +111 -0
- package/apps/dpi-sdk/src/client.ts +330 -0
- package/apps/dpi-sdk/src/errors.ts +16 -0
- package/apps/dpi-sdk/src/jobs.ts +99 -0
- package/apps/dpi-sdk/src/models.ts +472 -0
- package/apps/dpi-sdk/src/node/chunk.ts +488 -0
- package/apps/dpi-sdk/src/node/config.ts +175 -0
- package/apps/dpi-sdk/src/node/drivers.ts +402 -0
- package/apps/dpi-sdk/src/node/ops.ts +114 -0
- package/apps/dpi-sdk/src/node/private-dir.ts +48 -0
- package/apps/dpi-sdk/src/node/registry-migration.ts +549 -0
- package/apps/dpi-sdk/src/node/registry.ts +390 -0
- package/apps/dpi-sdk/src/node/sse-writer.ts +151 -0
- package/apps/dpi-sdk/src/protocol/backoff.ts +31 -0
- package/apps/dpi-sdk/src/protocol/limits.ts +199 -0
- package/apps/dpi-sdk/src/protocol/pairing.ts +311 -0
- package/apps/dpi-sdk/src/protocol/rest-routes.ts +105 -0
- package/apps/dpi-sdk/src/protocol/tunnel.ts +331 -0
- package/apps/dpi-sdk/src/sse.ts +117 -0
- package/apps/dpi-sdk/src/transcript.ts +291 -0
- package/apps/dpi-sdk/tsconfig.json +13 -0
- package/apps/dpi-sdk/w +20 -0
- package/apps/dpi-tui/README.md +54 -0
- package/apps/dpi-tui/bin/dpi-tui.mjs +5 -0
- package/apps/dpi-tui/package.json +20 -0
- package/apps/dpi-tui/src/app.ts +433 -0
- package/apps/dpi-tui/src/commands.ts +151 -0
- package/apps/dpi-tui/src/main.ts +122 -0
- package/apps/dpi-tui/src/pairing.ts +287 -0
- package/apps/dpi-tui/src/pickers.ts +238 -0
- package/apps/dpi-tui/src/render.ts +164 -0
- package/apps/dpi-tui/src/theme.ts +57 -0
- package/apps/dpi-tui/tsconfig.json +14 -0
- package/bin/device.mjs +5 -0
- package/bin/hub.mjs +5 -0
- package/bin/tui.mjs +5 -0
- package/deploy/Caddyfile +120 -0
- package/docs/verification.md +102 -0
- package/dpi-network.example.yaml +62 -0
- package/images/01_durable_agent_network.svg +185 -0
- package/images/02_pi_made_durable.svg +204 -0
- package/images/03_restart_mid_tool.svg +168 -0
- package/images/07_one_api_every_client.svg +123 -0
- package/images/08_device_session_agent.svg +123 -0
- package/images/09_compact_keep_history.svg +143 -0
- package/images/10_shared_app_state.svg +177 -0
- package/images/11_durable_jobs_wait.svg +141 -0
- package/images/12_tools_change_mid_run.svg +231 -0
- package/images/13_hook_blocks_tool.svg +122 -0
- package/images/14_fork_at_any_entry.svg +119 -0
- package/images/15_web_client.png +0 -0
- package/images/16_terminal_client.svg +43 -0
- package/images/17_devices_are_data.svg +182 -0
- package/images/18_should_every_agent_be_durable.svg +118 -0
- package/images/19_sqlite_on_every_device.svg +155 -0
- package/images/20_admission_and_effects.svg +134 -0
- package/justfile +33 -0
- package/package.json +41 -4
- package/scripts/verify.mjs +210 -0
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="660" viewBox="0 0 1200 660" role="img" aria-labelledby="title desc" font-family="Inter, 'Segoe UI', Helvetica, Arial, sans-serif">
|
|
2
|
+
<title id="title">Should every agent be durable?</title>
|
|
3
|
+
<desc id="desc">A table matches work requirements to agents: short, supervised work in one terminal suits Pi, while surviving restarts, waiting hours for a human, serving many clients and starting on its own call for Durable Pi, which still leaves the host, storage and effect recovery to choose.</desc>
|
|
4
|
+
<defs>
|
|
5
|
+
<symbol id="g-pi" viewBox="0 0 64 64">
|
|
6
|
+
<rect x="1.5" y="1.5" width="61" height="61" rx="12" fill="#141011" stroke="#FF5252" stroke-width="2.5"/>
|
|
7
|
+
<g fill="#FFFFFF" transform="translate(16 16) scale(8)">
|
|
8
|
+
<path d="M0 0H3V2H2V1H0Z"/>
|
|
9
|
+
<path d="M0 1H1V2H2V3H1V4H0Z"/>
|
|
10
|
+
<path d="M3 2H4V4H3Z"/>
|
|
11
|
+
</g>
|
|
12
|
+
</symbol>
|
|
13
|
+
<symbol id="g-dpi" viewBox="0 0 9 5">
|
|
14
|
+
<g fill="#FFFFFF" transform="translate(.5 .5)">
|
|
15
|
+
<path d="M0 0H1V4H0Z"/>
|
|
16
|
+
<path d="M1 0H2V1H3V2H2V1H1Z"/>
|
|
17
|
+
<path d="M2 2H3V3H2V4H1V3H2Z"/>
|
|
18
|
+
<g transform="translate(4)">
|
|
19
|
+
<path d="M0 0H3V2H2V1H0Z"/>
|
|
20
|
+
<path d="M0 1H1V2H2V3H1V4H0Z"/>
|
|
21
|
+
<path d="M3 2H4V4H3Z"/>
|
|
22
|
+
</g>
|
|
23
|
+
</g>
|
|
24
|
+
</symbol>
|
|
25
|
+
</defs>
|
|
26
|
+
<style>
|
|
27
|
+
.an { animation-duration: 12s; animation-iteration-count: infinite; animation-timing-function: cubic-bezier(.4, 0, .2, 1); }
|
|
28
|
+
.draw { stroke-dasharray: 1 2; }
|
|
29
|
+
|
|
30
|
+
/* rows reveal one at a time, then their check draws in (ring, then tick) */
|
|
31
|
+
.row0 { animation-name: row0; } .ring0 { animation-name: ring0; } .tick0 { animation-name: tick0; }
|
|
32
|
+
.row1 { animation-name: row1; } .ring1 { animation-name: ring1; } .tick1 { animation-name: tick1; }
|
|
33
|
+
.row2 { animation-name: row2; } .ring2 { animation-name: ring2; } .tick2 { animation-name: tick2; }
|
|
34
|
+
.row3 { animation-name: row3; } .ring3 { animation-name: ring3; } .tick3 { animation-name: tick3; }
|
|
35
|
+
.row4 { animation-name: row4; } .ring4 { animation-name: ring4; } .tick4 { animation-name: tick4; }
|
|
36
|
+
@keyframes row0 { 0%, 5% { opacity: 0; transform: translateY(10px) } 8%, 96% { opacity: 1; transform: translateY(0) } 100% { opacity: 0; transform: translateY(0) } }
|
|
37
|
+
@keyframes ring0 { 0%, 8% { stroke-dashoffset: 1; opacity: 0 } 8.5% { opacity: 1 } 11%, 100% { stroke-dashoffset: 0; opacity: 1 } }
|
|
38
|
+
@keyframes tick0 { 0%, 10% { stroke-dashoffset: 1; opacity: 0 } 10.5% { opacity: 1 } 13%, 100% { stroke-dashoffset: 0; opacity: 1 } }
|
|
39
|
+
@keyframes row1 { 0%, 14% { opacity: 0; transform: translateY(10px) } 17%, 96% { opacity: 1; transform: translateY(0) } 100% { opacity: 0; transform: translateY(0) } }
|
|
40
|
+
@keyframes ring1 { 0%, 17% { stroke-dashoffset: 1; opacity: 0 } 17.5% { opacity: 1 } 20%, 100% { stroke-dashoffset: 0; opacity: 1 } }
|
|
41
|
+
@keyframes tick1 { 0%, 19% { stroke-dashoffset: 1; opacity: 0 } 19.5% { opacity: 1 } 22%, 100% { stroke-dashoffset: 0; opacity: 1 } }
|
|
42
|
+
@keyframes row2 { 0%, 23% { opacity: 0; transform: translateY(10px) } 26%, 96% { opacity: 1; transform: translateY(0) } 100% { opacity: 0; transform: translateY(0) } }
|
|
43
|
+
@keyframes ring2 { 0%, 26% { stroke-dashoffset: 1; opacity: 0 } 26.5% { opacity: 1 } 29%, 100% { stroke-dashoffset: 0; opacity: 1 } }
|
|
44
|
+
@keyframes tick2 { 0%, 28% { stroke-dashoffset: 1; opacity: 0 } 28.5% { opacity: 1 } 31%, 100% { stroke-dashoffset: 0; opacity: 1 } }
|
|
45
|
+
@keyframes row3 { 0%, 32% { opacity: 0; transform: translateY(10px) } 35%, 96% { opacity: 1; transform: translateY(0) } 100% { opacity: 0; transform: translateY(0) } }
|
|
46
|
+
@keyframes ring3 { 0%, 35% { stroke-dashoffset: 1; opacity: 0 } 35.5% { opacity: 1 } 38%, 100% { stroke-dashoffset: 0; opacity: 1 } }
|
|
47
|
+
@keyframes tick3 { 0%, 37% { stroke-dashoffset: 1; opacity: 0 } 37.5% { opacity: 1 } 40%, 100% { stroke-dashoffset: 0; opacity: 1 } }
|
|
48
|
+
@keyframes row4 { 0%, 41% { opacity: 0; transform: translateY(10px) } 44%, 96% { opacity: 1; transform: translateY(0) } 100% { opacity: 0; transform: translateY(0) } }
|
|
49
|
+
@keyframes ring4 { 0%, 44% { stroke-dashoffset: 1; opacity: 0 } 44.5% { opacity: 1 } 47%, 100% { stroke-dashoffset: 0; opacity: 1 } }
|
|
50
|
+
@keyframes tick4 { 0%, 46% { stroke-dashoffset: 1; opacity: 0 } 46.5% { opacity: 1 } 49%, 100% { stroke-dashoffset: 0; opacity: 1 } }
|
|
51
|
+
|
|
52
|
+
/* the remaining choices close the table */
|
|
53
|
+
.footer { animation-name: footer; }
|
|
54
|
+
@keyframes footer { 0%, 52% { opacity: 0; transform: translateY(10px) } 57%, 96% { opacity: 1; transform: translateY(0) } 100% { opacity: 0; transform: translateY(0) } }
|
|
55
|
+
|
|
56
|
+
@media (prefers-reduced-motion: reduce) { * { animation: none !important; } }
|
|
57
|
+
</style>
|
|
58
|
+
|
|
59
|
+
<rect width="1200" height="660" rx="18" fill="#141011"/>
|
|
60
|
+
<text x="48" y="70" font-size="34" font-weight="600" fill="#F3EDEE">Should every agent be durable?</text>
|
|
61
|
+
|
|
62
|
+
<!-- table -->
|
|
63
|
+
<rect x="48" y="112" width="1104" height="426" rx="12" fill="#21191B" stroke="#443438" stroke-width="2"/>
|
|
64
|
+
<use href="#g-pi" x="732" y="132" width="56" height="56"/>
|
|
65
|
+
<use href="#g-dpi" x="964" y="140" width="72" height="40"/>
|
|
66
|
+
<g font-size="20" letter-spacing="1">
|
|
67
|
+
<text x="88" y="220" fill="#B9AAAE">WORK REQUIREMENT</text>
|
|
68
|
+
<text x="760" y="220" font-weight="600" text-anchor="middle" fill="#F3EDEE">PI</text>
|
|
69
|
+
<text x="1000" y="220" font-weight="600" text-anchor="middle" fill="#F3EDEE">DURABLE PI</text>
|
|
70
|
+
</g>
|
|
71
|
+
|
|
72
|
+
<g font-size="24" fill="#F3EDEE">
|
|
73
|
+
<g class="an row0">
|
|
74
|
+
<rect x="64" y="238" width="1072" height="56" rx="8" fill="#141011"/>
|
|
75
|
+
<text x="88" y="274">Short, supervised, one terminal</text>
|
|
76
|
+
<g transform="translate(742 248) scale(1.125)" fill="none" stroke="#FF5252">
|
|
77
|
+
<path class="an draw ring0" pathLength="1" d="M16 2.5A13.5 13.5 0 1 1 16 29.5A13.5 13.5 0 1 1 16 2.5" stroke-width="2.5"/>
|
|
78
|
+
<path class="an draw tick0" pathLength="1" d="M9.5 16.5L14 21L22.5 11.5" stroke-width="2.8" stroke-linecap="round" stroke-linejoin="round"/>
|
|
79
|
+
</g>
|
|
80
|
+
</g>
|
|
81
|
+
<g class="an row1">
|
|
82
|
+
<text x="88" y="330">Survives a crash or restart</text>
|
|
83
|
+
<g transform="translate(982 304) scale(1.125)" fill="none" stroke="#FF5252">
|
|
84
|
+
<path class="an draw ring1" pathLength="1" d="M16 2.5A13.5 13.5 0 1 1 16 29.5A13.5 13.5 0 1 1 16 2.5" stroke-width="2.5"/>
|
|
85
|
+
<path class="an draw tick1" pathLength="1" d="M9.5 16.5L14 21L22.5 11.5" stroke-width="2.8" stroke-linecap="round" stroke-linejoin="round"/>
|
|
86
|
+
</g>
|
|
87
|
+
</g>
|
|
88
|
+
<g class="an row2">
|
|
89
|
+
<rect x="64" y="350" width="1072" height="56" rx="8" fill="#141011"/>
|
|
90
|
+
<text x="88" y="386">Waits hours for a human</text>
|
|
91
|
+
<g transform="translate(982 360) scale(1.125)" fill="none" stroke="#FF5252">
|
|
92
|
+
<path class="an draw ring2" pathLength="1" d="M16 2.5A13.5 13.5 0 1 1 16 29.5A13.5 13.5 0 1 1 16 2.5" stroke-width="2.5"/>
|
|
93
|
+
<path class="an draw tick2" pathLength="1" d="M9.5 16.5L14 21L22.5 11.5" stroke-width="2.8" stroke-linecap="round" stroke-linejoin="round"/>
|
|
94
|
+
</g>
|
|
95
|
+
</g>
|
|
96
|
+
<g class="an row3">
|
|
97
|
+
<text x="88" y="442">Many clients, one agent</text>
|
|
98
|
+
<g transform="translate(982 416) scale(1.125)" fill="none" stroke="#FF5252">
|
|
99
|
+
<path class="an draw ring3" pathLength="1" d="M16 2.5A13.5 13.5 0 1 1 16 29.5A13.5 13.5 0 1 1 16 2.5" stroke-width="2.5"/>
|
|
100
|
+
<path class="an draw tick3" pathLength="1" d="M9.5 16.5L14 21L22.5 11.5" stroke-width="2.8" stroke-linecap="round" stroke-linejoin="round"/>
|
|
101
|
+
</g>
|
|
102
|
+
</g>
|
|
103
|
+
<g class="an row4">
|
|
104
|
+
<rect x="64" y="462" width="1072" height="56" rx="8" fill="#141011"/>
|
|
105
|
+
<text x="88" y="498">Starts before you sit down</text>
|
|
106
|
+
<g transform="translate(982 472) scale(1.125)" fill="none" stroke="#FF5252">
|
|
107
|
+
<path class="an draw ring4" pathLength="1" d="M16 2.5A13.5 13.5 0 1 1 16 29.5A13.5 13.5 0 1 1 16 2.5" stroke-width="2.5"/>
|
|
108
|
+
<path class="an draw tick4" pathLength="1" d="M9.5 16.5L14 21L22.5 11.5" stroke-width="2.8" stroke-linecap="round" stroke-linejoin="round"/>
|
|
109
|
+
</g>
|
|
110
|
+
</g>
|
|
111
|
+
</g>
|
|
112
|
+
|
|
113
|
+
<!-- what durable still leaves open -->
|
|
114
|
+
<g class="an footer">
|
|
115
|
+
<rect x="48" y="558" width="1104" height="64" rx="12" fill="#21191B" stroke="#443438" stroke-width="2"/>
|
|
116
|
+
<text x="88" y="598" font-size="22" fill="#B9AAAE">Durable still leaves you to choose: <tspan font-weight="600" fill="#F3EDEE">host · storage · effect recovery</tspan></text>
|
|
117
|
+
</g>
|
|
118
|
+
</svg>
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 600" width="1200" height="600" role="img" aria-labelledby="title desc" font-family="Inter, 'Segoe UI', Helvetica, Arial, sans-serif">
|
|
2
|
+
<title id="title">SQLite on every device</title>
|
|
3
|
+
<desc id="desc">Every device runs dpi-backend with its own SQLite files: a catalog, shared app state and one agent.sqlite per session, while the hub keeps only a network.sqlite of device URLs and tokens.</desc>
|
|
4
|
+
<defs>
|
|
5
|
+
<symbol id="g-pi" viewBox="0 0 64 64">
|
|
6
|
+
<rect x="1.5" y="1.5" width="61" height="61" rx="12" fill="#141011" stroke="#FF5252" stroke-width="2.5"/>
|
|
7
|
+
<g fill="#FFFFFF" transform="translate(16 16) scale(8)">
|
|
8
|
+
<path d="M0 0H3V2H2V1H0Z"/>
|
|
9
|
+
<path d="M0 1H1V2H2V3H1V4H0Z"/>
|
|
10
|
+
<path d="M3 2H4V4H3Z"/>
|
|
11
|
+
</g>
|
|
12
|
+
</symbol>
|
|
13
|
+
<symbol id="g-db" viewBox="0 0 48 60">
|
|
14
|
+
<path d="M3 10 V50 A21 7 0 0 0 45 50 V10" fill="#3A1D20" stroke="#FF5252" stroke-width="2.5"/>
|
|
15
|
+
<ellipse cx="24" cy="10" rx="21" ry="7" fill="#5A2328" stroke="#FF5252" stroke-width="2.5"/>
|
|
16
|
+
<path d="M3 24 A21 7 0 0 0 45 24 M3 37 A21 7 0 0 0 45 37" fill="none" stroke="#FF5252" stroke-width="2.5"/>
|
|
17
|
+
</symbol>
|
|
18
|
+
<symbol id="g-server" viewBox="0 0 64 44">
|
|
19
|
+
<rect x="3" y="4" width="58" height="16" rx="4" fill="#21191B" stroke="#F3EDEE" stroke-width="2.5"/>
|
|
20
|
+
<rect x="3" y="24" width="58" height="16" rx="4" fill="#21191B" stroke="#F3EDEE" stroke-width="2.5"/>
|
|
21
|
+
<circle cx="13" cy="12" r="2.6" fill="#FF5252"/><circle cx="13" cy="32" r="2.6" fill="#FF5252"/>
|
|
22
|
+
<path d="M36 12 H53 M36 32 H53" stroke="#B9AAAE" stroke-width="2.5" stroke-linecap="round"/>
|
|
23
|
+
</symbol>
|
|
24
|
+
<symbol id="g-laptop" viewBox="0 0 64 44">
|
|
25
|
+
<rect x="9" y="3" width="46" height="30" rx="4" fill="#21191B" stroke="#F3EDEE" stroke-width="2.5"/>
|
|
26
|
+
<rect x="15" y="9" width="34" height="18" rx="2" fill="#141011"/>
|
|
27
|
+
<path d="M2 37 H62 L58 42 H6 Z" fill="#F3EDEE"/>
|
|
28
|
+
</symbol>
|
|
29
|
+
<symbol id="g-key" viewBox="0 0 48 24">
|
|
30
|
+
<circle cx="11" cy="12" r="8" fill="none" stroke="#FF5252" stroke-width="2.8"/>
|
|
31
|
+
<path d="M19 12 H45 M36 12 V19 M42 12 V17" stroke="#FF5252" stroke-width="2.8" stroke-linecap="round"/>
|
|
32
|
+
</symbol>
|
|
33
|
+
<marker id="head-red" viewBox="0 0 12 10" refX="8" refY="5" markerWidth="12" markerHeight="10" markerUnits="userSpaceOnUse" orient="auto">
|
|
34
|
+
<path d="M0 0 L12 5 L0 10 Z" fill="#FF5252"/>
|
|
35
|
+
</marker>
|
|
36
|
+
</defs>
|
|
37
|
+
<style>
|
|
38
|
+
.loop, .a { animation-duration: 12s; animation-iteration-count: infinite; animation-timing-function: ease-in-out; }
|
|
39
|
+
.mono { font-family: 'JetBrains Mono', 'SF Mono', Menlo, Consolas, monospace; }
|
|
40
|
+
.loop { animation-name: loop; }
|
|
41
|
+
.dev { animation-name: dev; }
|
|
42
|
+
.cat { animation-name: cat; }
|
|
43
|
+
.app { animation-name: app; }
|
|
44
|
+
.col { animation-name: col; }
|
|
45
|
+
.row1 { animation-name: row1; }
|
|
46
|
+
.row2 { animation-name: row2; }
|
|
47
|
+
.row3 { animation-name: row3; }
|
|
48
|
+
.arr1 { animation-name: arr1; }
|
|
49
|
+
.arr2 { animation-name: arr2; }
|
|
50
|
+
.arr3 { animation-name: arr3; }
|
|
51
|
+
.head1 { animation-name: head1; }
|
|
52
|
+
.head2 { animation-name: head2; }
|
|
53
|
+
.head3 { animation-name: head3; }
|
|
54
|
+
.lid1 { opacity: 0; animation-name: lid1; }
|
|
55
|
+
.lid2 { opacity: 0; animation-name: lid2; }
|
|
56
|
+
.lid3 { opacity: 0; animation-name: lid3; }
|
|
57
|
+
.hub { animation-name: hub; }
|
|
58
|
+
.key1 { animation-name: key1; }
|
|
59
|
+
.key2 { animation-name: key2; }
|
|
60
|
+
.key3 { animation-name: key3; }
|
|
61
|
+
@keyframes loop { 0%, 96% { opacity: 1 } 99%, 100% { opacity: 0 } }
|
|
62
|
+
@keyframes dev { 0%, 1% { opacity: 0 } 5%, 100% { opacity: 1 } }
|
|
63
|
+
@keyframes cat { 0%, 5% { opacity: 0 } 8%, 100% { opacity: 1 } }
|
|
64
|
+
@keyframes app { 0%, 8% { opacity: 0 } 11%, 100% { opacity: 1 } }
|
|
65
|
+
@keyframes col { 0%, 11% { opacity: 0 } 14%, 100% { opacity: 1 } }
|
|
66
|
+
@keyframes row1 { 0%, 14% { opacity: 0 } 17%, 100% { opacity: 1 } }
|
|
67
|
+
@keyframes arr1 { 0%, 17% { stroke-dashoffset: 203 } 21%, 100% { stroke-dashoffset: 0 } }
|
|
68
|
+
@keyframes head1 { 0%, 20.5% { opacity: 0 } 21.5%, 100% { opacity: 1 } }
|
|
69
|
+
@keyframes lid1 { 0%, 21% { opacity: 0 } 22.5% { opacity: .85 } 25%, 100% { opacity: 0 } }
|
|
70
|
+
@keyframes row2 { 0%, 21% { opacity: 0 } 24%, 100% { opacity: 1 } }
|
|
71
|
+
@keyframes arr2 { 0%, 24% { stroke-dashoffset: 203 } 28%, 100% { stroke-dashoffset: 0 } }
|
|
72
|
+
@keyframes head2 { 0%, 27.5% { opacity: 0 } 28.5%, 100% { opacity: 1 } }
|
|
73
|
+
@keyframes lid2 { 0%, 28% { opacity: 0 } 29.5% { opacity: .85 } 32%, 100% { opacity: 0 } }
|
|
74
|
+
@keyframes row3 { 0%, 28% { opacity: 0 } 31%, 100% { opacity: 1 } }
|
|
75
|
+
@keyframes arr3 { 0%, 31% { stroke-dashoffset: 203 } 35%, 100% { stroke-dashoffset: 0 } }
|
|
76
|
+
@keyframes head3 { 0%, 34.5% { opacity: 0 } 35.5%, 100% { opacity: 1 } }
|
|
77
|
+
@keyframes lid3 { 0%, 35% { opacity: 0 } 36.5% { opacity: .85 } 39%, 100% { opacity: 0 } }
|
|
78
|
+
@keyframes hub { 0%, 41% { opacity: 0 } 45%, 100% { opacity: 1 } }
|
|
79
|
+
@keyframes key1 { 0%, 48% { opacity: .2 } 50%, 100% { opacity: 1 } }
|
|
80
|
+
@keyframes key2 { 0%, 51.5% { opacity: .2 } 53.5%, 100% { opacity: 1 } }
|
|
81
|
+
@keyframes key3 { 0%, 55% { opacity: .2 } 57%, 100% { opacity: 1 } }
|
|
82
|
+
@media (prefers-reduced-motion: reduce) { * { animation: none !important; } }
|
|
83
|
+
</style>
|
|
84
|
+
|
|
85
|
+
<rect width="1200" height="600" rx="18" fill="#141011"/>
|
|
86
|
+
<text x="48" y="70" font-size="34" font-weight="600" fill="#F3EDEE">SQLite on every device</text>
|
|
87
|
+
|
|
88
|
+
<g class="loop">
|
|
89
|
+
<!-- a device: dpi-backend and its SQLite files -->
|
|
90
|
+
<g class="a dev">
|
|
91
|
+
<rect x="48" y="100" width="788" height="422" rx="12" fill="#21191B" stroke="#443438" stroke-width="2"/>
|
|
92
|
+
<use href="#g-server" x="80" y="122" width="64" height="44"/>
|
|
93
|
+
<text class="mono" x="162" y="152" font-size="24" fill="#F3EDEE">dpi-backend</text>
|
|
94
|
+
<text x="340" y="152" font-size="20" fill="#B9AAAE">on every device</text>
|
|
95
|
+
<path d="M428 192 V498" stroke="#443438" stroke-width="2"/>
|
|
96
|
+
</g>
|
|
97
|
+
<g class="a cat">
|
|
98
|
+
<use href="#g-db" x="80" y="240" width="48" height="60"/>
|
|
99
|
+
<text class="mono" x="144" y="252" font-size="22" fill="#F3EDEE">catalog.sqlite</text>
|
|
100
|
+
<text x="144" y="278" font-size="20" fill="#B9AAAE">sessions, names,</text>
|
|
101
|
+
<text x="144" y="302" font-size="20" fill="#B9AAAE">idempotency keys</text>
|
|
102
|
+
</g>
|
|
103
|
+
<g class="a app">
|
|
104
|
+
<use href="#g-db" x="80" y="392" width="48" height="60"/>
|
|
105
|
+
<text class="mono" x="144" y="415" font-size="22" fill="#F3EDEE">app-state.sqlite</text>
|
|
106
|
+
<text x="144" y="441" font-size="20" fill="#B9AAAE">shared App State</text>
|
|
107
|
+
</g>
|
|
108
|
+
<g class="a col">
|
|
109
|
+
<text class="mono" x="452" y="212" font-size="22" fill="#F3EDEE">sessions/<id>/agent.sqlite</text>
|
|
110
|
+
<text x="452" y="240" font-size="20" fill="#B9AAAE">one harness per session</text>
|
|
111
|
+
</g>
|
|
112
|
+
|
|
113
|
+
<g class="a row1">
|
|
114
|
+
<rect x="452" y="258" width="352" height="72" rx="10" fill="#141011" stroke="#443438" stroke-width="2"/>
|
|
115
|
+
<use href="#g-pi" x="468" y="268" width="52" height="52"/>
|
|
116
|
+
<use href="#g-db" x="736" y="266" width="44" height="55"/>
|
|
117
|
+
</g>
|
|
118
|
+
<path class="a arr1" d="M528 294 H729" stroke-dasharray="203 203" fill="none" stroke="#FF5252" stroke-width="2.5"/>
|
|
119
|
+
<path class="a head1" d="M528 294 H729" fill="none" stroke="none" marker-end="url(#head-red)"/>
|
|
120
|
+
<ellipse class="a lid1" cx="758" cy="275.2" rx="19.3" ry="6.4" fill="#FF5252"/>
|
|
121
|
+
|
|
122
|
+
<g class="a row2">
|
|
123
|
+
<rect x="452" y="342" width="352" height="72" rx="10" fill="#141011" stroke="#443438" stroke-width="2"/>
|
|
124
|
+
<use href="#g-pi" x="468" y="352" width="52" height="52"/>
|
|
125
|
+
<use href="#g-db" x="736" y="350" width="44" height="55"/>
|
|
126
|
+
</g>
|
|
127
|
+
<path class="a arr2" d="M528 378 H729" stroke-dasharray="203 203" fill="none" stroke="#FF5252" stroke-width="2.5"/>
|
|
128
|
+
<path class="a head2" d="M528 378 H729" fill="none" stroke="none" marker-end="url(#head-red)"/>
|
|
129
|
+
<ellipse class="a lid2" cx="758" cy="359.2" rx="19.3" ry="6.4" fill="#FF5252"/>
|
|
130
|
+
|
|
131
|
+
<g class="a row3">
|
|
132
|
+
<rect x="452" y="426" width="352" height="72" rx="10" fill="#141011" stroke="#443438" stroke-width="2"/>
|
|
133
|
+
<use href="#g-pi" x="468" y="436" width="52" height="52"/>
|
|
134
|
+
<use href="#g-db" x="736" y="434" width="44" height="55"/>
|
|
135
|
+
</g>
|
|
136
|
+
<path class="a arr3" d="M528 462 H729" stroke-dasharray="203 203" fill="none" stroke="#FF5252" stroke-width="2.5"/>
|
|
137
|
+
<path class="a head3" d="M528 462 H729" fill="none" stroke="none" marker-end="url(#head-red)"/>
|
|
138
|
+
<ellipse class="a lid3" cx="758" cy="443.2" rx="19.3" ry="6.4" fill="#FF5252"/>
|
|
139
|
+
|
|
140
|
+
<!-- the hub: only how to reach each device -->
|
|
141
|
+
<g class="a hub">
|
|
142
|
+
<rect x="860" y="166" width="292" height="290" rx="12" fill="#21191B" stroke="#443438" stroke-width="2"/>
|
|
143
|
+
<use href="#g-laptop" x="884" y="186" width="64" height="44"/>
|
|
144
|
+
<text x="962" y="216" font-size="24" fill="#F3EDEE">hub</text>
|
|
145
|
+
<use href="#g-db" x="978" y="302" width="56" height="70"/>
|
|
146
|
+
<text class="mono" x="1006" y="404" font-size="22" fill="#F3EDEE" text-anchor="middle">network.sqlite</text>
|
|
147
|
+
<text x="1006" y="432" font-size="20" fill="#B9AAAE" text-anchor="middle">device URLs and tokens</text>
|
|
148
|
+
<use class="a key1" href="#g-key" x="930" y="258" width="40" height="20"/>
|
|
149
|
+
<use class="a key2" href="#g-key" x="986" y="258" width="40" height="20"/>
|
|
150
|
+
<use class="a key3" href="#g-key" x="1042" y="258" width="40" height="20"/>
|
|
151
|
+
</g>
|
|
152
|
+
</g>
|
|
153
|
+
|
|
154
|
+
<text x="48" y="566" font-size="22" fill="#B9AAAE">Each device owns its agents and their data. The hub only stores how to reach them.</text>
|
|
155
|
+
</svg>
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 690" width="1200" height="690" role="img" aria-labelledby="title desc" font-family="Inter, 'Segoe UI', Helvetica, Arial, sans-serif">
|
|
2
|
+
<title id="title">Admission and effects are separate</title>
|
|
3
|
+
<desc id="desc">A retried requestId is deduplicated into one submission, but a crash after an external API call can leave the effect done without a saved result, so recovery reruns replay-safe tools, returns an interrupted result for unsafe ones, and leaves external idempotency to you.</desc>
|
|
4
|
+
<defs>
|
|
5
|
+
<marker id="head-red" viewBox="0 0 12 10" refX="8" refY="5" markerWidth="12" markerHeight="10" markerUnits="userSpaceOnUse" orient="auto">
|
|
6
|
+
<path d="M0 0 L12 5 L0 10 Z" fill="#FF5252"/>
|
|
7
|
+
</marker>
|
|
8
|
+
<marker id="head-muted" viewBox="0 0 12 10" refX="8" refY="5" markerWidth="12" markerHeight="10" markerUnits="userSpaceOnUse" orient="auto">
|
|
9
|
+
<path d="M0 0 L12 5 L0 10 Z" fill="#B9AAAE"/>
|
|
10
|
+
</marker>
|
|
11
|
+
</defs>
|
|
12
|
+
<style>
|
|
13
|
+
.loop, .a { animation-duration: 14s; animation-iteration-count: infinite; animation-timing-function: ease-in-out; }
|
|
14
|
+
.pop { transform-box: fill-box; transform-origin: center; }
|
|
15
|
+
.mono { font-family: 'JetBrains Mono', 'SF Mono', Menlo, Consolas, monospace; }
|
|
16
|
+
.loop { animation-name: loop; }
|
|
17
|
+
.req1 { animation-name: req1; }
|
|
18
|
+
.p1 { animation-name: p1; }
|
|
19
|
+
.p1-h { animation-name: p1-h; }
|
|
20
|
+
.sub { animation-name: sub; }
|
|
21
|
+
.req2 { animation-name: req2; }
|
|
22
|
+
.p2 { animation-name: p2; }
|
|
23
|
+
.dot { animation-name: dot; }
|
|
24
|
+
.dedup { animation-name: dedup; }
|
|
25
|
+
.note { animation-name: note; }
|
|
26
|
+
.intent { animation-name: intent; }
|
|
27
|
+
.p3 { animation-name: p3; }
|
|
28
|
+
.p3-h { animation-name: p3-h; }
|
|
29
|
+
.api { animation-name: api; }
|
|
30
|
+
.p4 { animation-name: p4; }
|
|
31
|
+
.crash { animation-name: crash; }
|
|
32
|
+
.maybe { animation-name: maybe; }
|
|
33
|
+
.p5 { animation-name: p5; }
|
|
34
|
+
.ret { animation-name: ret; }
|
|
35
|
+
.ret-h { animation-name: ret-h; }
|
|
36
|
+
.why1 { animation-name: why1; }
|
|
37
|
+
.why2 { animation-name: why2; }
|
|
38
|
+
.why3 { animation-name: why3; }
|
|
39
|
+
.saved { animation-name: saved; }
|
|
40
|
+
@keyframes loop { 0%, 96% { opacity: 1 } 99%, 100% { opacity: 0 } }
|
|
41
|
+
@keyframes req1 { 0%, 2% { opacity: 0 } 5%, 100% { opacity: 1 } }
|
|
42
|
+
@keyframes p1 { 0%, 5% { stroke-dashoffset: 396 } 10%, 100% { stroke-dashoffset: 0 } }
|
|
43
|
+
@keyframes p1-h { 0%, 9.5% { opacity: 0 } 10.5%, 100% { opacity: 1 } }
|
|
44
|
+
@keyframes sub { 0%, 10% { opacity: 0; transform: scale(.9) } 13% { opacity: 1; transform: scale(1) } 24.5% { transform: scale(1) } 25.5% { transform: scale(1.05) } 27%, 100% { opacity: 1; transform: scale(1) } }
|
|
45
|
+
@keyframes req2 { 0%, 16% { opacity: 0 } 19%, 100% { opacity: 1 } }
|
|
46
|
+
@keyframes p2 { 0%, 19% { stroke-dashoffset: 300 } 24%, 100% { stroke-dashoffset: 0 } }
|
|
47
|
+
@keyframes dot { 0%, 23.5% { opacity: 0 } 24.5%, 100% { opacity: 1 } }
|
|
48
|
+
@keyframes dedup { 0%, 24.5% { opacity: 0 } 27%, 100% { opacity: 1 } }
|
|
49
|
+
@keyframes note { 0%, 27.5% { opacity: 0 } 30.5%, 100% { opacity: 1 } }
|
|
50
|
+
@keyframes intent { 0%, 33% { opacity: 0 } 36%, 100% { opacity: 1 } }
|
|
51
|
+
@keyframes p3 { 0%, 36% { stroke-dashoffset: 62 } 38.5%, 100% { stroke-dashoffset: 0 } }
|
|
52
|
+
@keyframes p3-h { 0%, 38% { opacity: 0 } 39%, 100% { opacity: 1 } }
|
|
53
|
+
@keyframes api { 0%, 38.5% { opacity: 0 } 41.5%, 100% { opacity: 1 } }
|
|
54
|
+
@keyframes p4 { 0%, 42% { stroke-dashoffset: 142 } 44.5%, 100% { stroke-dashoffset: 0 } }
|
|
55
|
+
@keyframes crash { 0%, 44.5% { opacity: 0; transform: scale(1.8) } 45.5% { opacity: 1; transform: scale(1) } 46.2% { opacity: .25 } 46.9% { opacity: 1 } 47.6% { opacity: .25 } 48.3%, 100% { opacity: 1; transform: scale(1) } }
|
|
56
|
+
@keyframes maybe { 0%, 47% { opacity: 0 } 49.5%, 100% { opacity: 1 } }
|
|
57
|
+
@keyframes p5 { 0%, 41% { opacity: 0 } 43%, 100% { opacity: 1 } }
|
|
58
|
+
@keyframes ret { 0%, 50% { stroke-dashoffset: 818 } 56%, 100% { stroke-dashoffset: 0 } }
|
|
59
|
+
@keyframes ret-h { 0%, 55.5% { opacity: 0 } 56.5%, 100% { opacity: 1 } }
|
|
60
|
+
@keyframes why1 { 0%, 51% { opacity: 0 } 53%, 100% { opacity: 1 } }
|
|
61
|
+
@keyframes why2 { 0%, 52.5% { opacity: 0 } 54.5%, 100% { opacity: 1 } }
|
|
62
|
+
@keyframes why3 { 0%, 54% { opacity: 0 } 56%, 100% { opacity: 1 } }
|
|
63
|
+
@keyframes saved { 0%, 41% { opacity: 0 } 43%, 56% { opacity: .3 } 58.5%, 100% { opacity: 1 } }
|
|
64
|
+
@media (prefers-reduced-motion: reduce) { * { animation: none !important; } }
|
|
65
|
+
</style>
|
|
66
|
+
|
|
67
|
+
<rect width="1200" height="690" rx="18" fill="#141011"/>
|
|
68
|
+
<text x="48" y="70" font-size="34" font-weight="600" fill="#F3EDEE">Admission and effects are separate</text>
|
|
69
|
+
|
|
70
|
+
<!-- panels -->
|
|
71
|
+
<rect x="48" y="100" width="1104" height="192" rx="12" fill="#21191B" stroke="#443438" stroke-width="2"/>
|
|
72
|
+
<text x="72" y="134" font-size="20" letter-spacing="1" fill="#B9AAAE">ADMISSION</text>
|
|
73
|
+
<rect x="48" y="316" width="1104" height="296" rx="12" fill="#21191B" stroke="#443438" stroke-width="2"/>
|
|
74
|
+
<text x="72" y="350" font-size="20" letter-spacing="1" fill="#B9AAAE">EXTERNAL EFFECTS</text>
|
|
75
|
+
|
|
76
|
+
<g class="loop">
|
|
77
|
+
<!-- admission: one requestId, one submission -->
|
|
78
|
+
<g class="a req1">
|
|
79
|
+
<rect x="72" y="156" width="222" height="48" rx="10" fill="#141011" stroke="#443438" stroke-width="2"/>
|
|
80
|
+
<text class="mono" x="92" y="188" font-size="22" fill="#F3EDEE">requestId r-42</text>
|
|
81
|
+
</g>
|
|
82
|
+
<path class="a p1" d="M298 180 H692" stroke-dasharray="396 396" fill="none" stroke="#FF5252" stroke-width="2.5"/>
|
|
83
|
+
<path class="a p1-h" d="M298 180 H692" fill="none" stroke="none" marker-end="url(#head-red)"/>
|
|
84
|
+
<g class="a sub pop">
|
|
85
|
+
<rect x="700" y="152" width="280" height="56" rx="10" fill="#2A1A1D" stroke="#FF5252" stroke-width="2.5"/>
|
|
86
|
+
<text x="840" y="188" font-size="22" font-weight="600" letter-spacing="1" fill="#F3EDEE" text-anchor="middle">ONE SUBMISSION</text>
|
|
87
|
+
</g>
|
|
88
|
+
|
|
89
|
+
<g class="a req2">
|
|
90
|
+
<rect x="72" y="220" width="301" height="48" rx="10" fill="#141011" stroke="#443438" stroke-width="2"/>
|
|
91
|
+
<text class="mono" x="92" y="252" font-size="22" fill="#F3EDEE">requestId r-42</text>
|
|
92
|
+
<rect x="291" y="229" width="68" height="30" rx="15" fill="none" stroke="#6B5A5E" stroke-width="1.5"/>
|
|
93
|
+
<text x="325" y="250" font-size="20" fill="#B9AAAE" text-anchor="middle">retry</text>
|
|
94
|
+
</g>
|
|
95
|
+
<path class="a p2" d="M377 244 H610 A10 10 0 0 0 620 234 V185" stroke-dasharray="300 300" fill="none" stroke="#B9AAAE" stroke-width="2.5"/>
|
|
96
|
+
<circle class="a dot" cx="620" cy="180" r="5" fill="#FF5252"/>
|
|
97
|
+
<text class="a dedup" x="596" y="230" font-size="20" fill="#B9AAAE" text-anchor="end">deduplicated</text>
|
|
98
|
+
<text class="a note" x="840" y="240" font-size="20" fill="#B9AAAE" text-anchor="middle">Each requestId is admitted once.</text>
|
|
99
|
+
|
|
100
|
+
<!-- external effects: the call can land, the result can be lost -->
|
|
101
|
+
<g class="a intent">
|
|
102
|
+
<rect x="72" y="404" width="200" height="56" rx="10" fill="#141011" stroke="#443438" stroke-width="2"/>
|
|
103
|
+
<text x="172" y="440" font-size="22" font-weight="600" letter-spacing="1" fill="#F3EDEE" text-anchor="middle">TOOL INTENT</text>
|
|
104
|
+
</g>
|
|
105
|
+
<path class="a p3" d="M280 432 H340" stroke-dasharray="62 62" fill="none" stroke="#B9AAAE" stroke-width="2.5"/>
|
|
106
|
+
<path class="a p3-h" d="M280 432 H340" fill="none" stroke="none" marker-end="url(#head-muted)"/>
|
|
107
|
+
<g class="a api">
|
|
108
|
+
<rect x="348" y="404" width="224" height="56" rx="10" fill="#141011" stroke="#443438" stroke-width="2"/>
|
|
109
|
+
<text x="460" y="440" font-size="22" font-weight="600" letter-spacing="1" fill="#F3EDEE" text-anchor="middle">EXTERNAL API</text>
|
|
110
|
+
</g>
|
|
111
|
+
<path class="a p4" d="M580 432 H720" stroke-dasharray="142 142" fill="none" stroke="#B9AAAE" stroke-width="2.5"/>
|
|
112
|
+
<g class="a crash pop" fill="none" stroke="#FF5252" stroke-width="3.5" stroke-linecap="round">
|
|
113
|
+
<path d="M727 446 L739 418"/>
|
|
114
|
+
<path d="M741 446 L753 418"/>
|
|
115
|
+
</g>
|
|
116
|
+
<text class="a maybe" x="740" y="384" font-size="20" letter-spacing="1" fill="#B9AAAE" text-anchor="middle">EFFECT MAY HAVE HAPPENED</text>
|
|
117
|
+
<path class="a p5" d="M768 432 H904" fill="none" stroke="#B9AAAE" stroke-width="2.5" stroke-dasharray="7 6" marker-end="url(#head-muted)"/>
|
|
118
|
+
<g class="a saved">
|
|
119
|
+
<rect x="912" y="404" width="216" height="56" rx="10" fill="#2A1A1D" stroke="#FF5252" stroke-width="2.5"/>
|
|
120
|
+
<text x="1020" y="440" font-size="22" font-weight="600" letter-spacing="1" fill="#F3EDEE" text-anchor="middle">RESULT SAVED</text>
|
|
121
|
+
</g>
|
|
122
|
+
|
|
123
|
+
<!-- recovery path -->
|
|
124
|
+
<path class="a ret" d="M440 464 V578 A10 10 0 0 0 450 588 H1010 A10 10 0 0 0 1020 578 V468" stroke-dasharray="818 818" fill="none" stroke="#FF5252" stroke-width="2.5"/>
|
|
125
|
+
<path class="a ret-h" d="M1020 478 V468" fill="none" stroke="none" marker-end="url(#head-red)"/>
|
|
126
|
+
<g font-size="22" fill="#B9AAAE">
|
|
127
|
+
<text class="a why1" x="464" y="500">Replay-safe tools rerun.</text>
|
|
128
|
+
<text class="a why2" x="464" y="530">Unsafe tools return an interrupted result.</text>
|
|
129
|
+
<text class="a why3" x="464" y="560">Add your own idempotency key.</text>
|
|
130
|
+
</g>
|
|
131
|
+
</g>
|
|
132
|
+
|
|
133
|
+
<text x="48" y="656" font-size="22" fill="#B9AAAE">Durable means checkpointed, not exactly-once.</text>
|
|
134
|
+
</svg>
|
package/justfile
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Durable Pi. Recipes are grouped by work area under just/<group>/mod.just.
|
|
2
|
+
# Device recipes take an id from dpi-network.yaml; nothing here names a machine.
|
|
3
|
+
set dotenv-load := true
|
|
4
|
+
set shell := ["zsh", "-cu"]
|
|
5
|
+
|
|
6
|
+
# Devices: up, deploy, status, logs, restart
|
|
7
|
+
mod net 'just/net'
|
|
8
|
+
|
|
9
|
+
# This machine's dpi-backend
|
|
10
|
+
mod backend 'just/backend'
|
|
11
|
+
|
|
12
|
+
# Web UI hub on port 4781
|
|
13
|
+
mod hub 'just/hub'
|
|
14
|
+
|
|
15
|
+
# Terminal client for one device
|
|
16
|
+
mod tui 'just/tui'
|
|
17
|
+
|
|
18
|
+
# Unit, UI, device and e2e suites
|
|
19
|
+
mod test 'just/test'
|
|
20
|
+
|
|
21
|
+
# List command groups
|
|
22
|
+
default:
|
|
23
|
+
@just --list
|
|
24
|
+
|
|
25
|
+
# Install dependencies for every network app
|
|
26
|
+
install:
|
|
27
|
+
cd apps/dpi-sdk && npm install --no-audit --no-fund
|
|
28
|
+
cd apps/dpi-backend && npm install --no-audit --no-fund
|
|
29
|
+
cd apps/dpi-playground && npm install --no-audit --no-fund
|
|
30
|
+
cd apps/dpi-tui && npm install --no-audit --no-fund
|
|
31
|
+
|
|
32
|
+
# Type checks and unit tests, every app
|
|
33
|
+
check: test::unit
|
package/package.json
CHANGED
|
@@ -1,6 +1,43 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "my-durable",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.0.2",
|
|
4
|
+
"description": "Durable Pi — the durable agent network: hub web UI, device backend daemon, TUI admin and the shared SDK, packaged as one runnable monorepo install",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/baphuongna/my-durable.git"
|
|
9
|
+
},
|
|
10
|
+
"bugs": {
|
|
11
|
+
"url": "https://github.com/baphuongna/my-durable/issues"
|
|
12
|
+
},
|
|
13
|
+
"homepage": "https://github.com/baphuongna/my-durable#readme",
|
|
14
|
+
"engines": {
|
|
15
|
+
"node": ">=22.0.0"
|
|
16
|
+
},
|
|
17
|
+
"bin": {
|
|
18
|
+
"my-durable-hub": "bin/hub.mjs",
|
|
19
|
+
"my-durable-device": "bin/device.mjs",
|
|
20
|
+
"my-durable-tui": "bin/tui.mjs"
|
|
21
|
+
},
|
|
22
|
+
"scripts": {
|
|
23
|
+
"hub": "tsx apps/dpi-playground/apps/dpi-playground-hub/src/main.ts",
|
|
24
|
+
"device": "tsx apps/dpi-backend/src/main.ts",
|
|
25
|
+
"tui": "tsx apps/dpi-tui/src/main.ts",
|
|
26
|
+
"verify": "node scripts/verify.mjs --phase P2"
|
|
27
|
+
},
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"@earendil-works/chord": "1.3.0",
|
|
30
|
+
"@earendil-works/pi-ai": "1.3.0",
|
|
31
|
+
"@earendil-works/pi-durable": "1.3.0",
|
|
32
|
+
"@earendil-works/pi-tui": "1.3.0",
|
|
33
|
+
"@sinclair/typebox": "0.34.52",
|
|
34
|
+
"dompurify": "^3.2.0",
|
|
35
|
+
"express": "^5.1.0",
|
|
36
|
+
"lucide-vue-next": "^0.468.0",
|
|
37
|
+
"marked": "^17.0.0",
|
|
38
|
+
"tsx": "^4.20.0",
|
|
39
|
+
"vue": "3.5.43",
|
|
40
|
+
"ws": "8.22.0",
|
|
41
|
+
"yaml": "^2.8.0"
|
|
42
|
+
}
|
|
43
|
+
}
|