@loicngr/kobo 2.1.18 → 2.1.20
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/AGENTS.md +49 -0
- package/CHANGELOG.md +8 -0
- package/CONFIGURATION.md +60 -1
- package/README.md +2 -0
- package/dist/mcp-server/kobo-tasks-server.js +28 -6
- package/dist/mcp-server/progress-bar-client.js +20 -0
- package/dist/mcp-server/workspace-dialogue-client.js +27 -7
- package/dist/server/db/migrations.js +2 -0
- package/dist/server/db/progress-bar-schema.js +27 -0
- package/dist/server/db/schema.js +2 -0
- package/dist/server/index.js +4 -0
- package/dist/server/routes/mcp.js +19 -9
- package/dist/server/routes/progress-bars.js +56 -0
- package/dist/server/routes/workspaces.js +33 -63
- package/dist/server/services/agent/engines/claude-code/engine.js +59 -16
- package/dist/server/services/agent/engines/claude-code/options-builder.js +13 -34
- package/dist/server/services/agent/engines/claude-code/stop-hook.js +8 -27
- package/dist/server/services/agent/engines/codex/engine.js +8 -1
- package/dist/server/services/agent/engines/codex/options-builder.js +11 -16
- package/dist/server/services/agent/orchestrator.js +53 -7
- package/dist/server/services/auto-loop-final-review-service.js +1 -1
- package/dist/server/services/auto-loop-service.js +10 -10
- package/dist/server/services/progress-bar-mcp-service.js +44 -0
- package/dist/server/services/progress-bar-runtime.js +29 -0
- package/dist/server/services/progress-bar-service.js +232 -0
- package/dist/shared/auto-loop-prompts.js +12 -12
- package/dist/shared/launch-instructions.js +57 -0
- package/dist/shared/progress-bar-prompts.js +11 -0
- package/dist/shared/progress-bar-tools.js +73 -0
- package/dist/shared/progress-bars.js +3 -0
- package/package.json +1 -1
- package/src/client/dist/pwa/assets/ActivityFeed-DiUxnmGJ.js +2 -0
- package/src/client/dist/pwa/assets/{AutoLoopFinalReviewSettings-CC8ICe_I.js → AutoLoopFinalReviewSettings-f4VDR5dd.js} +1 -1
- package/src/client/dist/pwa/assets/{ChangelogPage-C1aiPBoi.js → ChangelogPage-dEWpjTlp.js} +1 -1
- package/src/client/dist/pwa/assets/ComparisonPanel-Bwbqgvr4.js +2 -0
- package/src/client/dist/pwa/assets/CreatePage-CCCCAhrx.js +2 -0
- package/src/client/dist/pwa/assets/{DashboardPage-D1S3QGp4.js → DashboardPage-3byhBITf.js} +1 -1
- package/src/client/dist/pwa/assets/DiffViewer-Bj_NTfCF.js +8 -0
- package/src/client/dist/pwa/assets/{DocumentsPanel-C4AvyZF3.js → DocumentsPanel-xyLDV3T1.js} +1 -1
- package/src/client/dist/pwa/assets/{DrawerToggleButton-LzIEeeJY.js → DrawerToggleButton-pwBSstQP.js} +1 -1
- package/src/client/dist/pwa/assets/GitPanel-DvIdrkVw.js +3 -0
- package/src/client/dist/pwa/assets/{HealthPage-Cm13vxOi.js → HealthPage-BSwhZQRo.js} +1 -1
- package/src/client/dist/pwa/assets/MainLayout-DZJ9BvZw.js +2 -0
- package/src/client/dist/pwa/assets/{MemoryPanel-C6tzCv6D.js → MemoryPanel-ChR032zP.js} +1 -1
- package/src/client/dist/pwa/assets/{MemoryProposalList-CzpzIirK.js → MemoryProposalList-BRKSoS4K.js} +1 -1
- package/src/client/dist/pwa/assets/{QBtnDropdown-BnuKPevV.js → QBtnDropdown-o3QH0Bb8.js} +1 -1
- package/src/client/dist/pwa/assets/{QExpansionItem-DjaUhgjt.js → QExpansionItem-BhFHiyq9.js} +1 -1
- package/src/client/dist/pwa/assets/{QScrollArea-Dpksslru.js → QScrollArea-BsNY6slB.js} +1 -1
- package/src/client/dist/pwa/assets/QSelect-bEq3g_io.js +1 -0
- package/src/client/dist/pwa/assets/{QTooltip-CH45NuVs.js → QTooltip-xYZ6KNu2.js} +1 -1
- package/src/client/dist/pwa/assets/{SchedulePanel-QAjXuTIN.js → SchedulePanel-DIFv_FTY.js} +1 -1
- package/src/client/dist/pwa/assets/{SearchPage-B1pbwDej.js → SearchPage-BqTBIt5E.js} +1 -1
- package/src/client/dist/pwa/assets/SettingsPage-BLD0xWFB.js +9 -0
- package/src/client/dist/pwa/assets/{SplitWorkspacePage-CJ7e-KPh.js → SplitWorkspacePage-D6r2pl5g.js} +1 -1
- package/src/client/dist/pwa/assets/{TerminalPanel-DVomz3oo.js → TerminalPanel-CladK9Vv.js} +9 -9
- package/src/client/dist/pwa/assets/{ToolCallItem-BntDHc6p.js → ToolCallItem-CdzEME4w.js} +3 -3
- package/src/client/dist/pwa/assets/{TouchPan-DwqfsAxH.js → TouchPan-B4gQPwGN.js} +1 -1
- package/src/client/dist/pwa/assets/{TourReplayButton-OIavXdUg.js → TourReplayButton-B0j6AZwU.js} +1 -1
- package/src/client/dist/pwa/assets/{WorkspaceAttentionLabels-CYwN1-Rf.js → WorkspaceAttentionLabels-CeVhoidC.js} +1 -1
- package/src/client/dist/pwa/assets/WorkspacePage-CK5XCuG_.js +4 -0
- package/src/client/dist/pwa/assets/{WorkspacePage-B248nKIU.css → WorkspacePage-w2bF8wTd.css} +1 -1
- package/src/client/dist/pwa/assets/{browser-Cl0d1gbu.js → browser-B8tNScg1.js} +1 -1
- package/src/client/dist/pwa/assets/{build-path-tree-J3YQeMuV.js → build-path-tree-kmVAcvs_.js} +1 -1
- package/src/client/dist/pwa/assets/custom-sounds-CJwd-8TL.js +1 -0
- package/src/client/dist/pwa/assets/{de-C-RtXLqL.js → de-BaO6kbdO.js} +1 -1
- package/src/client/dist/pwa/assets/{editor.api-BoFiCjBZ.js → editor.api-CgbPVW9s.js} +1 -1
- package/src/client/dist/pwa/assets/{efforts-Y6XotW97.js → efforts-y7Wf_Rgd.js} +2 -2
- package/src/client/dist/pwa/assets/{es-CBlW91ZK.js → es-DTvSsbD0.js} +1 -1
- package/src/client/dist/pwa/assets/{expand-template-sfOHWudd.js → expand-template-BFbbjj7X.js} +1 -1
- package/src/client/dist/pwa/assets/{format-mWov137C.js → format-BETfc4z9.js} +1 -1
- package/src/client/dist/pwa/assets/{formatters-B_XsveM0.js → formatters-C22K9vlC.js} +1 -1
- package/src/client/dist/pwa/assets/{fr-Hfzp_sF5.js → fr-BH7V66Yz.js} +1 -1
- package/src/client/dist/pwa/assets/{freemarker2-2pGNakhH.js → freemarker2-DiRVvp9O.js} +1 -1
- package/src/client/dist/pwa/assets/{handlebars-Bn2V6Liw.js → handlebars-BLYRroSQ.js} +1 -1
- package/src/client/dist/pwa/assets/{html-BBhkJkf2.js → html-DAW2vteY.js} +1 -1
- package/src/client/dist/pwa/assets/i18n-DnuTmw3O.js +1 -0
- package/src/client/dist/pwa/assets/{index-DCpe-Tfm.js → index-CbyHfF8I.js} +2 -2
- package/src/client/dist/pwa/assets/{it-Bl-v27qg.js → it-DZGbkkoy.js} +1 -1
- package/src/client/dist/pwa/assets/{javascript-Ba0G68U2.js → javascript-Bb5J8n0k.js} +1 -1
- package/src/client/dist/pwa/assets/{liquid-C5VrzHr_.js → liquid-Dqx3adnJ.js} +1 -1
- package/src/client/dist/pwa/assets/{mdx-DrPRiuKb.js → mdx-D_7igLV3.js} +1 -1
- package/src/client/dist/pwa/assets/{monaco-contributions-qQUY6VS7.js → monaco-contributions-C-0CbrAy.js} +1 -1
- package/src/client/dist/pwa/assets/{monaco.contribution-Dtq2RsyB.js → monaco.contribution-c6JPBEZI.js} +2 -2
- package/src/client/dist/pwa/assets/network-auth-BE4qbvWm.js +1 -0
- package/src/client/dist/pwa/assets/notify-theme-BVFBBGrJ.js +1 -0
- package/src/client/dist/pwa/assets/{project-color-Dzvvmaml.js → project-color-CHOR2jB5.js} +1 -1
- package/src/client/dist/pwa/assets/{python-Cuf_7umq.js → python-Dqubw1F5.js} +1 -1
- package/src/client/dist/pwa/assets/{razor-DcVpxFeh.js → razor-BQphc9Kt.js} +1 -1
- package/src/client/dist/pwa/assets/{typescript-Bjcc3kYC.js → typescript-Dep00l0X.js} +1 -1
- package/src/client/dist/pwa/assets/{use-search-index-status-Bwf40BEI.js → use-search-index-status-CQHHvHwM.js} +1 -1
- package/src/client/dist/pwa/assets/{use-tours-CWafZt-m.js → use-tours-IVbXTmz2.js} +2 -2
- package/src/client/dist/pwa/assets/{use-worktree-restore-DkcM2FAZ.js → use-worktree-restore-B3s5xDGR.js} +1 -1
- package/src/client/dist/pwa/assets/{workspace-templates-DL_Cs7mD.js → workspace-templates-CyuTpztP.js} +1 -1
- package/src/client/dist/pwa/assets/{xml-BmJwqJOz.js → xml-BMS2dvaF.js} +1 -1
- package/src/client/dist/pwa/assets/{yaml-DAssfLhS.js → yaml-CYw92aic.js} +1 -1
- package/src/client/dist/pwa/index.html +1 -1
- package/src/client/dist/pwa/sw.js +1 -1
- package/src/mcp-server/README.md +112 -1
- package/src/mcp-server/kobo-tasks-server.ts +34 -6
- package/src/mcp-server/progress-bar-client.ts +27 -0
- package/src/mcp-server/workspace-dialogue-client.ts +26 -7
- package/src/client/dist/pwa/assets/ActivityFeed-S3XGw3WW.js +0 -2
- package/src/client/dist/pwa/assets/ComparisonPanel-DElbn4ac.js +0 -2
- package/src/client/dist/pwa/assets/CreatePage-Bx58t4YW.js +0 -2
- package/src/client/dist/pwa/assets/DiffViewer-BH4X9ru1.js +0 -8
- package/src/client/dist/pwa/assets/GitPanel-BP3N_4nh.js +0 -3
- package/src/client/dist/pwa/assets/MainLayout-DGmMkfuw.js +0 -2
- package/src/client/dist/pwa/assets/QSelect-Dh4CjliE.js +0 -1
- package/src/client/dist/pwa/assets/SettingsPage-CUQefsDh.js +0 -9
- package/src/client/dist/pwa/assets/WorkspacePage-CAsY7Hl-.js +0 -4
- package/src/client/dist/pwa/assets/custom-sounds-D-T5rpgv.js +0 -1
- package/src/client/dist/pwa/assets/i18n-sBCWwf8Y.js +0 -1
- package/src/client/dist/pwa/assets/network-auth-BPJpXK4L.js +0 -1
- package/src/client/dist/pwa/assets/notify-theme-Bl9iRsZB.js +0 -1
package/AGENTS.md
CHANGED
|
@@ -126,6 +126,7 @@ src/
|
|
|
126
126
|
| `workspace_activity` | significant lifecycle/PR events for the absence digest |
|
|
127
127
|
| `search_*` | derived logical-message search index and indexing progress; see `search-schema.ts` |
|
|
128
128
|
| `workspace_message_batches` | immutable recipient snapshots, request fingerprint and per-recipient delivery outcomes (v53); no stored message body |
|
|
129
|
+
| `session_progress_bars` | agent-reported session activities, producer ordering, terminal state and durable individual dismissal (v54); CASCADE DELETE on workspace/session |
|
|
129
130
|
| `mcp_message_requests` | durable external-message idempotency ledger; independent of event retention |
|
|
130
131
|
| `schema_migrations` | applied migration versions, names and timestamps |
|
|
131
132
|
| `workspace_chat_history` | chat-input history per workspace: message text + `created_at`, ordered by autoincrement id, capped at 200 entries by the service; CASCADE DELETE on workspace |
|
|
@@ -200,6 +201,31 @@ Every feature that touches the schema:
|
|
|
200
201
|
|
|
201
202
|
## WebSocket protocol
|
|
202
203
|
|
|
204
|
+
Session progress bars use the separate `progress:changed` ephemeral event with a
|
|
205
|
+
public record payload and workspace/session envelope. Persist the row before
|
|
206
|
+
broadcasting; never append numeric updates to chat history or overload native
|
|
207
|
+
`subagent:progress`. Clients hydrate on selected-session changes and reconnect,
|
|
208
|
+
merge server revisions, and preserve dismissal across races. Success visibility
|
|
209
|
+
expires at the stored completion time plus five seconds, not five seconds after
|
|
210
|
+
each fetch. Three rows are initially visible with bounded expandable overflow.
|
|
211
|
+
|
|
212
|
+
The four progress MCP tools share service validation across workspace stdio,
|
|
213
|
+
global stdio and HTTP. Internal ownership comes from the dedicated per-launch
|
|
214
|
+
`KOBO_PROGRESS_SESSION_TOKEN`, independent of memory modes/budgets; external
|
|
215
|
+
calls explicitly select an existing workspace/session. Revoke internal writers
|
|
216
|
+
when stopping starts, but interrupt their remaining bars only on confirmed
|
|
217
|
+
controller closure. Late callbacks must not affect a replacement launch or
|
|
218
|
+
reopen a closed database. Startup reconciles lost internal reporters while
|
|
219
|
+
preserving external ones. An interrupted reporter is not proof of cancelled
|
|
220
|
+
background work. Operational reporting never satisfies auto-loop verification.
|
|
221
|
+
|
|
222
|
+
Retain scoped activity-key fingerprints, producer sequences and dismissed rows
|
|
223
|
+
for retries; subsequent updates cannot resurrect a dismissed indicator or undo a
|
|
224
|
+
terminal state. Bound labels, steps, page size, active/retained records and update
|
|
225
|
+
frequency. Launch prompts instruct parent agents and their delegates to report
|
|
226
|
+
long-running work; restricted review/handoff launches receive only the explicit
|
|
227
|
+
operational-tool exception, never broader mutation permissions.
|
|
228
|
+
|
|
203
229
|
Claude streaming input is correlated by per-message UUIDs. A result can cover
|
|
204
230
|
several prompts through `user_message_uuids` (messages folded into one turn),
|
|
205
231
|
not one result per sent message. Retire only the matching yielded inputs;
|
|
@@ -319,6 +345,29 @@ When adding features touching `notion-service.ts`, remember: **no token = no fea
|
|
|
319
345
|
|
|
320
346
|
See the "Notion integration" section of the README for the end-user setup guide.
|
|
321
347
|
|
|
348
|
+
### Launch instructions
|
|
349
|
+
|
|
350
|
+
`src/shared/launch-instructions.ts` composes application-owned MCP discovery,
|
|
351
|
+
permissions, progress reporting and continuation rules for both engines on every
|
|
352
|
+
fresh/resumed launch. Prefer discovering the available tool schemas to embedding
|
|
353
|
+
a duplicate catalogue. Keep Plan conversation-only; template approval cannot
|
|
354
|
+
expand tool permissions. Initial writable auto-loop launches seed tasks and end;
|
|
355
|
+
manual launches implement under the workflow policy. Preserve custom templates
|
|
356
|
+
and frozen migration text when changing generated guidance.
|
|
357
|
+
|
|
358
|
+
The engine's `onPromptPrepared` callback supplies only its textual Kōbō prefix and
|
|
359
|
+
system append. Initial creation and pending initial retries opt into a single
|
|
360
|
+
session-scoped `user:message` with `sender: system-prompt`, displayed as Kōbō
|
|
361
|
+
instructions. Snapshot the orchestration context before memory is appended; never
|
|
362
|
+
serialize engine options, capability tokens or memory bodies into chat. This is
|
|
363
|
+
a prepared-launch record, not delivery confirmation. Snapshot failures must not
|
|
364
|
+
prevent launch. Require durable snapshot persistence before clearing the pending
|
|
365
|
+
initial prompt, using a compare-and-clear against the original mission. Async
|
|
366
|
+
preparation failures must leave that pending prompt available for retry. Historical rows remain unchanged. Handoff generation is enforced
|
|
367
|
+
read-only with only its managed capability-scoped report and operational progress
|
|
368
|
+
metadata exceptions. Ordinary Claude Plan launches cannot promote themselves
|
|
369
|
+
through `ExitPlanMode`; a permission change requires a new launch.
|
|
370
|
+
|
|
322
371
|
### Agent engines
|
|
323
372
|
|
|
324
373
|
Two engines live under `src/server/services/agent/engines/`, both implementing the `AgentEngine` contract in `types.ts`:
|
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,14 @@ All notable changes to Kōbō are documented here. The format is based on
|
|
|
4
4
|
[Keep a Changelog](https://keepachangelog.com/). Each release is an `## <version>`
|
|
5
5
|
section — the in-app "What's new" dialog reads this file.
|
|
6
6
|
|
|
7
|
+
## 2.1.20
|
|
8
|
+
|
|
9
|
+
- fix(progress): clarify activity updates and completion
|
|
10
|
+
|
|
11
|
+
## 2.1.19
|
|
12
|
+
|
|
13
|
+
- feat(progress): add session activity bars and improve launch prompts
|
|
14
|
+
|
|
7
15
|
## 2.1.18
|
|
8
16
|
|
|
9
17
|
- fix(tests): resolve deployment paths on macos
|
package/CONFIGURATION.md
CHANGED
|
@@ -857,6 +857,57 @@ The **External LLM access (MCP)** panel within global Network access settings pr
|
|
|
857
857
|
|
|
858
858
|
External senders can supply `idempotency_key` once per intended message and reuse it on retries. The durable receipt survives backend restarts and event retention. An uncertain delivery is explicitly reported and never automatically sent again; see the MCP guide for response codes and limitations.
|
|
859
859
|
|
|
860
|
+
## Session progress bars
|
|
861
|
+
|
|
862
|
+
Agents can report long-running tests, builds or reviews through the
|
|
863
|
+
`create_progress_bar`, `update_progress_bar`, `finish_progress_bar` and
|
|
864
|
+
`list_progress_bars` MCP tools. These tools are available through the workspace
|
|
865
|
+
MCP server, global stdio and the external HTTP endpoint. External clients select
|
|
866
|
+
an existing workspace and session; reporting progress never launches an agent.
|
|
867
|
+
|
|
868
|
+
Bars appear above the message input for the **selected session**, even while you
|
|
869
|
+
scroll its conversation. Each has an activity label, an optional current step,
|
|
870
|
+
and either measured progress or an indeterminate indicator. Three bars are shown
|
|
871
|
+
initially; **See others** expands a bounded list. Progress is reported by the
|
|
872
|
+
agent, not measured automatically by Kōbō, and does not validate workspace tasks
|
|
873
|
+
or acceptance criteria.
|
|
874
|
+
|
|
875
|
+
A successful bar disappears five seconds after its recorded completion. Failed
|
|
876
|
+
activities stay visible until you dismiss them. Closing a bar only hides that
|
|
877
|
+
indicator: work continues, later updates cannot bring it back, and new activities
|
|
878
|
+
still appear. Dismissal is saved on the server and shared across browser tabs
|
|
879
|
+
and reloads. Reconnecting does not restart the success display timer.
|
|
880
|
+
|
|
881
|
+
If an internal reporter's agent runtime closes before completion, its bar shows
|
|
882
|
+
that **reporting was interrupted**. This does not prove that an independently
|
|
883
|
+
running shell command was cancelled. On server restart, internal reporters from
|
|
884
|
+
the previous process are interrupted; external reporters may still be running
|
|
885
|
+
elsewhere, so their last state is preserved. A new internal launch uses a new
|
|
886
|
+
reporting identity.
|
|
887
|
+
|
|
888
|
+
Workspace launch instructions require the full reporting lifecycle: create a
|
|
889
|
+
bar, keep its returned ID and sequence, update that same bar at actual phase
|
|
890
|
+
changes and meaningful completed milestones, and finish it before the final
|
|
891
|
+
report once the outcome is known. Even without a measurable percentage, agents
|
|
892
|
+
must update the current step; omitting both numeric values preserves
|
|
893
|
+
indeterminate progress. No percentage is inferred from tool calls, elapsed time
|
|
894
|
+
or model activity. Unchanged updates, polling and timer-driven reporting loops
|
|
895
|
+
are not requested.
|
|
896
|
+
|
|
897
|
+
Parents pass this lifecycle to subagents, which report and finish their own
|
|
898
|
+
activities before returning. When a restricted subagent cannot access the tools,
|
|
899
|
+
its parent reports observed milestones and the outcome on its behalf, without
|
|
900
|
+
duplicate bars. Yielding while background work continues does not mean success.
|
|
901
|
+
Reporting permissions do not grant permission to edit project files or complete
|
|
902
|
+
tasks during a review. These instructions guide the model; they cannot guarantee
|
|
903
|
+
that it reports every milestone. Updated guidance applies on the next launch or
|
|
904
|
+
resume, not retroactively to an already running agent.
|
|
905
|
+
|
|
906
|
+
The service retains at most 1,000 indicators per session, with at most 32 running
|
|
907
|
+
at once. Hidden records are retained so retries cannot recreate dismissed bars.
|
|
908
|
+
The [MCP progress guide](src/mcp-server/README.md#session-progress-tools) documents
|
|
909
|
+
arguments, ordering, retry behavior and update limits.
|
|
910
|
+
|
|
860
911
|
## Persistent memory
|
|
861
912
|
|
|
862
913
|
Kōbō stores deliberate, concise facts in SQLite, independently of Claude Code's native memory and provider chat history. Claude Code and Codex read the same Kōbō scopes, so a fact saved in one engine can be available to the other. There is no background transcript extractor or extra LLM call: agents must deliberately use the memory tools to save useful knowledge.
|
|
@@ -2087,11 +2138,19 @@ for the same reason the API refuses the change. A change returns HTTP 409 while
|
|
|
2087
2138
|
|
|
2088
2139
|
Fresh defaults are manual. Existing settings/workspaces migrate to the previous automatic behavior for compatibility. Manual requires an explicit user request for that action; automatic supplies the workflow preference for the mission. Narrower user instructions always win. Publish means PR/MR creation, description updates and comments; merging needs separate authorization. Explicit Git-panel actions remain available. These preferences are agent instructions, not a shell-command filter or an OS sandbox.
|
|
2089
2140
|
|
|
2090
|
-
Plan is never promoted to Bypass by auto-loop preparation, an agent tool event, or loop enablement.
|
|
2141
|
+
Plan is never promoted to Bypass by auto-loop preparation, an agent tool event, or loop enablement. The initial Plan session provides its plan in the conversation without saving files or seeding tasks. Autonomous task preparation, execution and finalization block with an actionable message until an execution mode is explicitly selected.
|
|
2091
2142
|
|
|
2092
2143
|
Notion token environment overrides are applied consistently to both token variables passed to the child process. Explicit `OPENAPI_MCP_HEADERS` remain authoritative for compatibility and are not replaced by the resolved token. Direct integration configuration and legacy fallback are only read when an integration is used; opening Settings does not start a Notion users lookup. Connection tests and users refresh are explicit actions.
|
|
2093
2144
|
|
|
2094
2145
|
|
|
2146
|
+
### Initial Kōbō instructions
|
|
2147
|
+
|
|
2148
|
+
New workspaces receive the mission, repository context, current permissions, current phase and expected result. Agents first consult the available managed MCP tool descriptions and schemas, then prefer relevant Kōbō tools for workspace operations. This is not a request to call every tool or poll. Long tasks and delegated work use labeled progress bars; dismissing a bar hides only that activity and does not cancel its work.
|
|
2149
|
+
|
|
2150
|
+
Plan launches remain conversation-only. Writable auto-loop launches prepare the plan and task list before returning control to the loop; writable manual launches implement after plan approval, under the configured Git policy. Custom brainstorming, Notion and Sentry templates are preserved; they cannot expand launch permissions or authorize commits automatically. Review returns and handoff reports remain read-only, with only their scoped report and operational progress tools allowed. Plan approval does not change permissions; explicitly select an execution mode in Kōbō and start a new launch to implement.
|
|
2151
|
+
|
|
2152
|
+
The expandable **Kōbō instructions** chat entry records the application-owned text prepared by the engine builder for the initial launch or a pending initial-prompt retry, including progress guidance, continuation rules, workflow policy and managed integration notices. The pending initial mission is retained until this entry is durably recorded, so a failure during asynchronous launch preparation remains retryable. A later replacement mission is never cleared by an earlier launch. Preparation is not proof of provider delivery. The provider's own system preset is not included. Retrieved memory bodies and capability tokens are not copied to chat; memory usage remains visible separately in the Memory panel. Existing historical prompt entries retain their original content. Ordinary resumes receive current instructions without creating another initial-prompt entry.
|
|
2153
|
+
|
|
2095
2154
|
### Managed integration MCPs in agent sessions
|
|
2096
2155
|
|
|
2097
2156
|
**Test connection** uses the saved direct configuration when present, otherwise the
|
package/README.md
CHANGED
|
@@ -24,6 +24,8 @@ Kōbō (工房, "workshop") turns *one agent, one terminal* into a real workflow
|
|
|
24
24
|
|
|
25
25
|
Use [group messages](CONFIGURATION.md#group-workspace-messages) to send one instruction to selected workspaces, filtered by tags and status, from the interface or MCP. Auto-loops receive it on their next iteration; each recipient has a durable delivery result.
|
|
26
26
|
|
|
27
|
+
[Session progress bars](CONFIGURATION.md#session-progress-bars) show labelled long-running activities above the message input, including work delegated to subagents. Agents report progress through internal or external MCP; you can dismiss an individual bar without stopping its work.
|
|
28
|
+
|
|
27
29
|
## Quick start
|
|
28
30
|
|
|
29
31
|
Requires Node.js ≥ 24.15, Git, Bash and your own Claude Code **or** Codex authentication. No skill plugin or ticket integration is required. Kōbō is a local, single-user tool; each user installs their own instance.
|
|
@@ -4,12 +4,14 @@ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
|
|
|
4
4
|
import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
5
5
|
import { getDb } from '../server/db/index.js';
|
|
6
6
|
import { EXTERNAL_MEMORY_TOOL_DEFINITIONS, isMemoryToolName, MEMORY_TOOL_DEFINITIONS } from '../shared/memory-tools.js';
|
|
7
|
+
import { INTERNAL_PROGRESS_BAR_TOOLS, isProgressBarTool, PROGRESS_BAR_TOOLS } from '../shared/progress-bar-tools.js';
|
|
7
8
|
import { isWorkspaceCreationTool, MAX_MCP_CREATION_REQUEST_BYTES, WORKSPACE_CREATION_TOOLS, } from '../shared/workspace-creation-tools.js';
|
|
8
9
|
import { WORKSPACE_DIALOGUE_TOOLS } from '../shared/workspace-dialogue-tools.js';
|
|
9
10
|
import { isWorkspaceGroupMessageTool, WORKSPACE_GROUP_MESSAGE_TOOLS } from '../shared/workspace-group-message-tools.js';
|
|
10
11
|
import { isWorkspaceLifecycleTool, WORKSPACE_LIFECYCLE_TOOLS } from '../shared/workspace-lifecycle-tools.js';
|
|
11
12
|
import { createTaskHandler, cronListHandler, deleteTaskHandler, getDevServerStatusHandler, getSessionUsageHandler, getSettingsHandler, getTicketSourcesHandler, getWorkspaceInfoHandler, listDocumentsHandler, listTasksHandler, listWorkspaceImagesHandler, listWorkspacesHandler, logThoughtHandler, markAutoLoopReadyHandler, markTaskDoneHandler, readDocumentHandler, readWorkspaceEventsCsvHandler, setWorkspaceAgentDescriptionHandler, updateTaskHandler, } from './kobo-tasks-handlers.js';
|
|
12
13
|
import { callMemoryTool, isMemoryOutputSuppressed } from './memory-client.js';
|
|
14
|
+
import { callProgressBarTool } from './progress-bar-client.js';
|
|
13
15
|
import { callWorkspaceDialogueTool } from './workspace-dialogue-client.js';
|
|
14
16
|
const finalReviewToken = process.env.KOBO_FINAL_REVIEW_TOKEN;
|
|
15
17
|
const finalReviewSessionId = process.env.KOBO_FINAL_REVIEW_SESSION_ID;
|
|
@@ -213,7 +215,7 @@ const WORKSPACE_SCOPED_TOOLS = [
|
|
|
213
215
|
},
|
|
214
216
|
{
|
|
215
217
|
name: 'mark_auto_loop_ready',
|
|
216
|
-
description: 'CALL
|
|
218
|
+
description: 'CALL at the end of authorized auto-loop preparation, either during initial workspace creation with auto-loop or a later `/kobo-prep-autoloop` grooming session. First ensure tasks are atomic, implementable, and include the required verification/finalization work. Marks preparation ready; this is a mutation and cannot be called from a read-only launch. Do NOT call during unrelated normal sessions.',
|
|
217
219
|
inputSchema: { type: 'object', properties: {}, required: [] },
|
|
218
220
|
annotations: { destructiveHint: false, openWorldHint: false },
|
|
219
221
|
},
|
|
@@ -328,7 +330,7 @@ const WORKSPACE_SCOPED_TOOLS = [
|
|
|
328
330
|
},
|
|
329
331
|
{
|
|
330
332
|
name: 'cron_create',
|
|
331
|
-
description: 'Schedule a recurring trigger on THIS workspace. At each fire, Kōbō
|
|
333
|
+
description: 'Schedule a recurring trigger on THIS workspace. At each fire, Kōbō checks that the workspace is idle (no active session), then injects `prompt` into the conversation pinned when scheduled (`mode=resume`) or starts a new session (`mode=fresh`). Skip-if-active: if a session is already running when the timer fires, that occurrence is skipped, the next occurrence is computed, and the cron continues. The cron persists across server restarts (skip-missed semantics on boot — no catchup spam). Delete with `cron_delete(id)`. Multiple crons per workspace are allowed.',
|
|
332
334
|
inputSchema: {
|
|
333
335
|
type: 'object',
|
|
334
336
|
properties: {
|
|
@@ -538,7 +540,7 @@ const WORKSPACE_SCOPED_TOOLS = [
|
|
|
538
540
|
},
|
|
539
541
|
{
|
|
540
542
|
name: 'schedule_wakeup',
|
|
541
|
-
description: 'WHEN:
|
|
543
|
+
description: 'WHEN: the parent agent needs a durable later check for detached work or external state without a tracked completion notification. Do not duplicate SDK tracked-job continuation or schedule merely to advance auto-loop; subagents must leave the one workspace wakeup to their parent. Delay is measured from this call and clamped to [60, 21600] seconds. The wakeup targets this workspace and the session selected at scheduling time, not whichever session is newest later. It is deferred while busy when it cannot be delivered to the waiting controller; active auto-loop receives it as a queued instruction. Replaces the existing pending wakeup on this workspace, so preserve unrelated scheduled intent. Supply a concrete follow-up prompt and optional reason. End the current turn normally; delivery timing also depends on workspace availability. Prefer this durable Kōbō tool over native ScheduleWakeup',
|
|
542
544
|
inputSchema: {
|
|
543
545
|
type: 'object',
|
|
544
546
|
properties: {
|
|
@@ -566,6 +568,7 @@ const WORKSPACE_SCOPED_TOOLS = [
|
|
|
566
568
|
annotations: { destructiveHint: false, openWorldHint: false },
|
|
567
569
|
},
|
|
568
570
|
...MEMORY_TOOL_DEFINITIONS,
|
|
571
|
+
...INTERNAL_PROGRESS_BAR_TOOLS,
|
|
569
572
|
];
|
|
570
573
|
const GLOBAL_TOOLS = [
|
|
571
574
|
...WORKSPACE_DIALOGUE_TOOLS,
|
|
@@ -573,6 +576,7 @@ const GLOBAL_TOOLS = [
|
|
|
573
576
|
...WORKSPACE_LIFECYCLE_TOOLS,
|
|
574
577
|
...WORKSPACE_GROUP_MESSAGE_TOOLS,
|
|
575
578
|
...EXTERNAL_MEMORY_TOOL_DEFINITIONS,
|
|
579
|
+
...PROGRESS_BAR_TOOLS,
|
|
576
580
|
{
|
|
577
581
|
name: 'list_workspaces',
|
|
578
582
|
description: 'List Kōbō workspaces with their id, title, status, tags, and creation date. Set tag to return only workspaces carrying that exact tag. Works even when the Kōbō backend server is not running (reads the database directly). Use this to discover existing workspaces before creating one or targeting one with archive_workspace/stop_workspace.',
|
|
@@ -617,12 +621,19 @@ function availableTools() {
|
|
|
617
621
|
// A workspace process exposes the capability-bound memory tools exactly once.
|
|
618
622
|
// Unbound/global stdio exposes the external bridge variant instead.
|
|
619
623
|
const tools = workspaceId
|
|
620
|
-
? [
|
|
624
|
+
? [
|
|
625
|
+
...WORKSPACE_SCOPED_TOOLS,
|
|
626
|
+
...GLOBAL_TOOLS.filter((tool) => !isMemoryToolName(tool.name) && !isProgressBarTool(tool.name)),
|
|
627
|
+
]
|
|
621
628
|
: GLOBAL_TOOLS;
|
|
622
629
|
return tools.filter((tool) => handoffId && handoffToken
|
|
623
|
-
? tool.name === 'submit_session_handoff' ||
|
|
630
|
+
? tool.name === 'submit_session_handoff' ||
|
|
631
|
+
tool.annotations?.readOnlyHint === true ||
|
|
632
|
+
(isProgressBarTool(tool.name) && !!process.env.KOBO_PROGRESS_SESSION_TOKEN)
|
|
624
633
|
: finalReviewToken && finalReviewSessionId
|
|
625
|
-
? tool.name === 'submit_final_review' ||
|
|
634
|
+
? tool.name === 'submit_final_review' ||
|
|
635
|
+
tool.annotations?.readOnlyHint === true ||
|
|
636
|
+
(isProgressBarTool(tool.name) && !!process.env.KOBO_PROGRESS_SESSION_TOKEN)
|
|
626
637
|
: tool.name !== 'submit_session_handoff' && tool.name !== 'submit_final_review');
|
|
627
638
|
}
|
|
628
639
|
server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: availableTools() }));
|
|
@@ -676,6 +687,17 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
676
687
|
report: a.report,
|
|
677
688
|
}));
|
|
678
689
|
}
|
|
690
|
+
if (isProgressBarTool(name)) {
|
|
691
|
+
if (!workspaceId)
|
|
692
|
+
return await callWorkspaceDialogueTool(backendUrl, name, a, process.env.KOBO_NETWORK_TOKEN, process.env.KOBO_MCP_CLIENT_NAME ?? server.getClientVersion()?.name);
|
|
693
|
+
return await callProgressBarTool({
|
|
694
|
+
backendUrl,
|
|
695
|
+
name,
|
|
696
|
+
args: a,
|
|
697
|
+
capability: process.env.KOBO_PROGRESS_SESSION_TOKEN,
|
|
698
|
+
networkToken: process.env.KOBO_NETWORK_TOKEN,
|
|
699
|
+
});
|
|
700
|
+
}
|
|
679
701
|
if (isMemoryToolName(name)) {
|
|
680
702
|
if (!workspaceId) {
|
|
681
703
|
return await callWorkspaceDialogueTool(backendUrl, name, a, process.env.KOBO_NETWORK_TOKEN, process.env.KOBO_MCP_CLIENT_NAME ?? server.getClientVersion()?.name);
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { isProgressBarTool } from '../shared/progress-bar-tools.js';
|
|
2
|
+
export async function callProgressBarTool(input) {
|
|
3
|
+
if (!isProgressBarTool(input.name))
|
|
4
|
+
throw new TypeError('Unknown progress tool');
|
|
5
|
+
if (!input.capability)
|
|
6
|
+
throw new Error('Progress capability is unavailable for this process');
|
|
7
|
+
const headers = {
|
|
8
|
+
'Content-Type': 'application/json',
|
|
9
|
+
'X-Kobo-Progress-Session': input.capability,
|
|
10
|
+
};
|
|
11
|
+
if (input.networkToken)
|
|
12
|
+
headers['X-Kobo-Token'] = input.networkToken;
|
|
13
|
+
const response = await (input.fetcher ?? fetch)(`${input.backendUrl.replace(/\/$/, '')}/api/progress-bars/agent/${input.name}`, { method: 'POST', headers, body: JSON.stringify(input.args), signal: AbortSignal.timeout(30_000) });
|
|
14
|
+
const data = (await response.json());
|
|
15
|
+
return {
|
|
16
|
+
content: [{ type: 'text', text: JSON.stringify(data) }],
|
|
17
|
+
structuredContent: data,
|
|
18
|
+
...(!response.ok ? { isError: true } : {}),
|
|
19
|
+
};
|
|
20
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
2
2
|
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
|
|
3
3
|
import { isMemoryToolName, validateMemoryToolArguments } from '../shared/memory-tools.js';
|
|
4
|
+
import { isProgressBarTool, validateProgressBarArguments } from '../shared/progress-bar-tools.js';
|
|
4
5
|
import { isWorkspaceCreationTool, validateWorkspaceCreationArguments } from '../shared/workspace-creation-tools.js';
|
|
5
6
|
import { validateDialogueArguments } from '../shared/workspace-dialogue-tools.js';
|
|
6
7
|
import { isWorkspaceGroupMessageTool, validateWorkspaceGroupMessageArguments, } from '../shared/workspace-group-message-tools.js';
|
|
@@ -8,15 +9,34 @@ import { isWorkspaceLifecycleTool, validateWorkspaceLifecycleArguments } from '.
|
|
|
8
9
|
import { normalizeClientName } from '../shared/workspace-message-types.js';
|
|
9
10
|
/** Stateless HTTP bridge: external stdio clients never own agent runtime state. */
|
|
10
11
|
export async function callWorkspaceDialogueTool(backendUrl, name, args, token, clientName) {
|
|
12
|
+
if (isProgressBarTool(name)) {
|
|
13
|
+
try {
|
|
14
|
+
validateProgressBarArguments(name, args, true);
|
|
15
|
+
}
|
|
16
|
+
catch (error) {
|
|
17
|
+
const data = {
|
|
18
|
+
error: error instanceof Error ? error.message : 'Invalid arguments',
|
|
19
|
+
status: 400,
|
|
20
|
+
code: 'invalid_arguments',
|
|
21
|
+
};
|
|
22
|
+
return {
|
|
23
|
+
isError: true,
|
|
24
|
+
content: [{ type: 'text', text: JSON.stringify(data) }],
|
|
25
|
+
structuredContent: data,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
}
|
|
11
29
|
const arguments_ = isMemoryToolName(name)
|
|
12
30
|
? validateMemoryToolArguments(name, args, true)
|
|
13
|
-
:
|
|
14
|
-
?
|
|
15
|
-
:
|
|
16
|
-
?
|
|
17
|
-
:
|
|
18
|
-
?
|
|
19
|
-
:
|
|
31
|
+
: isProgressBarTool(name)
|
|
32
|
+
? args
|
|
33
|
+
: isWorkspaceCreationTool(name)
|
|
34
|
+
? validateWorkspaceCreationArguments(name, args)
|
|
35
|
+
: isWorkspaceLifecycleTool(name)
|
|
36
|
+
? validateWorkspaceLifecycleArguments(name, args)
|
|
37
|
+
: isWorkspaceGroupMessageTool(name)
|
|
38
|
+
? validateWorkspaceGroupMessageArguments(name, args)
|
|
39
|
+
: validateDialogueArguments(name, args);
|
|
20
40
|
const client = new Client({ name: 'kobo-stdio-bridge', version: '1.0.0' });
|
|
21
41
|
// Creation can include forge reads, worktree setup and user setup scripts.
|
|
22
42
|
// A timed-out creation is ambiguous and must never be retried automatically.
|
|
@@ -2,6 +2,7 @@ import { initAutoLoopFinalReviewSchema } from './auto-loop-final-review-schema.j
|
|
|
2
2
|
import { initAutoLoopSchema } from './auto-loop-schema.js';
|
|
3
3
|
import { initMcpMessageSchema } from './mcp-message-schema.js';
|
|
4
4
|
import { migrateMemorySchema } from './memory-schema.js';
|
|
5
|
+
import { initProgressBarSchema } from './progress-bar-schema.js';
|
|
5
6
|
import { initReviewReturnSchema, migrateDurableReviewReturns } from './review-return-schema.js';
|
|
6
7
|
import { initSchema } from './schema.js';
|
|
7
8
|
import { initSearchSchema } from './search-schema.js';
|
|
@@ -810,6 +811,7 @@ export const migrations = [
|
|
|
810
811
|
},
|
|
811
812
|
},
|
|
812
813
|
{ version: 53, name: 'workspace-group-message-receipts', migrate: initWorkspaceMessageBatchSchema },
|
|
814
|
+
{ version: 54, name: 'session-progress-bars', migrate: initProgressBarSchema },
|
|
813
815
|
];
|
|
814
816
|
/** Current schema version — always equals the highest migration version. */
|
|
815
817
|
export const SCHEMA_VERSION = migrations.length > 0 ? migrations[migrations.length - 1].version : 1;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export function initProgressBarSchema(db) {
|
|
2
|
+
db.exec(`CREATE TABLE IF NOT EXISTS session_progress_bars (
|
|
3
|
+
id TEXT PRIMARY KEY,
|
|
4
|
+
workspace_id TEXT NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
|
|
5
|
+
session_id TEXT NOT NULL REFERENCES agent_sessions(id) ON DELETE CASCADE,
|
|
6
|
+
owner_kind TEXT NOT NULL CHECK(owner_kind IN ('internal','external')),
|
|
7
|
+
owner_launch_id TEXT NOT NULL,
|
|
8
|
+
activity_key TEXT NOT NULL,
|
|
9
|
+
creation_fingerprint TEXT NOT NULL,
|
|
10
|
+
producer_fingerprint TEXT,
|
|
11
|
+
producer_updated_at TEXT,
|
|
12
|
+
label TEXT NOT NULL,
|
|
13
|
+
step TEXT,
|
|
14
|
+
current REAL,
|
|
15
|
+
total REAL,
|
|
16
|
+
status TEXT NOT NULL CHECK(status IN ('running','succeeded','failed','interrupted')),
|
|
17
|
+
dismissed_at TEXT,
|
|
18
|
+
completed_at TEXT,
|
|
19
|
+
created_at TEXT NOT NULL,
|
|
20
|
+
updated_at TEXT NOT NULL,
|
|
21
|
+
revision INTEGER NOT NULL DEFAULT 1,
|
|
22
|
+
sequence INTEGER NOT NULL DEFAULT 0,
|
|
23
|
+
UNIQUE(workspace_id,session_id,owner_kind,owner_launch_id,activity_key)
|
|
24
|
+
);
|
|
25
|
+
CREATE INDEX IF NOT EXISTS idx_progress_bars_session ON session_progress_bars(workspace_id,session_id,created_at,id);
|
|
26
|
+
CREATE INDEX IF NOT EXISTS idx_progress_bars_launch ON session_progress_bars(owner_kind,owner_launch_id,status);`);
|
|
27
|
+
}
|
package/dist/server/db/schema.js
CHANGED
|
@@ -2,6 +2,7 @@ import { initAutoLoopFinalReviewSchema } from './auto-loop-final-review-schema.j
|
|
|
2
2
|
import { initAutoLoopSchema } from './auto-loop-schema.js';
|
|
3
3
|
import { initMcpMessageSchema } from './mcp-message-schema.js';
|
|
4
4
|
import { initMemorySchema } from './memory-schema.js';
|
|
5
|
+
import { initProgressBarSchema } from './progress-bar-schema.js';
|
|
5
6
|
import { initReviewReturnSchema } from './review-return-schema.js';
|
|
6
7
|
import { initSearchSchema } from './search-schema.js';
|
|
7
8
|
import { initSessionHandoffSchema } from './session-handoff-schema.js';
|
|
@@ -242,4 +243,5 @@ export function initSchema(db) {
|
|
|
242
243
|
initSessionHandoffSchema(db);
|
|
243
244
|
initMemorySchema(db);
|
|
244
245
|
initWorkspaceMessageBatchSchema(db);
|
|
246
|
+
initProgressBarSchema(db);
|
|
245
247
|
}
|
package/dist/server/index.js
CHANGED
|
@@ -25,6 +25,7 @@ import mcpRouter from './routes/mcp.js';
|
|
|
25
25
|
import memoryRouter from './routes/memory.js';
|
|
26
26
|
import { migrationRouter } from './routes/migration.js';
|
|
27
27
|
import notionRouter from './routes/notion.js';
|
|
28
|
+
import progressBarsRouter from './routes/progress-bars.js';
|
|
28
29
|
import pullRequestsRouter from './routes/pull-requests.js';
|
|
29
30
|
import searchRouter from './routes/search.js';
|
|
30
31
|
import sentryRouter from './routes/sentry.js';
|
|
@@ -47,6 +48,7 @@ import { reconcileMessageRequests } from './services/mcp-message-request-service
|
|
|
47
48
|
import { reconcileMemoryContextsOnStartup } from './services/memory-context-service.js';
|
|
48
49
|
import { authorizeWsUpgrade, generateToken, getLanHostnames, getLanUrls, isAllowedOrigin, isAllowedRequestHost, resolveBindHost, resolveDevClientOrigin, resolveNetworkAccessEnvOverrides, resolveProxyHostname, } from './services/network-access-service.js';
|
|
49
50
|
import { startPrWatcher, stopPrWatcher } from './services/pr-watcher-service.js';
|
|
51
|
+
import { reconcileOrphanedProgressBars } from './services/progress-bar-service.js';
|
|
50
52
|
import * as quotaBackoffService from './services/quota-backoff-service.js';
|
|
51
53
|
import { reconcileReviewReturns } from './services/review-return-service.js';
|
|
52
54
|
import { startSearchIndex, stopSearchIndex } from './services/search-service.js';
|
|
@@ -130,6 +132,7 @@ const dailyBackupScheduler = startDailyDbBackupScheduler(async () => {
|
|
|
130
132
|
});
|
|
131
133
|
// Initialize process cleanup, agent watchdog, PR watcher, and wakeup rehydration
|
|
132
134
|
reconcileOrphanSessions();
|
|
135
|
+
reconcileOrphanedProgressBars();
|
|
133
136
|
reconcileReviewReturns();
|
|
134
137
|
reconcileSessionHandoffs();
|
|
135
138
|
// Deliver any new default prompt templates to existing installs (seed-once via the
|
|
@@ -162,6 +165,7 @@ app.route('/api/workspaces', workspacesRouter);
|
|
|
162
165
|
app.route('/api/workspace-messages', workspaceMessagesRouter);
|
|
163
166
|
app.route('/api/mcp', mcpRouter);
|
|
164
167
|
app.route('/api/memory', memoryRouter);
|
|
168
|
+
app.route('/api/progress-bars', progressBarsRouter);
|
|
165
169
|
app.route('/api/pull-requests', pullRequestsRouter);
|
|
166
170
|
app.route('/api/workspaces', imagesRouter);
|
|
167
171
|
app.route('/api/notion', notionRouter);
|
|
@@ -4,12 +4,15 @@ import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprot
|
|
|
4
4
|
import { Hono } from 'hono';
|
|
5
5
|
import { bodyLimit } from 'hono/body-limit';
|
|
6
6
|
import { EXTERNAL_MEMORY_TOOL_DEFINITIONS, isMemoryToolName } from '../../shared/memory-tools.js';
|
|
7
|
+
import { isProgressBarTool, PROGRESS_BAR_TOOLS } from '../../shared/progress-bar-tools.js';
|
|
7
8
|
import { isWorkspaceCreationTool, MAX_MCP_CREATION_REQUEST_BYTES, WORKSPACE_CREATION_TOOLS, } from '../../shared/workspace-creation-tools.js';
|
|
8
9
|
import { EXTERNAL_MCP_TOOLS } from '../../shared/workspace-dialogue-tools.js';
|
|
9
10
|
import { isWorkspaceGroupMessageTool, WORKSPACE_GROUP_MESSAGE_TOOLS, } from '../../shared/workspace-group-message-tools.js';
|
|
10
11
|
import { isWorkspaceLifecycleTool, WORKSPACE_LIFECYCLE_TOOLS } from '../../shared/workspace-lifecycle-tools.js';
|
|
11
12
|
import { createMcpClientContext } from '../services/mcp-client-context.js';
|
|
12
13
|
import { executeMemoryMcpTool } from '../services/memory-mcp-service.js';
|
|
14
|
+
import { executeProgressBarTool, progressErrorData } from '../services/progress-bar-mcp-service.js';
|
|
15
|
+
import { ProgressBarError } from '../services/progress-bar-service.js';
|
|
13
16
|
import { executeWorkspaceCreationTool, WorkspaceCreationMcpError } from '../services/workspace-creation-mcp-service.js';
|
|
14
17
|
import { executeWorkspaceDialogueTool } from '../services/workspace-dialogue-service.js';
|
|
15
18
|
import { executeWorkspaceGroupMessageTool, WorkspaceGroupMessageMcpError, } from '../services/workspace-group-message-mcp-service.js';
|
|
@@ -70,21 +73,24 @@ app.all('/', async (c) => {
|
|
|
70
73
|
...WORKSPACE_LIFECYCLE_TOOLS,
|
|
71
74
|
...WORKSPACE_GROUP_MESSAGE_TOOLS,
|
|
72
75
|
...EXTERNAL_MEMORY_TOOL_DEFINITIONS,
|
|
76
|
+
...PROGRESS_BAR_TOOLS,
|
|
73
77
|
],
|
|
74
78
|
}));
|
|
75
79
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
76
80
|
const isMemory = isMemoryToolName(request.params.name);
|
|
77
81
|
try {
|
|
78
82
|
const source = createMcpClientContext(c.req.header('X-Kobo-Client-Name'), c.req.header('X-Kobo-Client-Transport') === 'stdio' ? 'stdio' : 'http', c.req.header('X-Kobo-Client-Name-Encoding'));
|
|
79
|
-
const data =
|
|
80
|
-
?
|
|
81
|
-
:
|
|
82
|
-
?
|
|
83
|
-
:
|
|
84
|
-
? await
|
|
85
|
-
:
|
|
86
|
-
?
|
|
87
|
-
:
|
|
83
|
+
const data = isProgressBarTool(request.params.name)
|
|
84
|
+
? executeProgressBarTool(request.params.name, request.params.arguments ?? {})
|
|
85
|
+
: isMemory
|
|
86
|
+
? executeMemoryMcpTool(request.params.name, request.params.arguments ?? {}, source)
|
|
87
|
+
: isWorkspaceCreationTool(request.params.name)
|
|
88
|
+
? await executeWorkspaceCreationTool(request.params.name, request.params.arguments ?? {}, dispatchWorkspaceRequest)
|
|
89
|
+
: isWorkspaceLifecycleTool(request.params.name)
|
|
90
|
+
? await executeWorkspaceLifecycleTool(request.params.name, request.params.arguments ?? {}, dispatchWorkspaceRequest)
|
|
91
|
+
: isWorkspaceGroupMessageTool(request.params.name)
|
|
92
|
+
? executeWorkspaceGroupMessageTool(request.params.name, request.params.arguments ?? {}, source)
|
|
93
|
+
: await executeWorkspaceDialogueTool(request.params.name, request.params.arguments ?? {}, source);
|
|
88
94
|
if (isMemory) {
|
|
89
95
|
const bounded = prepareMemoryToolEnvelope(data, { targetTokens: 1_000, transport: 'external' });
|
|
90
96
|
if (bounded.data.memoryOutputSuppressed === true)
|
|
@@ -104,6 +110,10 @@ app.all('/', async (c) => {
|
|
|
104
110
|
};
|
|
105
111
|
}
|
|
106
112
|
catch (error) {
|
|
113
|
+
if (error instanceof ProgressBarError) {
|
|
114
|
+
const data = progressErrorData(error);
|
|
115
|
+
return { isError: true, content: [{ type: 'text', text: JSON.stringify(data) }], structuredContent: data };
|
|
116
|
+
}
|
|
107
117
|
if (error instanceof WorkspaceGroupMessageMcpError) {
|
|
108
118
|
const data = { error: error.message, status: error.status };
|
|
109
119
|
return { isError: true, content: [{ type: 'text', text: JSON.stringify(data) }], structuredContent: data };
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { Hono } from 'hono';
|
|
2
|
+
import { bodyLimit } from 'hono/body-limit';
|
|
3
|
+
import { executeProgressBarTool, progressErrorData } from '../services/progress-bar-mcp-service.js';
|
|
4
|
+
import { resolveProgressCapability } from '../services/progress-bar-runtime.js';
|
|
5
|
+
import { dismissProgressBar, listProgressBars, ProgressBarError } from '../services/progress-bar-service.js';
|
|
6
|
+
const router = new Hono();
|
|
7
|
+
router.use('*', bodyLimit({ maxSize: 16 * 1024, onError: (c) => c.json({ error: 'Request body is too large' }, 413) }));
|
|
8
|
+
router.onError((error, c) => {
|
|
9
|
+
if (error instanceof ProgressBarError)
|
|
10
|
+
return c.json(progressErrorData(error), error.status);
|
|
11
|
+
console.error('[progress-bars] Request failed', error);
|
|
12
|
+
return c.json({ error: 'Progress request failed' }, 500);
|
|
13
|
+
});
|
|
14
|
+
router.post('/agent/:tool', async (c) => {
|
|
15
|
+
let body;
|
|
16
|
+
try {
|
|
17
|
+
body = await c.req.json();
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return c.json({ error: 'Invalid JSON' }, 400);
|
|
21
|
+
}
|
|
22
|
+
// Stop may revoke the launch while the request body is being read. Resolve
|
|
23
|
+
// only after the last await so authorization and mutation stay synchronous.
|
|
24
|
+
const owner = resolveProgressCapability(c.req.header('X-Kobo-Progress-Session'));
|
|
25
|
+
return c.json(executeProgressBarTool(c.req.param('tool'), body, owner));
|
|
26
|
+
});
|
|
27
|
+
router.get('/', (c) => {
|
|
28
|
+
const workspaceId = c.req.query('workspaceId') ?? '';
|
|
29
|
+
const sessionId = c.req.query('sessionId') ?? '';
|
|
30
|
+
const limit = c.req.query('limit');
|
|
31
|
+
const offset = c.req.query('offset');
|
|
32
|
+
return c.json(listProgressBars({
|
|
33
|
+
workspaceId,
|
|
34
|
+
sessionId,
|
|
35
|
+
limit: limit === undefined ? undefined : Number(limit),
|
|
36
|
+
offset: offset === undefined ? undefined : Number(offset),
|
|
37
|
+
}));
|
|
38
|
+
});
|
|
39
|
+
router.post('/:id/dismiss', async (c) => {
|
|
40
|
+
let body;
|
|
41
|
+
try {
|
|
42
|
+
body = await c.req.json();
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
return c.json({ error: 'Invalid JSON' }, 400);
|
|
46
|
+
}
|
|
47
|
+
if (!body || typeof body !== 'object' || Array.isArray(body))
|
|
48
|
+
return c.json({ error: 'Expected an object' }, 400);
|
|
49
|
+
const record = body;
|
|
50
|
+
if (Object.keys(record).some((key) => key !== 'workspaceId' && key !== 'sessionId') ||
|
|
51
|
+
typeof record.workspaceId !== 'string' ||
|
|
52
|
+
typeof record.sessionId !== 'string')
|
|
53
|
+
return c.json({ error: 'workspaceId and sessionId are required' }, 400);
|
|
54
|
+
return c.json(dismissProgressBar({ workspaceId: record.workspaceId, sessionId: record.sessionId }, c.req.param('id')));
|
|
55
|
+
});
|
|
56
|
+
export default router;
|