@hachej/boring-agent 0.1.111 → 0.2.0
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/LICENSE +1 -1
- package/README.md +262 -51
- package/dist/agents.d.ts +75 -0
- package/dist/agents.js +91 -0
- package/dist/approval.d.ts +71 -0
- package/dist/approval.js +126 -0
- package/dist/artifacts.d.ts +53 -0
- package/dist/artifacts.js +129 -0
- package/dist/ask-user.d.ts +40 -0
- package/dist/ask-user.js +134 -0
- package/dist/attachment.d.ts +5 -0
- package/dist/attachment.js +4 -0
- package/dist/browser-task.d.ts +32 -0
- package/dist/browser-task.js +119 -0
- package/dist/chat-transport.d.ts +80 -0
- package/dist/chat-transport.js +306 -0
- package/dist/contracts.d.ts +40 -0
- package/dist/contracts.js +1 -0
- package/dist/conversations.d.ts +136 -0
- package/dist/conversations.js +366 -0
- package/dist/definitions.d.ts +37 -0
- package/dist/definitions.js +99 -0
- package/dist/delivery-input.d.ts +35 -0
- package/dist/delivery-input.js +56 -0
- package/dist/delivery.d.ts +33 -0
- package/dist/delivery.js +154 -0
- package/dist/durable-wait.d.ts +23 -0
- package/dist/durable-wait.js +79 -0
- package/dist/file-convert.d.ts +46 -0
- package/dist/file-convert.js +159 -0
- package/dist/file-guard.d.ts +50 -0
- package/dist/file-guard.js +171 -0
- package/dist/file-types.d.ts +17 -0
- package/dist/file-types.js +95 -0
- package/dist/gateway-provider.d.ts +24 -0
- package/dist/gateway-provider.js +42 -0
- package/dist/git.d.ts +34 -0
- package/dist/git.js +79 -0
- package/dist/harness-pool.d.ts +38 -0
- package/dist/harness-pool.js +134 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +1 -0
- package/dist/json-schema-tool.d.ts +25 -0
- package/dist/json-schema-tool.js +19 -0
- package/dist/memory/optchat-core.d.ts +118 -0
- package/dist/memory/optchat-core.js +317 -0
- package/dist/memory/optchat.d.ts +156 -0
- package/dist/memory/optchat.js +432 -0
- package/dist/mentions.d.ts +56 -0
- package/dist/mentions.js +140 -0
- package/dist/metering.d.ts +183 -0
- package/dist/metering.js +443 -0
- package/dist/model-gateway.d.ts +86 -0
- package/dist/model-gateway.js +241 -0
- package/dist/native-version.d.ts +9 -0
- package/dist/native-version.js +7 -0
- package/dist/native.d.ts +4 -0
- package/dist/native.js +1 -0
- package/dist/presentation.d.ts +17 -0
- package/dist/presentation.js +39 -0
- package/dist/projection-format.d.ts +68 -0
- package/dist/projection-format.js +118 -0
- package/dist/projection-window.d.ts +9 -0
- package/dist/projection-window.js +93 -0
- package/dist/projection.d.ts +22 -0
- package/dist/projection.js +153 -0
- package/dist/question-response.d.ts +20 -0
- package/dist/question-response.js +75 -0
- package/dist/questions.d.ts +74 -0
- package/dist/questions.js +199 -0
- package/dist/self-evolving.d.ts +55 -0
- package/dist/self-evolving.js +239 -0
- package/dist/skills.d.ts +15 -0
- package/dist/skills.js +51 -0
- package/dist/tool-evidence.d.ts +14 -0
- package/dist/tool-evidence.js +54 -0
- package/dist/validation.d.ts +38 -0
- package/dist/validation.js +68 -0
- package/dist/workspaces.d.ts +107 -0
- package/dist/workspaces.js +212 -0
- package/package.json +145 -150
- package/dist/DebugDrawer-JNA43SVR.js +0 -8
- package/dist/admin-DORVQfLn.d.ts +0 -340
- package/dist/chunk-2BGLZZ7T.js +0 -10
- package/dist/chunk-42D6KAQV.js +0 -2882
- package/dist/chunk-4XOW57KJ.js +0 -343
- package/dist/chunk-72KT6VWV.js +0 -1338
- package/dist/chunk-7XAOVFSN.js +0 -28
- package/dist/chunk-KJIEMSQP.js +0 -198
- package/dist/chunk-KN72XWP7.js +0 -394
- package/dist/chunk-N6THTH7P.js +0 -110
- package/dist/chunk-V3H5A3BR.js +0 -22501
- package/dist/chunk-YGRQ4Q5P.js +0 -20
- package/dist/chunk-YTUZFKB3.js +0 -78
- package/dist/core/index.d.ts +0 -28
- package/dist/core/index.js +0 -617
- package/dist/createHarness-DOLOHA62.js +0 -18
- package/dist/eval/index.d.ts +0 -247
- package/dist/eval/index.js +0 -541
- package/dist/file-search-BUgMSKZE.d.ts +0 -289
- package/dist/front/artifacts.d.ts +0 -34
- package/dist/front/artifacts.js +0 -21
- package/dist/front/index.d.ts +0 -1082
- package/dist/front/index.js +0 -12912
- package/dist/front/styles.css +0 -5380
- package/dist/harness-qHlMJhZo.d.ts +0 -276
- package/dist/middleware-CaAEXpi5.d.ts +0 -115
- package/dist/piChatEvent-DpE0lIb9.d.ts +0 -450
- package/dist/piChatSessionService-CBct-hmz.d.ts +0 -86
- package/dist/sandbox-BMhut3kh.d.ts +0 -317
- package/dist/server/agent-host/testing/compositionRouteProof.d.ts +0 -8
- package/dist/server/agent-host/testing/compositionRouteProof.js +0 -78
- package/dist/server/agent-host/testing/gatewayConformance.d.ts +0 -43
- package/dist/server/agent-host/testing/gatewayConformance.js +0 -605
- package/dist/server/index.d.ts +0 -2278
- package/dist/server/index.js +0 -274
- package/dist/server/pi-session-readability.d.ts +0 -12
- package/dist/server/pi-session-readability.js +0 -23
- package/dist/server/worker/index.d.ts +0 -68
- package/dist/server/worker/index.js +0 -377
- package/dist/share-entry-CxS6UJ_L.d.ts +0 -330
- package/dist/shared/index.d.ts +0 -2111
- package/dist/shared/index.js +0 -262
- package/dist/types-DcWoQMn8.d.ts +0 -1377
- package/docs/ACCESSIBILITY.md +0 -52
- package/docs/AGENT_GATEWAY_V0.md +0 -212
- package/docs/AGENT_PACKAGES.md +0 -90
- package/docs/API.md +0 -123
- package/docs/AUTHORING.md +0 -68
- package/docs/CSP.md +0 -41
- package/docs/ERROR_CODES.md +0 -229
- package/docs/KNOWN_LIMITATIONS.md +0 -100
- package/docs/MIGRATION.md +0 -50
- package/docs/PERFORMANCE.md +0 -68
- package/docs/PLUGINS.md +0 -138
- package/docs/README.md +0 -98
- package/docs/RISKS-MULTI-TAB.md +0 -46
- package/docs/SESSION_IDENTITY.md +0 -91
- package/docs/STYLING.md +0 -73
- package/docs/UI-SHADCN.md +0 -56
- package/docs/VERCEL_COSTS.md +0 -103
- package/docs/plans/archive/AGENT_EVAL_FRAMEWORK.md +0 -466
- package/docs/plans/archive/agent-package-spec.md +0 -1777
- package/docs/plans/archive/harness-followup-capabilities.md +0 -440
- package/docs/plans/archive/harness-tool-ui-capabilities.md +0 -144
- package/docs/plans/archive/pi-followup-history-projection.md +0 -229
- package/docs/plans/archive/pi-tools-migration.md +0 -1061
- package/docs/plans/archive/reviews/pi-followup-history-codex-review.md +0 -11
- package/docs/plans/archive/reviews/pi-followup-history-gpt-review.md +0 -64
- package/docs/plans/archive/reviews/pi-followup-history-opus-review.md +0 -43
- package/docs/plans/archive/reviews/pi-followup-history-xai-review.md +0 -43
- package/docs/plans/archive/vercel-base-snapshot-template-plan.md +0 -527
- package/docs/plans/archive/vercel-persistent-sandbox-adapter.md +0 -553
- package/docs/runtime-provisioning.md +0 -157
- package/docs/runtime.md +0 -296
- package/docs/tools.md +0 -102
package/docs/README.md
DELETED
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
# @hachej/boring-agent Docs
|
|
2
|
-
|
|
3
|
-
`@hachej/boring-agent` is a pane-embeddable coding agent: an LLM agent loop, a
|
|
4
|
-
tool catalog, and a chat UI, with swappable execution backends. The same agent,
|
|
5
|
-
tools, and UI run in three modes — `direct` (host process), `local` (bwrap
|
|
6
|
-
sandbox), and `vercel-sandbox` (Firecracker microVM) — selected at construction.
|
|
7
|
-
It is consumed two ways: standalone via `createAgentApp` (Fastify server +
|
|
8
|
-
`ChatPanel`), or mounted into `@hachej/boring-workspace` for the full IDE shell.
|
|
9
|
-
|
|
10
|
-
## Architecture
|
|
11
|
-
|
|
12
|
-
```
|
|
13
|
-
Chat UI (ChatPanel / front)
|
|
14
|
-
│ pi-chat SSE stream
|
|
15
|
-
Agent HTTP routes (registerAgentRoutes / createAgentApp)
|
|
16
|
-
│
|
|
17
|
-
Agent harness (pi-coding-agent loop) ── Tool catalog (AgentTool[])
|
|
18
|
-
│ │
|
|
19
|
-
Workspace (filesystem) Sandbox (command execution)
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
- **front** (`src/front`) — `ChatPanel` (= `PiChatPanel`), primitives, slash
|
|
23
|
-
commands, tool renderers, session hooks. Browser-only.
|
|
24
|
-
- **server** (`src/server`) — `createAgentApp`, `registerAgentRoutes`, the Pi
|
|
25
|
-
harness adapter, sandbox/workspace adapters, runtime provisioning, model
|
|
26
|
-
config, HTTP routes. Node-only.
|
|
27
|
-
- **shared** (`src/shared`) — platform-agnostic contracts and zod schemas
|
|
28
|
-
(`AgentHarness`, `Workspace`, `Sandbox`, `AgentTool`, `SessionStore`, chat
|
|
29
|
-
frames, error codes).
|
|
30
|
-
- **eval** (`src/eval`) — agent-behavior evaluation toolkit.
|
|
31
|
-
|
|
32
|
-
Data flow: the browser opens a pi-chat SSE stream; the server drives the
|
|
33
|
-
pi-coding-agent harness; tools resolve filesystem ops through the `Workspace`
|
|
34
|
-
adapter and shell/exec through the `Sandbox` adapter. Workspace + Sandbox must
|
|
35
|
-
target the same filesystem substrate (the mode adapter enforces the pairing).
|
|
36
|
-
|
|
37
|
-
## Key abstractions
|
|
38
|
-
|
|
39
|
-
The public surfaces a consumer or extender touches (all in
|
|
40
|
-
`@hachej/boring-agent/shared` unless noted):
|
|
41
|
-
|
|
42
|
-
- `AgentHarness` — the agent loop interface; pi-coding-agent is the v1 impl.
|
|
43
|
-
- `Workspace` / `Sandbox` — filesystem and command-execution adapters, swapped
|
|
44
|
-
per mode.
|
|
45
|
-
- `AgentTool` + `CatalogDeps` — the tool contract and the deps tools bind to.
|
|
46
|
-
- `SessionStore` — session listing/lifecycle.
|
|
47
|
-
- `createAgentApp` / `registerAgentRoutes` (`/server`) — entry points to run or
|
|
48
|
-
embed the server.
|
|
49
|
-
- `ChatPanel` (`/front`) — the embeddable UI.
|
|
50
|
-
|
|
51
|
-
## Architectural decisions
|
|
52
|
-
|
|
53
|
-
Locked decisions live in the root [`docs/DECISIONS.md`](../../../docs/DECISIONS.md);
|
|
54
|
-
the agent ↔ workspace boundary is in
|
|
55
|
-
[`docs/WORKSPACE_CONTRACT.md`](../../../docs/WORKSPACE_CONTRACT.md). Highlights:
|
|
56
|
-
|
|
57
|
-
- Standalone CLI-shaped product; same code embeds into a host shell — decision 1.
|
|
58
|
-
- pi-coding-agent as the v1 harness behind a generic `AgentHarness` — decisions 4–5.
|
|
59
|
-
- `mode = direct | local | vercel-sandbox`; Workspace+Sandbox pairing invariant — decisions 7a–7f.
|
|
60
|
-
- Single Anthropic provider by default, but the model layer also supports custom
|
|
61
|
-
OpenAI-compatible and Infomaniak providers — decision 10.
|
|
62
|
-
- Plugins extend via Pi resources or trusted server plugins, not core edits — decision 8.
|
|
63
|
-
- Four export surfaces: top-level/`front`, `/server`, `/shared`, `/eval` — decision 15.
|
|
64
|
-
|
|
65
|
-
## Documentation
|
|
66
|
-
|
|
67
|
-
**Surfaces & integration**
|
|
68
|
-
|
|
69
|
-
- [API](./API.md) — the four entry points and what each exports.
|
|
70
|
-
- [AUTHORING](./AUTHORING.md) — declarative agent directories, bounds, validation, and legacy catalog migration.
|
|
71
|
-
- [AGENT_PACKAGES](./AGENT_PACKAGES.md) — install, seat, update, unseat, and remove plugin-shaped agent packages in a workspace.
|
|
72
|
-
- [STYLING](./STYLING.md) — CSS-variable theming contract and public selectors.
|
|
73
|
-
- [UI-SHADCN](./UI-SHADCN.md) — `ChatPanel` styling model and tool-renderer overrides.
|
|
74
|
-
- [tools](./tools.md) — built-in tools, package-added tools, and how to add custom tools.
|
|
75
|
-
- [PLUGINS](./PLUGINS.md) — the two extension paths and tool-collision rules.
|
|
76
|
-
- [MIGRATION](./MIGRATION.md) — moving legacy integrations to the v2 split.
|
|
77
|
-
|
|
78
|
-
**Runtime & provisioning**
|
|
79
|
-
|
|
80
|
-
- [runtime](./runtime.md) — the three modes, the cwd invariant, and `.boring-agent/` layout.
|
|
81
|
-
- [runtime-provisioning](./runtime-provisioning.md) — when provisioning runs, package-authoring shape, trusted server provisioning.
|
|
82
|
-
|
|
83
|
-
**Contracts & operations**
|
|
84
|
-
|
|
85
|
-
- [SESSION_IDENTITY](./SESSION_IDENTITY.md) — durable session stream key, owner attributes, and v1→v2 migration contract.
|
|
86
|
-
- [ERROR_CODES](./ERROR_CODES.md) — the stable API error-code registry.
|
|
87
|
-
- [CSP](./CSP.md) — Content-Security-Policy compatibility.
|
|
88
|
-
- [ACCESSIBILITY](./ACCESSIBILITY.md) — a11y coverage and known gaps.
|
|
89
|
-
|
|
90
|
-
**Risk & cost notes**
|
|
91
|
-
|
|
92
|
-
- [KNOWN_LIMITATIONS](./KNOWN_LIMITATIONS.md) — accepted risks (orphaned sandboxes, deferred git routes).
|
|
93
|
-
- [RISKS-MULTI-TAB](./RISKS-MULTI-TAB.md) — last-write-wins behavior for concurrent edits.
|
|
94
|
-
- [VERCEL_COSTS](./VERCEL_COSTS.md) — Vercel sandbox cost model.
|
|
95
|
-
- [PERFORMANCE](./PERFORMANCE.md) — historical Vercel cold-start benchmark.
|
|
96
|
-
|
|
97
|
-
Historical plans and specs live under `docs/plans/archive/` — archival context only, not
|
|
98
|
-
current truth; verify against code before relying on them.
|
package/docs/RISKS-MULTI-TAB.md
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
# Multi-Tab Concurrency Risk
|
|
2
|
-
|
|
3
|
-
## Scope
|
|
4
|
-
|
|
5
|
-
This note documents current `@hachej/boring-agent` behavior when two browser tabs
|
|
6
|
-
point at the same workspace and edit the same file.
|
|
7
|
-
|
|
8
|
-
## Observed Behavior (v1)
|
|
9
|
-
|
|
10
|
-
- There is no workspace-level lock and no per-file lock.
|
|
11
|
-
- `POST /api/v1/files` performs an unconditional write.
|
|
12
|
-
- There is no optimistic concurrency precondition (no ETag/version check,
|
|
13
|
-
no `If-Match` handling).
|
|
14
|
-
- Result: writes are silent last-write-wins. A stale tab can overwrite a newer
|
|
15
|
-
edit without a conflict response.
|
|
16
|
-
|
|
17
|
-
This is visible in route code:
|
|
18
|
-
- [file.ts](../src/server/http/routes/file.ts) calls `workspace.writeFile(...)`
|
|
19
|
-
directly.
|
|
20
|
-
- [createNodeWorkspace.ts](../../boring-sandbox/src/providers/node-workspace/createNodeWorkspace.ts)
|
|
21
|
-
calls Node `writeFile(...)` without revision guards.
|
|
22
|
-
|
|
23
|
-
Behavior is exercised by:
|
|
24
|
-
- [file.test.ts](../src/server/http/routes/__tests__/file.test.ts)
|
|
25
|
-
`multi-tab stale write overwrites newer content (last write wins)`.
|
|
26
|
-
|
|
27
|
-
## Session Semantics
|
|
28
|
-
|
|
29
|
-
- Tabs are not treated as exclusive owners of a workspace.
|
|
30
|
-
- Session identity is driven by `sessionId`; multiple tabs can operate against
|
|
31
|
-
the same workspace concurrently.
|
|
32
|
-
|
|
33
|
-
## Known User Impact
|
|
34
|
-
|
|
35
|
-
- Lost-update risk for simultaneous edits on the same path.
|
|
36
|
-
- No explicit error or merge prompt when overwrite happens.
|
|
37
|
-
|
|
38
|
-
## Future Mitigation Seam
|
|
39
|
-
|
|
40
|
-
Introduce optimistic write preconditions:
|
|
41
|
-
|
|
42
|
-
1. `GET /api/v1/files` returns a version token (for example ETag/content hash +
|
|
43
|
-
mtime).
|
|
44
|
-
2. `POST /api/v1/files` accepts `If-Match` and rejects mismatched versions with
|
|
45
|
-
`409 Conflict`.
|
|
46
|
-
3. Frontend handles `409` with refresh/retry UX instead of silent overwrite.
|
package/docs/SESSION_IDENTITY.md
DELETED
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
# Session stream identity
|
|
2
|
-
|
|
3
|
-
This contract governs durable agent event-stream addressing. The code in
|
|
4
|
-
`src/shared/events.ts` is authoritative when this document and the
|
|
5
|
-
implementation disagree.
|
|
6
|
-
|
|
7
|
-
## Durable key
|
|
8
|
-
|
|
9
|
-
A session stream is keyed by `(workspaceScopeId, sessionId)`. Its path is:
|
|
10
|
-
|
|
11
|
-
```text
|
|
12
|
-
sessions/<enc(workspaceScopeId)>/<enc(sessionId)>
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
`enc` percent-encodes every byte outside `[A-Za-z0-9._-]`, using uppercase
|
|
16
|
-
hex. Both fields are opaque, non-empty, well-formed Unicode strings; session
|
|
17
|
-
ids need not be UUIDs.
|
|
18
|
-
`sessionStreamPath(identity)` is the only constructor and
|
|
19
|
-
`parseSessionStreamPath(path)` accepts only the canonical encoding.
|
|
20
|
-
The value helpers are server-internal and are not exported from the package's
|
|
21
|
-
shared public barrel; only the `SessionStreamIdentity` type is public there.
|
|
22
|
-
|
|
23
|
-
The process-local Pi cache may still use a JSON tuple, but it is not a durable
|
|
24
|
-
key. Gateway host maps use `(workspaceScopeId, agentTypeId, sessionId)`, and
|
|
25
|
-
Pi transcript directories use their existing agent and workspace namespace.
|
|
26
|
-
Neither grammar may be embedded into a durable stream path.
|
|
27
|
-
|
|
28
|
-
When no event store is configured, legacy/headless callers may omit
|
|
29
|
-
`workspaceId`. The service preserves their pre-durability JSON cache key and
|
|
30
|
-
never constructs or validates a durable path. Once an event store is present,
|
|
31
|
-
both identity fields are required and invalid identity or durable-read errors
|
|
32
|
-
surface instead of being treated as a missing transcript.
|
|
33
|
-
|
|
34
|
-
## Owner attributes
|
|
35
|
-
|
|
36
|
-
`boring_event_stream_owners` stores one row for each addressed session stream:
|
|
37
|
-
|
|
38
|
-
- `path` is the primary key.
|
|
39
|
-
- `workspace_scope_id` and `session_id` repeat the durable identity and are
|
|
40
|
-
indexed together.
|
|
41
|
-
- `agent_type_id` is required for newly opened channels but is an attribute,
|
|
42
|
-
not part of the stream key.
|
|
43
|
-
- `auth_subject_id` is execution attribution, never ownership.
|
|
44
|
-
- `seat_id` and `thread_id` are reserved nullable columns; A1 defines no
|
|
45
|
-
semantics or foreign keys for them.
|
|
46
|
-
- `key_version` is `2` for streams created with this grammar and `1` for
|
|
47
|
-
migrated rows.
|
|
48
|
-
|
|
49
|
-
There is deliberately no foreign key. SQLite foreign-key enforcement is not
|
|
50
|
-
enabled on this connection; migration validation and store transactions enforce
|
|
51
|
-
the relationship instead.
|
|
52
|
-
|
|
53
|
-
`auth_subject_id` uses first-writer semantics: the first successful
|
|
54
|
-
`createSessionStream` claim records it, and later opens do not replace it.
|
|
55
|
-
This is attribution for the opening execution, not a durable authorization or
|
|
56
|
-
ownership decision.
|
|
57
|
-
|
|
58
|
-
## Schema v1 to v2
|
|
59
|
-
|
|
60
|
-
Opening a v1 database runs one `BEGIN IMMEDIATE` migration. It preflights every
|
|
61
|
-
old stream into `boring_event_stream_migration_v2` by parent `rowid`, raw
|
|
62
|
-
`path`, and `typeof(path)`, validates unique targets, every parent's path and
|
|
63
|
-
metadata, per-stream row counts and maximum sequence values, every owner row,
|
|
64
|
-
and every child row before swapping paths across all three event tables.
|
|
65
|
-
|
|
66
|
-
The collision rules are exhaustive:
|
|
67
|
-
|
|
68
|
-
1. A single old row rekeys to its v2 path.
|
|
69
|
-
2. For an empty-user row colliding with user-bearing rows, the empty-user row
|
|
70
|
-
wins and the others are quarantined.
|
|
71
|
-
3. If several user-bearing rows collide without an empty-user row, all are
|
|
72
|
-
quarantined because their sequence spaces cannot be merged safely.
|
|
73
|
-
4. Non-matching, malformed, or otherwise ambiguous old paths are quarantined.
|
|
74
|
-
|
|
75
|
-
Legacy identities containing ill-formed Unicode are quarantined with reason
|
|
76
|
-
`unencodable-identity`. Non-TEXT parent paths (including SQL `NULL`) use a
|
|
77
|
-
rowid-safe quarantine destination; their raw original value/type remains in
|
|
78
|
-
the manifest. No encoding failure aborts migration of the remaining rows.
|
|
79
|
-
|
|
80
|
-
Ordinary quarantine destinations are `quarantine/v1/<enc(oldPath)>`; rowid-safe
|
|
81
|
-
destinations cover values that cannot be encoded. Rows are never dropped. The
|
|
82
|
-
swap is validated again before `schema_version` becomes `2`.
|
|
83
|
-
Concurrent openers serialize on the immediate transaction, re-read the version
|
|
84
|
-
under the lock, and only one migrates. A migrated owner has
|
|
85
|
-
`agent_type_id = NULL` until the next legitimate channel open backfills it from
|
|
86
|
-
the composition's explicit agent type.
|
|
87
|
-
|
|
88
|
-
The migration is a rollback fence, not a reversible downgrade. Disable
|
|
89
|
-
`BORING_CHAT_DURABLE_STREAM` before running an old binary; an old binary pointed
|
|
90
|
-
at a v2 file refuses it with `EventStreamSchemaVersionError` rather than writing
|
|
91
|
-
mixed path grammars.
|
package/docs/STYLING.md
DELETED
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
# STYLING
|
|
2
|
-
|
|
3
|
-
Styling contract for `@hachej/boring-agent` frontend surfaces. For the full
|
|
4
|
-
agent/workspace Tailwind isolation model, see
|
|
5
|
-
[`docs/TAILWIND-V4-STYLE-ISOLATION.md`](../../../docs/TAILWIND-V4-STYLE-ISOLATION.md).
|
|
6
|
-
|
|
7
|
-
## Package CSS
|
|
8
|
-
|
|
9
|
-
Consumers import the precompiled package stylesheet once, after host/workspace
|
|
10
|
-
base CSS and before app overrides:
|
|
11
|
-
|
|
12
|
-
```ts
|
|
13
|
-
import "@hachej/boring-workspace/globals.css"
|
|
14
|
-
import "@hachej/boring-agent/front/styles.css"
|
|
15
|
-
import "./app.css"
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
The published `@hachej/boring-agent/front/styles.css` is consumer-safe: it contains no
|
|
19
|
-
Tailwind `@source`, no Tailwind imports, and no repo-relative source paths.
|
|
20
|
-
|
|
21
|
-
## Public selectors
|
|
22
|
-
|
|
23
|
-
Agent surfaces expose a package namespace root and stable part attributes:
|
|
24
|
-
|
|
25
|
-
```css
|
|
26
|
-
[data-boring-agent] {}
|
|
27
|
-
[data-boring-agent-part="chat"] {}
|
|
28
|
-
[data-boring-agent-part="composer"] {}
|
|
29
|
-
[data-boring-agent-part="tool-card"] {}
|
|
30
|
-
[data-boring-agent-message-role="assistant"] {}
|
|
31
|
-
[data-boring-state="selected"] {}
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
`data-boring-agent-*` is the public selector namespace for agent UI. Workspace
|
|
35
|
-
uses `data-boring-workspace-*`; do not style agent internals through workspace
|
|
36
|
-
selectors.
|
|
37
|
-
|
|
38
|
-
## Token contract
|
|
39
|
-
|
|
40
|
-
Workspace owns the public visual tokens (`--boring-*`). Agent consumes those
|
|
41
|
-
host tokens and provides standalone fallbacks under `[data-boring-agent]`.
|
|
42
|
-
|
|
43
|
-
Common tokens:
|
|
44
|
-
|
|
45
|
-
- `--boring-background`
|
|
46
|
-
- `--boring-foreground`
|
|
47
|
-
- `--boring-card`
|
|
48
|
-
- `--boring-muted`
|
|
49
|
-
- `--boring-muted-foreground`
|
|
50
|
-
- `--boring-accent`
|
|
51
|
-
- `--boring-border`
|
|
52
|
-
- `--boring-radius`
|
|
53
|
-
- `--boring-font-sans`
|
|
54
|
-
- `--boring-font-mono`
|
|
55
|
-
|
|
56
|
-
Example app override:
|
|
57
|
-
|
|
58
|
-
```css
|
|
59
|
-
[data-boring-agent-part="composer"] {
|
|
60
|
-
--boring-accent: oklch(0.64 0.18 250);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
[data-boring-agent-message-role="assistant"] {
|
|
64
|
-
--boring-card: oklch(0.98 0.01 250);
|
|
65
|
-
}
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
## Invariants
|
|
69
|
-
|
|
70
|
-
- Keep reusable primitives driven by semantic CSS variables and public data
|
|
71
|
-
attributes, not package-internal DOM structure.
|
|
72
|
-
- Keep styling decisions out of `src/shared/**` and server runtime modules.
|
|
73
|
-
- Published package CSS must remain precompiled and consumer-safe.
|
package/docs/UI-SHADCN.md
DELETED
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
# Agent UI
|
|
2
|
-
|
|
3
|
-
`@hachej/boring-agent` exports the pane-embeddable `ChatPanel` and its frontend
|
|
4
|
-
primitives. The default styled surface is packaged with precompiled CSS.
|
|
5
|
-
|
|
6
|
-
## Quickstart
|
|
7
|
-
|
|
8
|
-
```tsx
|
|
9
|
-
import "@hachej/boring-workspace/globals.css"
|
|
10
|
-
import "@hachej/boring-agent/front/styles.css"
|
|
11
|
-
import { ChatPanel } from "@hachej/boring-agent"
|
|
12
|
-
|
|
13
|
-
function App() {
|
|
14
|
-
return <ChatPanel sessionId="my-session" />
|
|
15
|
-
}
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
Import app overrides after the package CSS when customizing:
|
|
19
|
-
|
|
20
|
-
```ts
|
|
21
|
-
import "@hachej/boring-workspace/globals.css"
|
|
22
|
-
import "@hachej/boring-agent/front/styles.css"
|
|
23
|
-
import "./app.css"
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
## Styling model
|
|
27
|
-
|
|
28
|
-
| Concern | Contract |
|
|
29
|
-
|---|---|
|
|
30
|
-
| Package CSS | `@hachej/boring-agent/front/styles.css` |
|
|
31
|
-
| Root selector | `[data-boring-agent]` |
|
|
32
|
-
| Parts | `[data-boring-agent-part="composer"]`, `[data-boring-agent-part="tool-card"]`, etc. |
|
|
33
|
-
| Message role | `[data-boring-agent-message-role="assistant"]` |
|
|
34
|
-
| State | `[data-boring-state="selected"]`, `[data-boring-state="disabled"]`, etc. |
|
|
35
|
-
| Tokens | Consumes host `--boring-*` tokens with standalone fallbacks |
|
|
36
|
-
|
|
37
|
-
The built stylesheet has no Tailwind `@source` directives, no Tailwind imports,
|
|
38
|
-
and no repo-relative source paths.
|
|
39
|
-
|
|
40
|
-
## Dark mode
|
|
41
|
-
|
|
42
|
-
Add `class="dark"` to an ancestor. Workspace owns the dark `--boring-*` token
|
|
43
|
-
values; agent inherits them and falls back when embedded standalone.
|
|
44
|
-
|
|
45
|
-
## Custom tool renderers
|
|
46
|
-
|
|
47
|
-
Same API as `ChatPanel`:
|
|
48
|
-
|
|
49
|
-
```tsx
|
|
50
|
-
<ChatPanel
|
|
51
|
-
sessionId="sess"
|
|
52
|
-
toolRenderers={{
|
|
53
|
-
write: ({ toolCall }) => <div>Wrote {toolCall.input.path}</div>,
|
|
54
|
-
}}
|
|
55
|
-
/>
|
|
56
|
-
```
|
package/docs/VERCEL_COSTS.md
DELETED
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
# Vercel Sandbox Cost Model
|
|
2
|
-
|
|
3
|
-
Date: 2026-04-23
|
|
4
|
-
|
|
5
|
-
## Inputs
|
|
6
|
-
|
|
7
|
-
### Pricing + limits (official)
|
|
8
|
-
|
|
9
|
-
Source: Vercel Sandbox pricing and limits (last updated March 14, 2026):
|
|
10
|
-
<https://vercel.com/docs/vercel-sandbox/pricing>
|
|
11
|
-
|
|
12
|
-
| Metric | Rate / Limit |
|
|
13
|
-
|---|---|
|
|
14
|
-
| Active CPU | `$0.128 / vCPU-hour` |
|
|
15
|
-
| Provisioned Memory | `$0.0212 / GB-hour` |
|
|
16
|
-
| Sandbox creations | `$0.60 / 1M` (`$0.0000006 / create`) |
|
|
17
|
-
| Data transfer | `$0.15 / GB` |
|
|
18
|
-
| Snapshot storage | `$0.08 / GB-month` |
|
|
19
|
-
| Default vCPU | `2` |
|
|
20
|
-
| Memory per vCPU | `2 GB` |
|
|
21
|
-
| Max runtime | Hobby `45 min`, Pro/Enterprise `5h` |
|
|
22
|
-
| vCPU allocation rate limit | Hobby `40 vCPU / 10 min`, Pro `200 / min`, Ent `400 / min` |
|
|
23
|
-
|
|
24
|
-
Snapshot defaults (official):
|
|
25
|
-
- <https://vercel.com/docs/vercel-sandbox/concepts/snapshots>
|
|
26
|
-
- Default snapshot expiration is `30 days` unless configured otherwise.
|
|
27
|
-
|
|
28
|
-
### Measured workload inputs (this repo)
|
|
29
|
-
|
|
30
|
-
- Cold-start benchmark (`96h`): [PERFORMANCE.md](./PERFORMANCE.md)
|
|
31
|
-
- FS + exec latency benchmark (`f4f`): historical raw JSON artifact removed; see the root `docs/PERFORMANCE.md` rollup.
|
|
32
|
-
- Measured snapshot sizes from benchmark project: ~`279 MB` each (`0.2606 GB`).
|
|
33
|
-
|
|
34
|
-
Observations:
|
|
35
|
-
- 96h: cold-start p95 is below `3s`, so we do not need a large warm pool to hide startup.
|
|
36
|
-
- f4f + 96h traces are I/O-heavy; CPU-active share is much lower than wall-clock. Model uses `30%` CPU-active as the baseline.
|
|
37
|
-
|
|
38
|
-
## Model
|
|
39
|
-
|
|
40
|
-
For one workspace/day:
|
|
41
|
-
|
|
42
|
-
```text
|
|
43
|
-
daily_cost =
|
|
44
|
-
(active_cpu_vcpu_hours * 0.128) +
|
|
45
|
-
(memory_gb * wall_clock_hours * 0.0212) +
|
|
46
|
-
(creates_per_day * 0.0000006) +
|
|
47
|
-
(snapshot_gb * snapshots_kept * 0.08 / 30)
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
Baseline assumptions used below:
|
|
51
|
-
- `2 vCPU`, `4 GB` memory.
|
|
52
|
-
- one active user session/day: `30 min` wall-clock, `30%` CPU-active.
|
|
53
|
-
- this gives `active_cpu_vcpu_hours = 2 * 0.5 * 0.3 = 0.3` vCPU-hours/day.
|
|
54
|
-
- `1` creation/day.
|
|
55
|
-
- snapshot retention `keep-last-2`.
|
|
56
|
-
- idle policy changes runtime billed for memory, but not active CPU time.
|
|
57
|
-
|
|
58
|
-
## Cost per Workspace per Day
|
|
59
|
-
|
|
60
|
-
Historical companion CSV artifacts were removed from the package tree; the table below preserves the cost model.
|
|
61
|
-
|
|
62
|
-
| Idle policy | Runtime billed/day | CPU $/day | Memory $/day | Snapshot $/day | Create $/day | Total $/day |
|
|
63
|
-
|---|---:|---:|---:|---:|---:|---:|
|
|
64
|
-
| Stop on session end | 0.5 h | 0.0384 | 0.0424 | 0.0014 | 0.0000006 | **0.0822** |
|
|
65
|
-
| Idle-stop after 60 min | 1.0 h | 0.0384 | 0.0848 | 0.0014 | 0.0000006 | **0.1246** |
|
|
66
|
-
| No explicit stop (5h timeout) | 5.0 h | 0.0384 | 0.4240 | 0.0014 | 0.0000006 | **0.4638** |
|
|
67
|
-
| Pinned 24h workspace | 24.0 h | 0.0384 | 2.0352 | 0.0014 | 0.0000006 | **2.0750** |
|
|
68
|
-
|
|
69
|
-
Implication:
|
|
70
|
-
- Memory wall-clock billing dominates cost. Idle lifetime policy matters far more than creation count.
|
|
71
|
-
|
|
72
|
-
## Snapshot Retention Trade-off
|
|
73
|
-
|
|
74
|
-
With measured snapshot size `0.2606 GB`:
|
|
75
|
-
|
|
76
|
-
| Retention | Storage/workspace/month |
|
|
77
|
-
|---|---:|
|
|
78
|
-
| Keep 1 | `$0.0209` |
|
|
79
|
-
| Keep 2 (current) | `$0.0417` |
|
|
80
|
-
| Keep 5 | `$0.1043` |
|
|
81
|
-
| Keep 10 | `$0.2085` |
|
|
82
|
-
|
|
83
|
-
Conclusion:
|
|
84
|
-
- **Keep-last-2 is still the right default.**
|
|
85
|
-
- Storage cost is tiny at small scale but scales linearly with workspace count.
|
|
86
|
-
|
|
87
|
-
## Idle Pool Sizing
|
|
88
|
-
|
|
89
|
-
If we keep a warm 2 vCPU / 4 GB sandbox running for 24h, per slot:
|
|
90
|
-
- Memory-only floor: `4 GB * 24h * 0.0212 = $2.0352/day`.
|
|
91
|
-
- At 1% CPU-active overhead, total is about `~$2.10/day` per warm slot.
|
|
92
|
-
|
|
93
|
-
Because 96h cold-start p95 is already `<3s`, default should be **no prewarmed idle pool**.
|
|
94
|
-
|
|
95
|
-
## Policy Recommendation
|
|
96
|
-
|
|
97
|
-
1. Keep `BORING_AGENT_SNAPSHOT_KEEP=2` (confirmed).
|
|
98
|
-
2. Stop sandbox proactively on session end; do not rely on timeout.
|
|
99
|
-
3. Add/keep idle-stop guardrail at `<= 60 min` idle.
|
|
100
|
-
4. Add stale-handle cleanup: force destroy after `24h` idle as a safety backstop if stop hooks are missed.
|
|
101
|
-
5. Keep idle pool size at `0` by default; only enable a tiny pool behind feature flag if product latency goals tighten.
|
|
102
|
-
|
|
103
|
-
This policy minimizes spend while keeping current UX targets achievable.
|