agentbox-app 0.1.7 → 0.1.11
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/README.md +209 -55
- package/bin/agentbox.mjs +6 -0
- package/briefs/message-rules.md +13 -3
- package/briefs/worker.md +63 -49
- package/briefs/writing-rules.md +90 -131
- package/main/account-discovery.mjs +21 -20
- package/main/account-tooling.mjs +9 -10
- package/main/agent-activity.mjs +45 -5
- package/main/agent-schedule.mjs +14 -14
- package/main/agent-sessions.mjs +94 -10
- package/main/agent-updates.mjs +114 -0
- package/main/agents.mjs +52 -46
- package/main/analytics.mjs +27 -0
- package/main/approval-prompt-server.mjs +2 -2
- package/main/artifact-path.mjs +11 -0
- package/main/claude-bin.mjs +31 -5
- package/main/claude-input.mjs +45 -3
- package/main/claude-plan.mjs +11 -11
- package/main/code-change.mjs +3 -3
- package/main/codex-account.mjs +1 -1
- package/main/codex-bin.mjs +17 -0
- package/main/codex-memory-gate.mjs +260 -0
- package/main/codex-models.mjs +12 -7
- package/main/codex-threads.mjs +46 -23
- package/main/codex-usage-file.mjs +7 -7
- package/main/codex-usage.mjs +4 -4
- package/main/codex-watch.mjs +12 -12
- package/main/config.mjs +68 -8
- package/main/dev-window.mjs +9 -9
- package/main/doc-scheme.mjs +2 -0
- package/main/engine-setup.mjs +193 -0
- package/main/feedback.mjs +55 -0
- package/main/folder-pictures.mjs +48 -0
- package/main/frame-scrollbars.mjs +90 -0
- package/main/fresh-user.mjs +6 -3
- package/main/git-change-offthread.mjs +70 -0
- package/main/git-change-thread.mjs +11 -0
- package/main/git-change.mjs +1 -1
- package/main/img-scheme.mjs +70 -1
- package/main/instruction-settings.mjs +92 -54
- package/main/ipc.mjs +316 -42
- package/main/leftovers.mjs +518 -0
- package/main/live-replies.mjs +43 -5
- package/main/machine.mjs +47 -0
- package/main/main.mjs +119 -15
- package/main/memory-gate-history.mjs +254 -0
- package/main/memory-gate-server.mjs +461 -0
- package/main/memory-gate.mjs +206 -0
- package/main/message-priority.mjs +87 -0
- package/main/rail-note.mjs +2 -2
- package/main/refresh-agent-models.mjs +20 -0
- package/main/repeats.mjs +4 -4
- package/main/row-label.mjs +114 -51
- package/main/serve.mjs +67 -5
- package/main/settings.mjs +223 -26
- package/main/ship-queue.mjs +279 -0
- package/main/sign-in-files.mjs +39 -0
- package/main/source-updater.mjs +298 -0
- package/main/store/home.mjs +47 -2
- package/main/store/work-items.mjs +150 -6
- package/main/store.mjs +235 -9
- package/main/supervisor.mjs +1444 -406
- package/main/task-commands.mjs +8 -10
- package/main/task-folders.mjs +74 -13
- package/main/task-remote-control.mjs +3 -3
- package/main/task-terminals.mjs +2 -1
- package/main/team/index.mjs +440 -0
- package/main/team/memory-cloud.mjs +247 -0
- package/main/team/projects.mjs +162 -0
- package/main/team/session.mjs +225 -0
- package/main/team/sign-in.mjs +106 -0
- package/main/team/supabase-backend.mjs +231 -0
- package/main/team/sync.mjs +163 -0
- package/main/updater.mjs +15 -5
- package/main/write-before-reload.mjs +50 -0
- package/mcp/core/page.mjs +9 -11
- package/mcp/core/work.mjs +91 -25
- package/mcp/tools.mjs +12 -6
- package/package.json +21 -9
- package/renderer/dist/assets/agentbox-icon-F1oN9nj_.svg +15 -0
- package/renderer/dist/assets/index-B-2Az952.css +32 -0
- package/renderer/dist/assets/index-D6qncgai.js +1168 -0
- package/renderer/dist/index.html +2 -2
- package/scripts/memory-gate-hook.sh +59 -0
- package/shared/agent-import.mjs +38 -15
- package/shared/agents.d.mts +26 -8
- package/shared/agents.mjs +100 -108
- package/shared/analytics-events.mjs +19 -2
- package/shared/answers.mjs +12 -0
- package/shared/bridge-map.d.mts +12 -0
- package/shared/bridge-map.mjs +37 -1
- package/shared/claude-commands.generated.mjs +2 -2
- package/shared/claude-models.generated.mjs +4 -4
- package/shared/claude-usage.mjs +6 -6
- package/shared/codex-import.mjs +7 -7
- package/shared/codex-modes.d.mts +50 -0
- package/shared/codex-usage.mjs +7 -8
- package/shared/demo-world.mjs +5 -5
- package/shared/engines.mjs +27 -10
- package/shared/feedback.d.mts +14 -0
- package/shared/feedback.mjs +44 -0
- package/shared/first-run-examples.mjs +4 -4
- package/shared/first-run-practice.d.mts +16 -0
- package/shared/first-run-practice.mjs +176 -70
- package/shared/fresh-user-home.mjs +22 -3
- package/shared/instruction-defaults.json +2 -2
- package/shared/product-name.mjs +4 -2
- package/shared/project-folder-check.mjs +6 -0
- package/shared/rank.d.mts +1 -0
- package/shared/rank.mjs +22 -0
- package/shared/referenced-files.mjs +1 -1
- package/shared/schemes.d.mts +11 -0
- package/shared/schemes.mjs +1 -1
- package/shared/shortcuts.d.mts +41 -0
- package/shared/shortcuts.mjs +236 -0
- package/shared/spawn-trouble.d.mts +2 -0
- package/shared/spawn-trouble.mjs +39 -18
- package/shared/team-rules.d.mts +17 -0
- package/shared/team-rules.mjs +230 -0
- package/shared/team-status.d.mts +11 -0
- package/shared/team-status.mjs +90 -0
- package/shared/terminal-links.d.mts +2 -0
- package/shared/terminal-links.mjs +55 -0
- package/shared/terminal-state.d.mts +1 -0
- package/shared/terminal-state.mjs +16 -0
- package/shared/thread-cards.d.mts +19 -0
- package/shared/thread-cards.mjs +254 -0
- package/shared/usage.d.mts +1 -1
- package/shared/usage.mjs +6 -7
- package/shared/work-items.mjs +255 -27
- package/shared/work-lines.mjs +393 -16
- package/worker-permissions.json +1 -1
- package/renderer/dist/assets/cel-dusk-CS5I7kJS.webp +0 -0
- package/renderer/dist/assets/cel-dusk-DUslqS6B.webp +0 -0
- package/renderer/dist/assets/cel-dusk-Jt_xVGxp.webp +0 -0
- package/renderer/dist/assets/cel-dusk-sm-BBkV-tWT.webp +0 -0
- package/renderer/dist/assets/frost-haze-CxPSOBEg.webp +0 -0
- package/renderer/dist/assets/frost-haze-sm-C_w21qgd.webp +0 -0
- package/renderer/dist/assets/ice-BC8luINc.webp +0 -0
- package/renderer/dist/assets/ice-CP9PrKHo.webp +0 -0
- package/renderer/dist/assets/ice-river-D6ziOhLY.webp +0 -0
- package/renderer/dist/assets/ice-river-UVM2-JY_.webp +0 -0
- package/renderer/dist/assets/ice-river-bErJwYWW.webp +0 -0
- package/renderer/dist/assets/ice-river-sm-Bg1U-SIj.webp +0 -0
- package/renderer/dist/assets/ice-sm-CbVcg3_D.webp +0 -0
- package/renderer/dist/assets/index-B7hhfHrT.js +0 -684
- package/renderer/dist/assets/index-CwiDv5bL.css +0 -32
- package/renderer/dist/assets/lake-C0WaW-6E.webp +0 -0
- package/renderer/dist/assets/lake-CSKjLC5K.webp +0 -0
- package/renderer/dist/assets/lake-ETGcOb25.webp +0 -0
- package/renderer/dist/assets/lake-harbour-BCQRbrHb.webp +0 -0
- package/renderer/dist/assets/lake-harbour-B_wfXTmE.webp +0 -0
- package/renderer/dist/assets/lake-harbour-Te1pEvBh.webp +0 -0
- package/renderer/dist/assets/lake-harbour-sm-Cme_ShEg.webp +0 -0
- package/renderer/dist/assets/lake-sm-CbG72Hbv.webp +0 -0
- package/renderer/dist/assets/lino-coast-CUZHcucI.webp +0 -0
- package/renderer/dist/assets/lino-coast-DP4J7cgd.webp +0 -0
- package/renderer/dist/assets/lino-coast-kOIAffr_.webp +0 -0
- package/renderer/dist/assets/lino-coast-sm-C1Mdbgit.webp +0 -0
- package/renderer/dist/assets/moon-pines-BskgnnXR.webp +0 -0
- package/renderer/dist/assets/moon-pines-CFSIIwt0.webp +0 -0
- package/renderer/dist/assets/moon-pines-PNhdOYww.webp +0 -0
- package/renderer/dist/assets/moon-pines-sm-C6K1NomK.webp +0 -0
- package/renderer/dist/assets/orbit-rings-2XV36Ch3.webp +0 -0
- package/renderer/dist/assets/orbit-rings-C4NrcYGQ.webp +0 -0
- package/renderer/dist/assets/orbit-rings-DGLk07dT.webp +0 -0
- package/renderer/dist/assets/orbit-rings-sm-Dky3YdvL.webp +0 -0
- package/renderer/dist/assets/peach-haze-2-C6f7xnWw.webp +0 -0
- package/renderer/dist/assets/peach-haze-2-sm-Dj_Ez_Sb.webp +0 -0
- package/renderer/dist/assets/pixel-harbour-DQjqMROg.webp +0 -0
- package/renderer/dist/assets/pixel-harbour-Dw71H_bc.webp +0 -0
- package/renderer/dist/assets/pixel-harbour-kOZfm-GM.webp +0 -0
- package/renderer/dist/assets/pixel-harbour-sm-Dturjuky.webp +0 -0
- package/renderer/dist/assets/pixel-orbit-C296JVMO.webp +0 -0
- package/renderer/dist/assets/pixel-orbit-C4oMRDSx.webp +0 -0
- package/renderer/dist/assets/pixel-orbit-CqVmQ4eh.webp +0 -0
- package/renderer/dist/assets/pixel-orbit-sm-CHagC_nO.webp +0 -0
- package/renderer/dist/assets/pixel-ridge-C6LYu6uE.webp +0 -0
- package/renderer/dist/assets/pixel-ridge-CIUCEESs.webp +0 -0
- package/renderer/dist/assets/pixel-ridge-sm-BnE0F_w-.webp +0 -0
- package/renderer/dist/assets/riso-hills-7heKVtry.webp +0 -0
- package/renderer/dist/assets/riso-hills-CIjAL3J6.webp +0 -0
- package/renderer/dist/assets/riso-hills-sm-DHsnbCfP.webp +0 -0
- package/renderer/dist/assets/slate-haze-BPWdkNsw.webp +0 -0
- package/renderer/dist/assets/slate-haze-sm-B0Cb5a2W.webp +0 -0
- package/renderer/dist/assets/valley-haze-BDHPqoJy.webp +0 -0
- package/renderer/dist/assets/valley-haze-sm-CTyjmPAG.webp +0 -0
- package/renderer/dist/assets/vector-dunes-DzzWLdKo.webp +0 -0
- package/renderer/dist/assets/vector-dunes-Yr9NBQUy.webp +0 -0
- package/renderer/dist/assets/vector-dunes-sm-D8MYY6ms.webp +0 -0
- package/renderer/dist/assets/watercolour-mist-BCGKN4u4.webp +0 -0
- package/renderer/dist/assets/watercolour-mist-BF-jk5MC.webp +0 -0
- package/renderer/dist/assets/watercolour-mist-sm-Ds1xzTw9.webp +0 -0
- package/renderer/dist/assets/woodblock-sea-B1um67Z9.webp +0 -0
- package/renderer/dist/assets/woodblock-sea-DKQdYs32.webp +0 -0
- package/renderer/dist/assets/woodblock-sea-sm-BJzNq8xh.webp +0 -0
- package/renderer/dist/emulator/audio-rules.mjs +0 -74
- package/renderer/dist/emulator/data/compression/README.md +0 -11
- package/renderer/dist/emulator/data/compression/extract7z.js +0 -1
- package/renderer/dist/emulator/data/compression/extractzip.js +0 -1
- package/renderer/dist/emulator/data/compression/libunrar.js +0 -519
- package/renderer/dist/emulator/data/compression/libunrar.wasm +0 -0
- package/renderer/dist/emulator/data/cores/README.md +0 -22
- package/renderer/dist/emulator/data/cores/mgba-legacy-wasm.data +0 -0
- package/renderer/dist/emulator/data/cores/mgba-thread-legacy-wasm.data +0 -0
- package/renderer/dist/emulator/data/cores/mgba-thread-wasm.data +0 -0
- package/renderer/dist/emulator/data/cores/mgba-wasm.data +0 -0
- package/renderer/dist/emulator/data/cores/package.json +0 -65
- package/renderer/dist/emulator/data/cores/reports/mgba.json +0 -1
- package/renderer/dist/emulator/data/emulator.css +0 -1614
- package/renderer/dist/emulator/data/loader.js +0 -170
- package/renderer/dist/emulator/data/localization/README.md +0 -63
- package/renderer/dist/emulator/data/localization/af-FR.json +0 -339
- package/renderer/dist/emulator/data/localization/ar-AR.json +0 -301
- package/renderer/dist/emulator/data/localization/ben-BEN.json +0 -301
- package/renderer/dist/emulator/data/localization/de-GER.json +0 -301
- package/renderer/dist/emulator/data/localization/el-GR.json +0 -301
- package/renderer/dist/emulator/data/localization/en-US.json +0 -339
- package/renderer/dist/emulator/data/localization/es-ES.json +0 -310
- package/renderer/dist/emulator/data/localization/fa-AF.json +0 -310
- package/renderer/dist/emulator/data/localization/hi-HI.json +0 -301
- package/renderer/dist/emulator/data/localization/it-IT.json +0 -302
- package/renderer/dist/emulator/data/localization/ja-JA.json +0 -301
- package/renderer/dist/emulator/data/localization/jv-JV.json +0 -301
- package/renderer/dist/emulator/data/localization/ko-KO.json +0 -336
- package/renderer/dist/emulator/data/localization/pt-BR.json +0 -361
- package/renderer/dist/emulator/data/localization/retroarch.json +0 -617
- package/renderer/dist/emulator/data/localization/ro-RO.json +0 -310
- package/renderer/dist/emulator/data/localization/ru-RU.json +0 -301
- package/renderer/dist/emulator/data/localization/tr-TR.json +0 -310
- package/renderer/dist/emulator/data/localization/vi-VN.json +0 -302
- package/renderer/dist/emulator/data/localization/zh-CN.json +0 -351
- package/renderer/dist/emulator/data/src/GameManager.js +0 -464
- package/renderer/dist/emulator/data/src/compression.js +0 -142
- package/renderer/dist/emulator/data/src/emulator.js +0 -6158
- package/renderer/dist/emulator/data/src/gamepad.js +0 -167
- package/renderer/dist/emulator/data/src/nipplejs.js +0 -1
- package/renderer/dist/emulator/data/src/shaders.js +0 -236
- package/renderer/dist/emulator/data/src/socket.io.min.js +0 -7
- package/renderer/dist/emulator/data/src/storage.js +0 -125
- package/renderer/dist/emulator/data/version.json +0 -5
- package/renderer/dist/emulator/host.js +0 -299
- package/renderer/dist/emulator/index.html +0 -28
- package/renderer/dist/emulator/provenance.json +0 -6
package/shared/agents.mjs
CHANGED
|
@@ -49,24 +49,22 @@ export function sameInstant(a, b) {
|
|
|
49
49
|
// already records each worker's sessionId when it spawns it. Either alone is
|
|
50
50
|
// enough; both means the fold cannot drift as one of them changes.
|
|
51
51
|
//
|
|
52
|
-
// This matters because without it Agentbox shouts its own work back at
|
|
53
|
-
// the raw
|
|
54
|
-
//
|
|
55
|
-
// a second row about themselves.
|
|
52
|
+
// This matters because without it Agentbox shouts its own work back at the
|
|
53
|
+
// user. In the raw list, Agentbox's own workers, already in the inbox as work
|
|
54
|
+
// items, showed up again as a second row about themselves.
|
|
56
55
|
export function startedByZero(agent, { pids = new Set(), sessionIds = new Set() } = {}) {
|
|
57
56
|
if (agent.sessionId && sessionIds.has(agent.sessionId)) return true;
|
|
58
57
|
return !!agent.ppid && pids.has(agent.ppid);
|
|
59
58
|
}
|
|
60
59
|
|
|
61
60
|
/* --------------------------- is it asking anything ----------------------- */
|
|
62
|
-
// A ROW THAT ASKS NOTHING DOES NOT GET FILED.
|
|
63
|
-
// place this feature could most easily break it:
|
|
64
|
-
//
|
|
65
|
-
//
|
|
66
|
-
//
|
|
67
|
-
//
|
|
68
|
-
//
|
|
69
|
-
// twelve are still listed, still findable, one keystroke away — they just do
|
|
61
|
+
// A ROW THAT ASKS NOTHING DOES NOT GET FILED. A standing rule, and the one
|
|
62
|
+
// place this feature could most easily break it: most outside agents on a
|
|
63
|
+
// machine are idle at any moment, and filing them all puts a wall of rows in
|
|
64
|
+
// the inbox that say "nothing is asked".
|
|
65
|
+
//
|
|
66
|
+
// So the inbox takes exactly the agents that are waiting on a human. The
|
|
67
|
+
// others are still listed, still findable, one keystroke away — they just do
|
|
70
68
|
// not interrupt.
|
|
71
69
|
export function asksSomething(agent) {
|
|
72
70
|
return agent.status === 'waiting';
|
|
@@ -79,14 +77,14 @@ export function asksSomething(agent) {
|
|
|
79
77
|
// "input needed" the agent finished its turn and is waiting for a human
|
|
80
78
|
// to say something next. A message IS that human turn.
|
|
81
79
|
// Proven on this machine 2026-08-16: a message written
|
|
82
|
-
// to a live session's socket arrived, was read as
|
|
83
|
-
// turn, and the agent went back to work.
|
|
80
|
+
// to a live session's socket arrived, was read as the
|
|
81
|
+
// human turn, and the agent went back to work.
|
|
84
82
|
//
|
|
85
83
|
// "permission prompt" the agent is frozen on a box asking to approve a tool
|
|
86
84
|
// call. A message queues BEHIND that box. Sending one
|
|
87
85
|
// would look like it worked and change nothing, which is
|
|
88
86
|
// the failure this codebase cares about most: the system
|
|
89
|
-
// swallowing something
|
|
87
|
+
// swallowing something the user said.
|
|
90
88
|
//
|
|
91
89
|
// So a reply box appears on the first and never on the second, and the second
|
|
92
90
|
// says out loud that it has to be answered where it is running.
|
|
@@ -105,7 +103,7 @@ export function replyReaches(agent) {
|
|
|
105
103
|
// there was nothing there to answer. That sentence was wrong.
|
|
106
104
|
//
|
|
107
105
|
// MEASURED 2026-08-17, not reasoned: a throwaway session was left sitting at
|
|
108
|
-
// its prompt with nothing asked
|
|
106
|
+
// its prompt with nothing asked, the exact state of the card in question, and
|
|
109
107
|
// the same line `reply` writes was written into its socket. It arrived, the
|
|
110
108
|
// session read it and went back to work and answered it. An idle session is
|
|
111
109
|
// listening; idle is what a session at its prompt IS.
|
|
@@ -142,12 +140,12 @@ export function replyIsSwallowed(agent) {
|
|
|
142
140
|
// because a timer here ran out.
|
|
143
141
|
//
|
|
144
142
|
// The comparison is `>`, against the stamp and not the status alone, because
|
|
145
|
-
// the session is still idle for the moment or two between
|
|
146
|
-
// it picking the message up. Reading the status alone would send the
|
|
147
|
-
// straight back to the inbox, which is the bug
|
|
143
|
+
// the session is still idle for the moment or two between the user pressing
|
|
144
|
+
// send and it picking the message up. Reading the status alone would send the
|
|
145
|
+
// row straight back to the inbox, which is the original bug wearing a hat.
|
|
148
146
|
//
|
|
149
147
|
// AND THE ONE SESSION THIS CANNOT PROMISE ANYTHING ABOUT: one that publishes no
|
|
150
|
-
// status at all (
|
|
148
|
+
// status at all (an older CLI). Agentbox cannot see that one work
|
|
151
149
|
// and cannot see it stop, so it is not moved anywhere and the reply is still
|
|
152
150
|
// delivered. A promise that could never be kept is worse than no promise.
|
|
153
151
|
export function tookHerReply(agent) {
|
|
@@ -193,7 +191,7 @@ export function agentKey(agent) {
|
|
|
193
191
|
return `pid:${agent?.pid ?? 0}:${agent?.startedAt ?? 0}`;
|
|
194
192
|
}
|
|
195
193
|
|
|
196
|
-
// The moment
|
|
194
|
+
// The moment the user said they would deal with it. A past moment is not a deferral:
|
|
197
195
|
// once it passes the row is back, which is the same predicate rule work items
|
|
198
196
|
// follow. So a missed one comes back late rather than being lost, and nothing
|
|
199
197
|
// has to fire at 8am.
|
|
@@ -214,7 +212,7 @@ export function putOff(agent, now = Date.now()) {
|
|
|
214
212
|
// session exists. WHAT THIS COSTS, stated rather than hidden: a session she
|
|
215
213
|
// closes while it is working will not return to her inbox when it later stops
|
|
216
214
|
// and asks something. That is the same sentence read the other way, and it is
|
|
217
|
-
// the one
|
|
215
|
+
// the one that was chosen.
|
|
218
216
|
//
|
|
219
217
|
// "UNLESS ASKED OTHERWISE" IS THE UNDO, and it is why this stays a number in
|
|
220
218
|
// the file instead of becoming a boolean: `close(key, 0)` clears it, which is
|
|
@@ -229,8 +227,8 @@ export function putAway(agent) {
|
|
|
229
227
|
}
|
|
230
228
|
|
|
231
229
|
/* -------------------------------- the words ------------------------------ */
|
|
232
|
-
// Plain sentences, no jargon, no metaphor
|
|
233
|
-
//
|
|
230
|
+
// Plain sentences, no jargon, no metaphor, and the first line of the body is
|
|
231
|
+
// the one thing the user has to do about it, in bold, one
|
|
234
232
|
// sentence, under fifteen words (instructions.md). The row clips at
|
|
235
233
|
// SUMMARY_BUDGET = 112 characters on the last full stop inside it, so that
|
|
236
234
|
// sentence has to carry the whole point on its own.
|
|
@@ -260,7 +258,7 @@ export function whereItRuns(agent) {
|
|
|
260
258
|
// goes because a card is not a diff viewer.
|
|
261
259
|
//
|
|
262
260
|
// Split out from `oneSentence` when `howItEnded` needed the same cleaning from
|
|
263
|
-
// the other end of the message. One copy, so a quote of
|
|
261
|
+
// the other end of the message. One copy, so a quote of the user's and a quote of its
|
|
264
262
|
// answer can never be tidied by two different rules.
|
|
265
263
|
function readableWords(raw) {
|
|
266
264
|
return String(raw ?? '')
|
|
@@ -331,26 +329,25 @@ function saidWhen(agent, now) {
|
|
|
331
329
|
return `**It answered ${when}:**`;
|
|
332
330
|
}
|
|
333
331
|
|
|
334
|
-
// THE LAST THING
|
|
335
|
-
// `last-prompt` line, so it is
|
|
332
|
+
// THE LAST THING THE USER TYPED INTO IT. Read straight off the session's own
|
|
333
|
+
// `last-prompt` line, so it is the user's turn and never a tool result wearing a user
|
|
336
334
|
// message's clothes.
|
|
337
335
|
export function lastAsk(agent, budget = 180) {
|
|
338
336
|
return oneSentence(agent.lastAsked, budget);
|
|
339
337
|
}
|
|
340
338
|
|
|
341
339
|
/* ------------------------------- what it IS ------------------------------ */
|
|
342
|
-
//
|
|
340
|
+
// A card whose loudest word is `session-71` says nothing. A session name is a
|
|
343
341
|
// handle, not a memory.
|
|
344
342
|
//
|
|
345
343
|
// Every Claude Code session writes a one-line title of ITSELF into its own
|
|
346
|
-
// transcript and keeps it current.
|
|
347
|
-
//
|
|
348
|
-
//
|
|
349
|
-
// days old, sitting in a file Agentbox was already reading and throwing away.
|
|
344
|
+
// transcript and keeps it current. Every outside session measured had one, and
|
|
345
|
+
// it is usually the very sentence a person would use to recall the work,
|
|
346
|
+
// sitting in a file Agentbox was already reading and throwing away.
|
|
350
347
|
//
|
|
351
348
|
// So the title of the row is what the work IS, with the session's name in front
|
|
352
|
-
// of it because
|
|
353
|
-
//
|
|
349
|
+
// of it because two sessions can run in the same folder and the name is how
|
|
350
|
+
// they are told apart. When a session has no title of its own the row says
|
|
354
351
|
// what it used to say, which is better than a blank.
|
|
355
352
|
export function whatItIs(agent) {
|
|
356
353
|
return String(agent?.about ?? '').replace(/\s+/g, ' ').trim();
|
|
@@ -361,57 +358,56 @@ export function agentTitle(agent, now = Date.now()) {
|
|
|
361
358
|
if (about) return `${agent.name}: ${about}`;
|
|
362
359
|
if (replyReaches(agent)) return `${agent.name} is waiting for you`;
|
|
363
360
|
if (asksSomething(agent)) return `${agent.name} needs you where it is running`;
|
|
364
|
-
// NOT "QUIET" ONCE
|
|
361
|
+
// NOT "QUIET" ONCE THE USER HAS SPOKEN TO IT. Without this the row just
|
|
365
362
|
// replied to sat in In progress under a heading saying it had been quiet for
|
|
366
|
-
// three days, which is the same sentence it wore before
|
|
363
|
+
// three days, which is the same sentence it wore before anything was said.
|
|
367
364
|
if (tookHerReply(agent)) return `${agent.name} is working on what you told it`;
|
|
368
365
|
return `${agent.name} has been quiet for ${howLong(now - (agent.lastActiveAt ?? agent.startedAt ?? now))}`;
|
|
369
366
|
}
|
|
370
367
|
|
|
371
368
|
/* ------------------------------ RECALLING IT ----------------------------- */
|
|
372
|
-
//
|
|
373
|
-
//
|
|
369
|
+
// A card that carries only the title and the last thing typed is not enough to
|
|
370
|
+
// recall a session.
|
|
374
371
|
//
|
|
375
372
|
// WHAT WAS MISSING WAS THE BEGINNING, and it is the one thing on a transcript
|
|
376
|
-
// that never changes.
|
|
377
|
-
//
|
|
378
|
-
//
|
|
379
|
-
// is
|
|
380
|
-
// perfectly true, and no help whatsoever in remembering what the thing is for.
|
|
373
|
+
// that never changes. In every live session measured, the FIRST message was
|
|
374
|
+
// the ask, and no card had ever shown it. `last-prompt` is the LAST thing the
|
|
375
|
+
// user typed, and days into a session that is usually a short follow-up that
|
|
376
|
+
// is perfectly true and no help whatsoever in remembering what the thing is for.
|
|
381
377
|
//
|
|
382
|
-
//
|
|
383
|
-
//
|
|
384
|
-
//
|
|
385
|
-
//
|
|
378
|
+
// The human side of a conversation is also small enough to just print: a
|
|
379
|
+
// handful of turns per session, a sentence or two each. The megabytes in a
|
|
380
|
+
// transcript are the agent's half. So the recall is the user's own words, read
|
|
381
|
+
// off the file, and no model sees any of it.
|
|
386
382
|
//
|
|
387
383
|
// ONE SHAPE, NOT THREE, AND IT IS NOT CONFIGURABLE.
|
|
388
384
|
//
|
|
389
|
-
// So the card does the same thing on every session: the message
|
|
390
|
-
// with, up to three later messages of
|
|
391
|
-
// working. `ask` and `trail` are gone, and there is deliberately no
|
|
392
|
-
// this
|
|
393
|
-
// judgement
|
|
385
|
+
// So the card does the same thing on every session: the message the user
|
|
386
|
+
// started it with, up to three later messages of theirs, where it stopped, and
|
|
387
|
+
// where it is working. `ask` and `trail` are gone, and there is deliberately no
|
|
388
|
+
// setting for this: deciding per session which of them a card deserves is a
|
|
389
|
+
// judgement that should not be made, whether by a model or by a knob.
|
|
394
390
|
|
|
395
|
-
// The messages
|
|
391
|
+
// The messages the user typed, oldest first, with the newest ones kept whole and the
|
|
396
392
|
// opening always present.
|
|
397
393
|
//
|
|
398
394
|
// AN EMPTY LIST IS NOT A FALLBACK TO `lastAsked`, and the difference is the
|
|
399
395
|
// whole point of this change rather than a nicety. A session whose transcript
|
|
400
|
-
// could not be read has exactly one thing
|
|
401
|
-
// LAST one. So the caller is told which of the two it has. WHAT
|
|
402
|
-
// AGENTBOX IS ALSO WHAT
|
|
396
|
+
// could not be read has exactly one thing the user typed on record, and it is
|
|
397
|
+
// the LAST one. So the caller is told which of the two it has. WHAT THE USER
|
|
398
|
+
// SAID FROM AGENTBOX IS ALSO WHAT THE USER SAID.
|
|
403
399
|
//
|
|
404
|
-
// So the card went on saying only what
|
|
400
|
+
// So the card went on saying only what the session was started with.
|
|
405
401
|
//
|
|
406
402
|
// `spoke` is the other half, written by main/agent-schedule.mjs at the moment
|
|
407
403
|
// of delivery. It is a RECORD, not a guess: Agentbox does not try to work out
|
|
408
|
-
// which wrapped peer message in a transcript was
|
|
409
|
-
// sessions pinging this one is a real peer and drawing that as
|
|
410
|
-
// put a sentence
|
|
404
|
+
// which wrapped peer message in a transcript was the user's, because another of
|
|
405
|
+
// their sessions pinging this one is a real peer and drawing that as the user's
|
|
406
|
+
// words would put a sentence they never typed on the one card built to be trusted.
|
|
411
407
|
//
|
|
412
408
|
// Merged by time, so the thread reads forwards however it arrived, and deduped
|
|
413
|
-
// on the text because a session that DOES record
|
|
414
|
-
// (a future Claude Code, or one
|
|
409
|
+
// on the text because a session that DOES record the user's injected turn as
|
|
410
|
+
// its own (a future Claude Code, or one typed into directly) must not show it
|
|
415
411
|
// twice.
|
|
416
412
|
export function herWords(agent) {
|
|
417
413
|
const asked = (agent?.asked ?? []).filter((t) => t && t.text);
|
|
@@ -434,11 +430,11 @@ export function herWords(agent) {
|
|
|
434
430
|
return first ? [first, ...rest] : [];
|
|
435
431
|
}
|
|
436
432
|
|
|
437
|
-
// WHICH OF
|
|
438
|
-
// answer is how long they are.
|
|
439
|
-
// driving it, not describing it:
|
|
440
|
-
//
|
|
441
|
-
//
|
|
433
|
+
// WHICH OF THE USER'S MESSAGES ACTUALLY RECALL ANYTHING, and the cheapest
|
|
434
|
+
// honest answer is how long they are. Much of what a person types while an
|
|
435
|
+
// agent works is driving it, not describing it: short nudges to restart,
|
|
436
|
+
// carry on or approve are almost always under sixty characters, while a turn
|
|
437
|
+
// that describes the work typically runs well past a hundred.
|
|
442
438
|
//
|
|
443
439
|
// So the long ones are preferred, and the short ones are still there when
|
|
444
440
|
// there is nothing longer, because a card that drops to silence is worse.
|
|
@@ -459,7 +455,7 @@ function ago(at, now) {
|
|
|
459
455
|
return `${howLong(gap)} ago`;
|
|
460
456
|
}
|
|
461
457
|
|
|
462
|
-
// The rest of the context, in
|
|
458
|
+
// The rest of the context, in the user's sentences: what they asked for, where the
|
|
463
459
|
// thread got to, what it last said back, and what it has had its hands on.
|
|
464
460
|
function context(agent, now = Date.now()) {
|
|
465
461
|
const words = herWords(agent);
|
|
@@ -472,13 +468,13 @@ function context(agent, now = Date.now()) {
|
|
|
472
468
|
const when = ago(opening.at, now);
|
|
473
469
|
lines.push(`**You started it${when ? ` ${when}` : ''} with:**\n\n“${oneSentence(opening.text, 420)}”`);
|
|
474
470
|
} else {
|
|
475
|
-
// No history, so the only thing on record is the LAST thing
|
|
471
|
+
// No history, so the only thing on record is the LAST thing the user typed, and
|
|
476
472
|
// it gets the label that is true of it.
|
|
477
473
|
const last = lastAsk(agent);
|
|
478
474
|
if (last) lines.push(`**The last thing you told it:**\n\n“${last}”`);
|
|
479
475
|
}
|
|
480
476
|
|
|
481
|
-
// Everything else
|
|
477
|
+
// Everything else the user typed, oldest first, so the thread reads forwards.
|
|
482
478
|
// Three of them; more than that is the transcript rather than a card.
|
|
483
479
|
if (rest.length) {
|
|
484
480
|
const recent = worthRecalling(rest).slice(-3);
|
|
@@ -586,10 +582,10 @@ export function reachesInbox(agent, now = Date.now(), mode = 'all') {
|
|
|
586
582
|
// argument is not taken because a reply cancels a deferral (`replyClearsSchedule`
|
|
587
583
|
// does the same for work items) — she spoke to it, so it is not put off any more.
|
|
588
584
|
//
|
|
589
|
-
// THIS IS NOT `reachesProgress`, WHICH
|
|
590
|
-
// purpose. It stays dead: a working session
|
|
591
|
-
// inbox, exactly as
|
|
592
|
-
// the reply
|
|
585
|
+
// THIS IS NOT `reachesProgress`, WHICH WAS REMOVED, and the name is different
|
|
586
|
+
// on purpose. It stays dead: a working session the user has not spoken to is in
|
|
587
|
+
// the inbox, exactly as they left it. What moves a row here is THE USER, and
|
|
588
|
+
// only the user: the reply they wrote.
|
|
593
589
|
export function progressAfterReply(agent, now = Date.now(), mode = 'all') {
|
|
594
590
|
if (agent.startedByZero) return false;
|
|
595
591
|
if (mode === 'off') return false;
|
|
@@ -603,7 +599,7 @@ export function listed(agent) {
|
|
|
603
599
|
}
|
|
604
600
|
|
|
605
601
|
/* --------------------- ACTIVE AGENTS, IN THE SIDEBAR --------------------- */
|
|
606
|
-
//
|
|
602
|
+
// The design: one line per session in its own words,
|
|
607
603
|
// the clock on the right, and no dot, mark, colour, wash, edge or line of any
|
|
608
604
|
// kind.
|
|
609
605
|
//
|
|
@@ -611,8 +607,8 @@ export function listed(agent) {
|
|
|
611
607
|
// where the rule lives, because it decides what the rule can be: nothing
|
|
612
608
|
// FINISHED is ever on this list and never has been. `main/agents.mjs` drops any
|
|
613
609
|
// record whose process is gone, so a session that finishes exits and disappears
|
|
614
|
-
// by itself. Measured
|
|
615
|
-
//
|
|
610
|
+
// by itself. Measured: most live sessions were terminals sitting at a prompt
|
|
611
|
+
// for between two and seven days.
|
|
616
612
|
// So length comes from sessions that are alive and forgotten, and a day is
|
|
617
613
|
// where the app's own clock (`format.ts`) stops saying hours and starts saying
|
|
618
614
|
// `1d`. The panel therefore holds exactly what the clock beside each row can
|
|
@@ -649,21 +645,19 @@ export function byRecency(a, b) {
|
|
|
649
645
|
}
|
|
650
646
|
|
|
651
647
|
/* --------------------------- THE CONVERSATION ---------------------------- */
|
|
652
|
-
//
|
|
653
|
-
//
|
|
654
|
-
//
|
|
655
|
-
// whether she asked or not, so it is four sentences; this is only ever drawn
|
|
656
|
-
// because she pressed something, so it can be the conversation.
|
|
648
|
+
// THE CARD IS THE RECALL AND THIS IS THE REST OF IT. The card is drawn for the
|
|
649
|
+
// user whether they asked or not, so it is four sentences; this is only ever
|
|
650
|
+
// drawn because they pressed something, so it can be the conversation.
|
|
657
651
|
//
|
|
658
|
-
// STILL NO MODEL, AND NOW NO COST AT ALL UNTIL
|
|
659
|
-
//
|
|
660
|
-
//
|
|
661
|
-
//
|
|
662
|
-
//
|
|
652
|
+
// STILL NO MODEL, AND NOW NO COST AT ALL UNTIL IT IS PRESSED. Measured: the
|
|
653
|
+
// readable conversation is 0.6% of a transcript's bytes, and the worst single
|
|
654
|
+
// file measured (160MB) carries 3,800 readable turns, 2.6MB of text, 729ms to
|
|
655
|
+
// pull out. That last number is why the read is streamed and never happens on
|
|
656
|
+
// a draw.
|
|
663
657
|
//
|
|
664
658
|
// WHY IT IS A WINDOW AND NOT THE WHOLE FILE. 3,800 turns is not a conversation
|
|
665
|
-
//
|
|
666
|
-
// is the ask in
|
|
659
|
+
// anyone can get up to speed on, it is a scroll bar. So it is the opening,
|
|
660
|
+
// which is the ask in every session measured, and the end, which is where it got to,
|
|
667
661
|
// and one plain line saying how many are in between rather than pretending
|
|
668
662
|
// there are none.
|
|
669
663
|
export const TRAIL_OPENING = 3;
|
|
@@ -681,12 +675,11 @@ export function conversationWindow(turns, { opening = TRAIL_OPENING, keep = TRAI
|
|
|
681
675
|
// because "some messages" is the kind of sentence that makes her wonder what
|
|
682
676
|
// else the app is rounding off.
|
|
683
677
|
//
|
|
684
|
-
//
|
|
685
|
-
//
|
|
686
|
-
//
|
|
687
|
-
//
|
|
688
|
-
//
|
|
689
|
-
// road, so a thread that had eaten her follow-up simply said so and stopped.
|
|
678
|
+
// And it is not rare. Rebuilding every row's thread the way the pane draws it,
|
|
679
|
+
// nearly half the rows with a conversation hide part of it, many of them
|
|
680
|
+
// hiding messages the user wrote, and the line was a plain div with nothing to
|
|
681
|
+
// press. "Not shown" was true and it was also the end of the road, so a thread
|
|
682
|
+
// that had eaten a follow-up simply said so and stopped.
|
|
690
683
|
//
|
|
691
684
|
// So the words say what pressing does. The window itself is untouched: it still
|
|
692
685
|
// opens on the end of a long conversation, because an 18,100px page is the
|
|
@@ -700,17 +693,17 @@ export function conversationGap(omitted) {
|
|
|
700
693
|
// So the item is the conversation, and each thing the agent ran sits on its own
|
|
701
694
|
// quiet line between the messages, in the order it happened. This half of the
|
|
702
695
|
// file decides what one of those lines SAYS. What it looks like is the frosted
|
|
703
|
-
// treatment
|
|
696
|
+
// treatment chosen in round two and lives in the stylesheet.
|
|
704
697
|
//
|
|
705
|
-
// WHY IT IS BOUNDED THREE WAYS, all measured over the 40 largest transcripts
|
|
706
|
-
//
|
|
698
|
+
// WHY IT IS BOUNDED THREE WAYS, all measured over the 40 largest transcripts
|
|
699
|
+
// available:
|
|
707
700
|
//
|
|
708
701
|
// * one session held 6,070 tool calls and 8MB of output. So output is capped
|
|
709
702
|
// per line (WORK_CHARS) rather than sent whole.
|
|
710
703
|
// * the longest unbroken run of tool calls between two messages was 111, and
|
|
711
704
|
// the median session's longest run was 25. So a run is capped (WORK_RUN)
|
|
712
705
|
// and says how many it is not showing, because 111 quiet lines standing
|
|
713
|
-
// between
|
|
706
|
+
// between a question and its answer is the original problem wearing a
|
|
714
707
|
// different hat.
|
|
715
708
|
// * a windowed thread of 40 messages could still carry thousands of work
|
|
716
709
|
// lines, so the whole thread is capped too (WORK_TOTAL), oldest first.
|
|
@@ -723,12 +716,12 @@ export const WORK_RUN = 20;
|
|
|
723
716
|
export const WORK_TOTAL = 200;
|
|
724
717
|
|
|
725
718
|
// WHAT A TOOL CALL SAYS lives in its own file now (`shared/work-lines.mjs`),
|
|
726
|
-
// because
|
|
719
|
+
// because a report on the imported threads turned one rule into
|
|
727
720
|
// three: the verb, the subject and the fold. It is re-exported here so that
|
|
728
721
|
// nothing that already reads this file has to learn a second import.
|
|
729
722
|
export {
|
|
730
|
-
workVerb, workSubject, fullSubject, shortPath, plainCommand,
|
|
731
|
-
groupWork, runSummary, runFailures, RUN_MIN,
|
|
723
|
+
workVerb, workSubject, fullSubject, shortPath, plainCommand, commandWork,
|
|
724
|
+
groupWork, runSummary, runFailures, RUN_MIN, isBookkeeping,
|
|
732
725
|
changedFile, fileInChange, CHANGES_A_FILE,
|
|
733
726
|
} from './work-lines.mjs';
|
|
734
727
|
|
|
@@ -755,8 +748,8 @@ export function outputCut(shownLines, allLines) {
|
|
|
755
748
|
//
|
|
756
749
|
// `whole` IS WHAT THE GAP LINE PRESSES. Every message stands, and nothing else
|
|
757
750
|
// changes: the work is still capped by `capRuns` below, because 530 tool calls
|
|
758
|
-
// is not a conversation and
|
|
759
|
-
// under them. Opening it is
|
|
751
|
+
// is not a conversation and what is wanted is the follow-ups, not the output
|
|
752
|
+
// under them. Opening it is the user's decision and it lasts until they leave the row,
|
|
760
753
|
// so no thread is ever born at this size.
|
|
761
754
|
export function threadWindow(events, { opening = TRAIL_OPENING, keep = TRAIL_TURNS, whole = false } = {}) {
|
|
762
755
|
const all = (events ?? []).filter((e) => e && (e.kind === 'work' ? true : !!e.text));
|
|
@@ -884,15 +877,14 @@ export function saidCount(events) {
|
|
|
884
877
|
// A provider writing a tool call sometimes emits its closing tags as ordinary
|
|
885
878
|
// text, and the field it was writing then holds the answer with the machinery
|
|
886
879
|
// of the call still stuck to the end. On w-b108b1d596 the result that reached
|
|
887
|
-
//
|
|
888
|
-
// Measured
|
|
889
|
-
// and 50 messages on screen.
|
|
880
|
+
// the pane ended "7,369 tests both times.</result>\n</invoke>" and was shown as
|
|
881
|
+
// is. Measured: dozens of field writes across dozens of rows carried it.
|
|
890
882
|
//
|
|
891
883
|
// IT ALSO BREAKS THE FOLD THAT SAYS ONE THING ONCE. That run noticed the leak
|
|
892
884
|
// and wrote its result again, clean. The fold keeps the FULLER of two copies of
|
|
893
885
|
// one answer, and the junk made the broken copy the fuller one, so the leak was
|
|
894
886
|
// what stayed on the screen and the good rewrite was the copy thrown away. That
|
|
895
|
-
// is
|
|
887
|
+
// is what happened on that row, and it is why the cut happens before anything
|
|
896
888
|
// compares two messages.
|
|
897
889
|
//
|
|
898
890
|
// The cut runs from the first tag to the end, because nothing after one is
|
|
@@ -25,6 +25,15 @@ export const EVENTS = {
|
|
|
25
25
|
task_opened: 'A task was opened',
|
|
26
26
|
reply_sent: 'A reply was sent',
|
|
27
27
|
task_finished: 'A task finished',
|
|
28
|
+
// REAL USE, NOT ONLY THE WALKTHROUGH (2026-10-06). Every "task finished" on
|
|
29
|
+
// the day downloads opened was somebody closing practice rows in setup; there
|
|
30
|
+
// was no count of an agent doing real work, of where setup was left, or of an
|
|
31
|
+
// install being used on a day, which is what retention is read from.
|
|
32
|
+
day_active: `${Name} was used today`,
|
|
33
|
+
first_run_step: 'A setup step was reached',
|
|
34
|
+
task_written: 'A task was written',
|
|
35
|
+
run_started: 'An agent started work',
|
|
36
|
+
run_finished: 'An agent stopped work',
|
|
28
37
|
};
|
|
29
38
|
|
|
30
39
|
export const EVENT_NAMES = Object.keys(EVENTS);
|
|
@@ -39,11 +48,15 @@ export const ALLOWED_PROPS = new Set([
|
|
|
39
48
|
'count', // how many of a thing, never which ones
|
|
40
49
|
'kind', // -> KINDS below, an enum and nothing else
|
|
41
50
|
'fromAgent', // whether an agent or the founder did it
|
|
51
|
+
'failed', // whether an agent's run ended in failure
|
|
52
|
+
'practice', // whether it happened in setup's practice project
|
|
53
|
+
'engine', // -> ENGINES below, which coding agent ran
|
|
42
54
|
]);
|
|
43
55
|
|
|
44
|
-
// `kind`
|
|
45
|
-
// value outside it is dropped, not passed through.
|
|
56
|
+
// `kind` and `engine` are the properties that are not numbers, so each is a
|
|
57
|
+
// closed list. A value outside it is dropped, not passed through.
|
|
46
58
|
export const KINDS = new Set(['task', 'question', 'review', 'directive', 'agent', 'digest']);
|
|
59
|
+
export const ENGINES = new Set(['claude', 'codex']);
|
|
47
60
|
|
|
48
61
|
// Refuse an event nobody approved; drop a property nobody approved. Returns the
|
|
49
62
|
// payload that may be sent, or null when the event itself is not one of hers.
|
|
@@ -56,6 +69,10 @@ export function sanitize(name, props = {}) {
|
|
|
56
69
|
if (typeof value === 'string' && KINDS.has(value)) out.kind = value;
|
|
57
70
|
continue;
|
|
58
71
|
}
|
|
72
|
+
if (key === 'engine') {
|
|
73
|
+
if (typeof value === 'string' && ENGINES.has(value)) out.engine = value;
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
59
76
|
if (typeof value === 'number' && Number.isFinite(value)) out[key] = value;
|
|
60
77
|
else if (typeof value === 'boolean') out[key] = value;
|
|
61
78
|
}
|
package/shared/answers.mjs
CHANGED
|
@@ -78,3 +78,15 @@ export function answerSettled(item) {
|
|
|
78
78
|
export function answerTs(item) {
|
|
79
79
|
return item?.wrote?.answer?.ts ?? 0;
|
|
80
80
|
}
|
|
81
|
+
|
|
82
|
+
// SHE STOPPED THIS ROW AND HAS NOT SPOKEN SINCE. Stop writes `blocked` in her
|
|
83
|
+
// hand (zero:stop-session), and it promises the row stays in her inbox until
|
|
84
|
+
// she replies, resumes it or sends it back. A reply she wrote BEFORE the stop
|
|
85
|
+
// is not one of those, though a kill hands it back to the queue: that is how a
|
|
86
|
+
// stopped run came straight back ten seconds later (2026-10-01).
|
|
87
|
+
// tests/a-stopped-agent-stays-stopped-until-she-resumes-it.test.mjs
|
|
88
|
+
export function stoppedByHer(item) {
|
|
89
|
+
const status = item?.wrote?.status;
|
|
90
|
+
return item?.status === 'blocked' && status?.source === 'founder'
|
|
91
|
+
&& answerTs(item) <= (status.ts ?? 0);
|
|
92
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// Types for shared/bridge-map.mjs, for the window side.
|
|
2
|
+
//
|
|
3
|
+
// EVERY ONE OF THESE IS A PHONE BOOK AND IS TYPED AS ONE. Naming the hundred
|
|
4
|
+
// and thirty keys over again here would be a second copy of the list the file
|
|
5
|
+
// exists to be the only copy of, and the first one to fall behind it. What the
|
|
6
|
+
// screen needs from a type is that a channel is a string and a wrap is a list
|
|
7
|
+
// of argument names; which names exist is checked against preload.cjs at test
|
|
8
|
+
// time instead (tests/both-front-doors-offer-the-same-bridge.test.mjs).
|
|
9
|
+
export declare const REQUEST_CHANNELS: Readonly<Record<string, string>>;
|
|
10
|
+
export declare const PUSH_CHANNELS: Readonly<Record<string, string>>;
|
|
11
|
+
export declare const WRAPPED_ARGS: Readonly<Record<string, string[]>>;
|
|
12
|
+
export declare const DESKTOP_ONLY: readonly string[];
|
package/shared/bridge-map.mjs
CHANGED
|
@@ -13,7 +13,10 @@
|
|
|
13
13
|
/** Asked, and the screen waits for the answer. */
|
|
14
14
|
export const REQUEST_CHANNELS = {
|
|
15
15
|
terminal: 'zero:terminal',
|
|
16
|
+
agentUpdate: 'zero:agent-update',
|
|
16
17
|
snapshot: 'zero:snapshot',
|
|
18
|
+
// The next page of old finished threads, at the foot of Done and All.
|
|
19
|
+
olderItems: 'zero:older-items',
|
|
17
20
|
dashboard: 'zero:dashboard',
|
|
18
21
|
commandCatalog: 'zero:command-catalog',
|
|
19
22
|
remoteControl: 'zero:remote-control',
|
|
@@ -21,8 +24,32 @@ export const REQUEST_CHANNELS = {
|
|
|
21
24
|
compact: 'zero:compact',
|
|
22
25
|
compactionStatus: 'zero:compaction-status',
|
|
23
26
|
answer: 'zero:answer',
|
|
27
|
+
sendNow: 'zero:send-now',
|
|
24
28
|
compose: 'zero:compose',
|
|
25
29
|
schedule: 'zero:schedule',
|
|
30
|
+
// Feedback to the Agentbox team, from the sidebar's Feedback card.
|
|
31
|
+
sendFeedback: 'zero:send-feedback',
|
|
32
|
+
// The team version: signing in, the team, sharing, routing a given task.
|
|
33
|
+
teamSignIn: 'zero:team-sign-in',
|
|
34
|
+
teamSignInCancel: 'zero:team-sign-in-cancel',
|
|
35
|
+
teamSignInReopen: 'zero:team-sign-in-reopen',
|
|
36
|
+
teamSignOut: 'zero:team-sign-out',
|
|
37
|
+
teamSignInEmail: 'zero:team-sign-in-email',
|
|
38
|
+
teamSignUp: 'zero:team-sign-up',
|
|
39
|
+
teamCreate: 'zero:team-create',
|
|
40
|
+
teamInvite: 'zero:team-invite',
|
|
41
|
+
teamRename: 'zero:team-rename',
|
|
42
|
+
teamRemoveMember: 'zero:team-remove-member',
|
|
43
|
+
teamLeave: 'zero:team-leave',
|
|
44
|
+
teamCancelInvite: 'zero:team-cancel-invite',
|
|
45
|
+
teamAcceptInvite: 'zero:team-accept-invite',
|
|
46
|
+
teamStatus: 'zero:team-status',
|
|
47
|
+
teamShare: 'zero:team-share',
|
|
48
|
+
teamSync: 'zero:team-sync',
|
|
49
|
+
teamRoute: 'zero:team-route',
|
|
50
|
+
teamReact: 'zero:team-react',
|
|
51
|
+
teamMessage: 'zero:team-message',
|
|
52
|
+
threadEdit: 'zero:thread-edit',
|
|
26
53
|
repeats: 'zero:repeats',
|
|
27
54
|
composeRepeat: 'zero:compose-repeat',
|
|
28
55
|
setRepeat: 'zero:set-repeat',
|
|
@@ -50,6 +77,7 @@ export const REQUEST_CHANNELS = {
|
|
|
50
77
|
updateInstall: 'zero:update-install',
|
|
51
78
|
notify: 'zero:notify',
|
|
52
79
|
stopSession: 'zero:stop-session',
|
|
80
|
+
runNow: 'zero:run-now',
|
|
53
81
|
reopen: 'zero:reopen',
|
|
54
82
|
instructionRead: 'zero:instruction-read',
|
|
55
83
|
instructionWrite: 'zero:instruction-write',
|
|
@@ -62,11 +90,14 @@ export const REQUEST_CHANNELS = {
|
|
|
62
90
|
settingsRead: 'zero:settings-read',
|
|
63
91
|
claudeRecheck: 'zero:claude-recheck',
|
|
64
92
|
codexRecheck: 'zero:codex-recheck',
|
|
93
|
+
engineSetup: 'zero:engine-setup',
|
|
65
94
|
codexAddAccount: 'zero:codex-add-account',
|
|
66
95
|
claudeAddAccount: 'zero:claude-add-account',
|
|
67
96
|
setProjectSetting: 'zero:settings-set-project',
|
|
68
97
|
setWorkspaceSetting: 'zero:settings-set-workspace',
|
|
69
98
|
projectRename: 'zero:project-rename',
|
|
99
|
+
projectArchive: 'zero:project-archive',
|
|
100
|
+
projectSeenBy: 'zero:project-seen-by',
|
|
70
101
|
projectIcon: 'zero:project-icon',
|
|
71
102
|
projectIconClear: 'zero:project-icon-clear',
|
|
72
103
|
projectInstructionsRead: 'zero:project-instructions-read',
|
|
@@ -78,6 +109,7 @@ export const REQUEST_CHANNELS = {
|
|
|
78
109
|
sessionTrace: 'zero:session-trace',
|
|
79
110
|
itemHistory: 'zero:item-history',
|
|
80
111
|
openArtifact: 'zero:open-artifact',
|
|
112
|
+
folderPictures: 'zero:folder-pictures',
|
|
81
113
|
readDoc: 'zero:read-doc',
|
|
82
114
|
codeChange: 'zero:code-change',
|
|
83
115
|
codeFile: 'zero:code-file',
|
|
@@ -125,4 +157,8 @@ export const WRAPPED_ARGS = {
|
|
|
125
157
|
// Electron can tell you the real path of a file somebody dropped onto the
|
|
126
158
|
// window. A browser cannot, by design, and no server can answer it either, so
|
|
127
159
|
// this one is absent there rather than wrong. The screen already reads null.
|
|
128
|
-
|
|
160
|
+
//
|
|
161
|
+
// `onWriteHeld` is the desktop's ⌘R asking the page to write what the undo
|
|
162
|
+
// window holds before it reloads (main/write-before-reload.mjs). A browser
|
|
163
|
+
// reload asks nobody; the page writes on `pagehide` there instead.
|
|
164
|
+
export const DESKTOP_ONLY = ['pathForFile', 'onWriteHeld'];
|
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
// build time, rather than typing them into a file, is the only way the list
|
|
11
11
|
// cannot rot quietly.
|
|
12
12
|
|
|
13
|
-
export const READ_FROM = "2.1.
|
|
14
|
-
export const READ_AT = "2026-
|
|
13
|
+
export const READ_FROM = "2.1.289";
|
|
14
|
+
export const READ_AT = "2026-10-07";
|
|
15
15
|
export const CLAUDE_COMMANDS = [
|
|
16
16
|
{
|
|
17
17
|
"name": "model",
|
|
@@ -11,14 +11,14 @@
|
|
|
11
11
|
// number typed into a file of ours would look authoritative while being a
|
|
12
12
|
// guess. Running an old model by mistake is the failure being avoided.
|
|
13
13
|
|
|
14
|
-
export const READ_FROM = "2.1.
|
|
15
|
-
export const READ_AT = "2026-
|
|
14
|
+
export const READ_FROM = "2.1.289";
|
|
15
|
+
export const READ_AT = "2026-10-07";
|
|
16
16
|
|
|
17
17
|
export const CLAUDE_MODELS = [
|
|
18
18
|
{"alias":"opus","id":"claude-opus-5-5","label":"Opus 5.5","defaultLevel":"medium"},
|
|
19
19
|
{"alias":"claude-opus-5","id":"claude-opus-5","label":"Opus 5","defaultLevel":"high"},
|
|
20
|
-
{"alias":"sonnet","id":"claude-sonnet-5","label":"Sonnet 5","defaultLevel":"
|
|
21
|
-
{"alias":"claude-sonnet-
|
|
20
|
+
{"alias":"sonnet","id":"claude-sonnet-5-5","label":"Sonnet 5.5","defaultLevel":"medium"},
|
|
21
|
+
{"alias":"claude-sonnet-5","id":"claude-sonnet-5","label":"Sonnet 5","defaultLevel":"high"},
|
|
22
22
|
{"alias":"haiku","id":"claude-haiku-4-5","label":"Haiku 4.5","defaultLevel":null},
|
|
23
23
|
{"alias":"claude-3-5-haiku","id":"claude-3-5-haiku","label":"Haiku 3.5","defaultLevel":null},
|
|
24
24
|
{"alias":"fable","id":"claude-fable-5-1","label":"Fable 5.1","defaultLevel":"high"},
|