agentbox-app 0.1.7 → 0.1.12
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 +220 -58
- package/bin/agentbox.mjs +18 -3
- package/briefs/message-rules.md +24 -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 +11 -11
- 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 +116 -0
- package/main/agents.mjs +52 -46
- package/main/analytics.mjs +27 -0
- package/main/approval-prompt-server.mjs +2 -2
- package/main/approvals.mjs +14 -5
- package/main/artifact-path.mjs +11 -0
- package/main/claude-bin.mjs +32 -5
- package/main/claude-input.mjs +45 -3
- package/main/claude-plan.mjs +25 -13
- package/main/code-change.mjs +3 -3
- package/main/codex-account.mjs +1 -1
- package/main/codex-bin.mjs +18 -0
- package/main/codex-launch-env.mjs +31 -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 +82 -17
- package/main/demo.mjs +17 -14
- package/main/dev-window.mjs +9 -9
- package/main/doc-scheme.mjs +2 -0
- package/main/engine-setup.mjs +204 -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 +7 -4
- package/main/git-change-offthread.mjs +70 -0
- package/main/git-change-thread.mjs +11 -0
- package/main/git-change.mjs +9 -3
- package/main/img-scheme.mjs +70 -1
- package/main/instruction-settings.mjs +134 -60
- package/main/ipc.mjs +335 -42
- package/main/leftovers.mjs +518 -0
- package/main/live-replies.mjs +43 -5
- package/main/machine.mjs +48 -1
- package/main/main.mjs +138 -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/notify.mjs +1 -1
- package/main/rail-note.mjs +2 -2
- package/main/refresh-agent-models.mjs +21 -0
- package/main/repeats.mjs +4 -4
- package/main/row-label.mjs +115 -51
- package/main/runs-on.mjs +93 -0
- package/main/serve.mjs +77 -5
- package/main/settings.mjs +245 -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 +84 -7
- package/main/store/project.mjs +15 -19
- package/main/store/work-items.mjs +150 -6
- package/main/store.mjs +245 -13
- package/main/supervisor.mjs +1634 -417
- package/main/task-commands.mjs +8 -10
- package/main/task-folders.mjs +94 -16
- package/main/task-remote-control.mjs +3 -3
- package/main/task-terminals.mjs +14 -2
- 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 +10 -12
- package/mcp/core/work.mjs +123 -26
- package/mcp/tools.mjs +13 -6
- package/package.json +21 -9
- package/renderer/dist/assets/agentbox-icon-F1oN9nj_.svg +15 -0
- package/renderer/dist/assets/index-ChKsQkRw.js +1169 -0
- package/renderer/dist/assets/index-ClBXnq3B.css +32 -0
- package/renderer/dist/index.html +2 -2
- package/scripts/after-install.mjs +14 -0
- package/scripts/approval-server.sh +7 -2
- package/scripts/memory-gate-hook.sh +59 -0
- package/shared/agent-import.mjs +39 -16
- 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 +38 -1
- package/shared/claude-commands.generated.mjs +2 -2
- package/shared/claude-models.generated.mjs +6 -6
- 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-modes.mjs +1 -1
- package/shared/codex-usage.mjs +7 -8
- package/shared/demo-world.mjs +6 -6
- 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 +34 -4
- package/shared/instruction-defaults.json +2 -2
- package/shared/product-name.mjs +4 -2
- package/shared/project-folder-check.mjs +9 -3
- package/shared/rank.d.mts +1 -0
- package/shared/rank.mjs +22 -0
- package/shared/referenced-files.mjs +1 -1
- package/shared/runs-on.d.mts +20 -0
- package/shared/runs-on.mjs +79 -0
- 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 +40 -19
- 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 +258 -28
- 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
|
@@ -11,16 +11,16 @@
|
|
|
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.293";
|
|
15
|
+
export const READ_AT = "2026-10-08";
|
|
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-
|
|
22
|
-
{"alias":"haiku","id":"claude-haiku-
|
|
23
|
-
{"alias":"claude-
|
|
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
|
+
{"alias":"haiku","id":"claude-haiku-5-5","label":"Haiku 5.5","defaultLevel":"medium"},
|
|
23
|
+
{"alias":"claude-haiku-4-5","id":"claude-haiku-4-5","label":"Haiku 4.5","defaultLevel":null},
|
|
24
24
|
{"alias":"fable","id":"claude-fable-5-1","label":"Fable 5.1","defaultLevel":"high"},
|
|
25
25
|
{"alias":"claude-fable-5","id":"claude-fable-5","label":"Fable 5","defaultLevel":"high"},
|
|
26
26
|
];
|
package/shared/claude-usage.mjs
CHANGED
|
@@ -28,11 +28,11 @@ import { instantIn, localZone, sessionLimit, untilReset, wallIn } from './usage.
|
|
|
28
28
|
// { span, qualifier, name, percent, resetsAt|null, resetsText, resetsOn, zone }
|
|
29
29
|
|
|
30
30
|
const LINE = /^Current\s+(session|week)(?:\s*\(([^)]+)\))?\s*:\s*(\d+)%\s*used(?:\s*·\s*resets\s+(.+?))?\s*$/i;
|
|
31
|
-
// THE MINUTES ARE OPTIONAL, AND THAT IS WHY
|
|
32
|
-
// drops the ":00" when a reset lands on the hour, so
|
|
33
|
-
//
|
|
34
|
-
//
|
|
35
|
-
//
|
|
31
|
+
// THE MINUTES ARE OPTIONAL, AND THAT IS WHY THE CORNER WENT QUIET. Claude Code
|
|
32
|
+
// drops the ":00" when a reset lands on the hour, so a stamp reads "Sep 1 at
|
|
33
|
+
// 4pm" and this refused it. Refusing it took the countdown out of the pill AND
|
|
34
|
+
// out of the tooltip, which left a wordless percentage nobody could read. It
|
|
35
|
+
// is one hour in every five.
|
|
36
36
|
//
|
|
37
37
|
// THE AM/PM HALF STAYS REQUIRED. An hour on its own is ambiguous by twelve
|
|
38
38
|
// hours, and the standing rule in this file is to refuse rather than guess.
|
|
@@ -90,7 +90,7 @@ export function resetAt(text, now = Date.now(), zoneNow = localZone()) {
|
|
|
90
90
|
}
|
|
91
91
|
|
|
92
92
|
/**
|
|
93
|
-
* WHAT EACH LIMIT IS CALLED, IN
|
|
93
|
+
* WHAT EACH LIMIT IS CALLED, IN PLAIN WORDS. One copy, because the sentence the
|
|
94
94
|
* corner reads aloud and the panel's rows have to agree word for word: they are
|
|
95
95
|
* on the screen at the same moment, one of them read aloud and one of them read.
|
|
96
96
|
*
|
package/shared/codex-import.mjs
CHANGED
|
@@ -13,9 +13,9 @@
|
|
|
13
13
|
// now, so opening the row draws the strip and a 1 or a 2 answers it exactly as
|
|
14
14
|
// Y and N do on the row.
|
|
15
15
|
//
|
|
16
|
-
// NOTHING IS RESUMED.
|
|
17
|
-
// holds here: a yes makes a row
|
|
18
|
-
// last message, and replies still happen in Codex.
|
|
16
|
+
// NOTHING IS RESUMED. That is the rule for Claude Code threads and it
|
|
17
|
+
// holds here: a yes makes a row the user can READ, with their prompt and
|
|
18
|
+
// Codex's last message, and replies still happen in Codex.
|
|
19
19
|
//
|
|
20
20
|
// A NO NEVER LOSES ONE.So a no closes the row under its own label, Closed shows
|
|
21
21
|
// it under "Not imported" with an Import key, and the ⌘K import card lists it
|
|
@@ -29,7 +29,7 @@ import { Name } from '../shared/product-name.mjs';
|
|
|
29
29
|
export const CODEX_IMPORT_LABEL = 'codex-import';
|
|
30
30
|
/** On the row once it is hers to read. */
|
|
31
31
|
export const CODEX_MIRROR_LABEL = 'codex';
|
|
32
|
-
/** On a row
|
|
32
|
+
/** On a row the user said not now to. */
|
|
33
33
|
export const NOT_IMPORTED_LABEL = 'not-imported';
|
|
34
34
|
/** And which conversation, on all three. Codex's own thread id. */
|
|
35
35
|
export const codexLabel = (id) => `codex:${String(id ?? '').trim()}`;
|
|
@@ -68,7 +68,7 @@ export function whenPhrase(when, now = Date.now()) {
|
|
|
68
68
|
* to a notes file in its worktree.
|
|
69
69
|
*
|
|
70
70
|
* So: pictures are left out. A link to the open web stays a link, because it
|
|
71
|
-
* works from anywhere
|
|
71
|
+
* works from anywhere. A link to this Mac, a
|
|
72
72
|
* file path or a localhost address, keeps its words and loses its target, and
|
|
73
73
|
* a line that was nothing but such a link goes entirely, since "Open the
|
|
74
74
|
* interactive preview." with nothing to open is the confusing part. */
|
|
@@ -173,7 +173,7 @@ export function codexImportRow(thread, { projectName, now = Date.now() } = {}) {
|
|
|
173
173
|
}
|
|
174
174
|
|
|
175
175
|
/**
|
|
176
|
-
* THE ROW ONCE
|
|
176
|
+
* THE ROW ONCE THE USER SAID YES. Their prompt is the body and Codex's last message
|
|
177
177
|
* is the result, so the thread reads You, then Codex, the way it did over
|
|
178
178
|
* there. The result carries the one line that says where replies go. */
|
|
179
179
|
export function codexMirrorPatch(thread) {
|
|
@@ -201,7 +201,7 @@ export function importChoice(answer) {
|
|
|
201
201
|
|
|
202
202
|
/**
|
|
203
203
|
* WHICH PROJECT A CONVERSATION BELONGS TO: the one whose folder it ran in,
|
|
204
|
-
*
|
|
204
|
+
* the same rule every import follows. Null when nobody points at that folder. */
|
|
205
205
|
export function productsForThread(thread, products = []) {
|
|
206
206
|
const key = String(thread?.folder ?? '').replace(/\/+$/, '');
|
|
207
207
|
if (!key) return [];
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// Types for shared/codex-modes.mjs, for the window side.
|
|
2
|
+
//
|
|
3
|
+
// The three ids are `CodexModeId` in renderer/src/types.ts, which is where that
|
|
4
|
+
// union already lives; this file states the shape around them rather than a
|
|
5
|
+
// second copy of the list. renderer/src/codex-modes.ts is the screen's own
|
|
6
|
+
// narrowed view of the same table and reads these through it.
|
|
7
|
+
import type { CodexModeId } from '../renderer/src/types';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* THE PAIR A MODE REALLY IS. `sandbox` and `approvalPolicy` go straight into
|
|
11
|
+
* Codex's `thread/start`; `approvalsReviewer` is set on `auto` alone, which is
|
|
12
|
+
* the only row with asks left to answer. They are plain strings rather than
|
|
13
|
+
* unions on purpose: the authority for what Codex accepts is Codex's own
|
|
14
|
+
* schema, quoted in the .mjs, and a union here would be a third copy of it
|
|
15
|
+
* that nothing checks.
|
|
16
|
+
*/
|
|
17
|
+
export interface CodexMode {
|
|
18
|
+
label: string;
|
|
19
|
+
sandbox: string;
|
|
20
|
+
approvalPolicy: string;
|
|
21
|
+
approvalsReviewer?: string;
|
|
22
|
+
what: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export declare const CODEX_MODE_ORDER: CodexModeId[];
|
|
26
|
+
export declare const CODEX_DEFAULT_MODE: CodexModeId;
|
|
27
|
+
export declare const CODEX_MODES: Record<CodexModeId, CodexMode>;
|
|
28
|
+
export declare const CODEX_MODE_COMMAND: Record<CodexModeId, string>;
|
|
29
|
+
export declare const CODEX_MODE_HINT: Record<CodexModeId, string>;
|
|
30
|
+
export declare const CODEX_MODE_STATUS: Record<CodexModeId, string>;
|
|
31
|
+
|
|
32
|
+
export declare function isCodexMode(word: unknown): boolean;
|
|
33
|
+
/** The pair, falling back to the default's pair when the word is not one of ours. */
|
|
34
|
+
export declare function codexPosture(mode: string | null | undefined): {
|
|
35
|
+
sandbox: string;
|
|
36
|
+
approvalPolicy: string;
|
|
37
|
+
approvalsReviewer?: string;
|
|
38
|
+
};
|
|
39
|
+
export declare function codexModeWords(mode: string | null | undefined): string;
|
|
40
|
+
/**
|
|
41
|
+
* The rows the menu draws for what has been typed. `null` is the way back to
|
|
42
|
+
* the project's own setting and is a row like the others.
|
|
43
|
+
*/
|
|
44
|
+
export declare function codexMenuRowsFor(
|
|
45
|
+
query: string | null,
|
|
46
|
+
set?: unknown,
|
|
47
|
+
): (CodexModeId | null)[];
|
|
48
|
+
export declare function nextCodexMode(mode: CodexModeId): CodexModeId;
|
|
49
|
+
/** The mode a typed `/word ` means, or null when it means nothing. */
|
|
50
|
+
export declare function exactCodexMode(word: string | null | undefined): CodexModeId | null;
|
package/shared/codex-modes.mjs
CHANGED
package/shared/codex-usage.mjs
CHANGED
|
@@ -58,17 +58,16 @@
|
|
|
58
58
|
// ---------------------------------------------------------------------------
|
|
59
59
|
// AND `primary` IS NOT ALWAYS THE FIVE HOUR WINDOW. The block above read one
|
|
60
60
|
// scratch account on 2026-09-05 and took the pairing it happened to see as the
|
|
61
|
-
// shape.
|
|
62
|
-
//
|
|
63
|
-
//
|
|
64
|
-
// one five hour window exists on her plan.
|
|
61
|
+
// shape. On some Codex plans the rate-limit records look different: EVERY ONE
|
|
62
|
+
// of them has `secondary: null` and a `primary` whose window is 10080 minutes.
|
|
63
|
+
// Not one five hour window exists on such a plan.
|
|
65
64
|
//
|
|
66
|
-
// So the old table would have drawn
|
|
67
|
-
// session", which is a confident wrong number about
|
|
68
|
-
// the corner would have counted a week down as though it were an afternoon.
|
|
65
|
+
// So the old table would have drawn a SEVEN DAY limit under the words "This
|
|
66
|
+
// session", which is a confident wrong number about the user's subscription,
|
|
67
|
+
// and the corner would have counted a week down as though it were an afternoon.
|
|
69
68
|
//
|
|
70
69
|
// THE WINDOW'S OWN LENGTH DECIDES WHAT IT IS CALLED, and the slot it arrived in
|
|
71
|
-
// decides nothing. 300 minutes is
|
|
70
|
+
// decides nothing. 300 minutes is a session, 10080 is a week, and an account
|
|
72
71
|
// reporting only one of them gets only that one row. The slot order is still the
|
|
73
72
|
// tie-breaker when a payload names no duration at all, because that is the one
|
|
74
73
|
// case where there is nothing better to go on.
|
package/shared/demo-world.mjs
CHANGED
|
@@ -12,10 +12,10 @@
|
|
|
12
12
|
// shape of every row here is checked by the same rules the real ones are, which
|
|
13
13
|
// only works while this stays importable by a test with no app around it.
|
|
14
14
|
//
|
|
15
|
-
// NOTHING HERE IS
|
|
16
|
-
// invented week of work. No path on this Mac, no name of anyone
|
|
17
|
-
// product
|
|
18
|
-
// the screen in front of a room is invented, and
|
|
15
|
+
// NOTHING HERE IS THE USER'S AND NOTHING HERE IS REAL. Three invented products,
|
|
16
|
+
// one invented week of work. No path on this Mac, no name of anyone real, no
|
|
17
|
+
// product anyone actually ships. That is the whole point of the row: what goes
|
|
18
|
+
// on the screen in front of a room is invented, and the real inbox stays shut.
|
|
19
19
|
|
|
20
20
|
import { envName, nameSlug } from './product-name.mjs';
|
|
21
21
|
|
|
@@ -80,7 +80,7 @@ export const DEMO_PRODUCTS = [
|
|
|
80
80
|
// work built and waiting the "merge it" she should not have to type
|
|
81
81
|
// something blocked on her the app saying it is stuck, out loud
|
|
82
82
|
// a finished row a result, and what the inbox looks like empty
|
|
83
|
-
// one row
|
|
83
|
+
// one row the user wrote the user's own words on a card, answered
|
|
84
84
|
//
|
|
85
85
|
// THE BODIES ARE WRITTEN THE WAY THE WORKER BRIEF SAYS TO WRITE THEM: the ask
|
|
86
86
|
// in bold on the first line, under fifteen words, then the context, then an
|
|
@@ -214,7 +214,7 @@ function lines(now) {
|
|
|
214
214
|
result: [
|
|
215
215
|
'The clause summariser is merged and running. It read all ten contracts in the test folder and named every termination, auto renewal and liability clause in all ten, with two false positives on the longest one.',
|
|
216
216
|
'',
|
|
217
|
-
'Ninety three seconds for the longest contract, four seconds for the shortest. Measured on this
|
|
217
|
+
'Ninety three seconds for the longest contract, four seconds for the shortest. Measured on this computer, not estimated.',
|
|
218
218
|
].join('\n'),
|
|
219
219
|
});
|
|
220
220
|
|
package/shared/engines.mjs
CHANGED
|
@@ -25,15 +25,15 @@
|
|
|
25
25
|
// :494). Nothing has ever been written to clear it on purpose, so the honest
|
|
26
26
|
// statement is "probably still there", not "always will be".
|
|
27
27
|
//
|
|
28
|
-
// HOW MANY SUCH ROWS
|
|
29
|
-
// UNTIL SOMEBODY LOOKS. It could not be measured from the machine this was
|
|
30
|
-
// written on: there is no ~/Zero there at all. On
|
|
28
|
+
// HOW MANY SUCH ROWS A STORE ACTUALLY HAS IS AN OPEN QUESTION, AND IT IS NOT
|
|
29
|
+
// ZERO UNTIL SOMEBODY LOOKS. It could not be measured from the machine this was
|
|
30
|
+
// written on: there is no ~/Zero there at all. On a real store it is one command,
|
|
31
31
|
// `grep -rho '"engine":"[a-z]*"' ~/Zero | sort | uniq -c`, and the answer
|
|
32
32
|
// belongs in this paragraph when someone runs it. The gate below costs nothing
|
|
33
33
|
// if the count turns out to be zero, and is the whole story if it is not.
|
|
34
34
|
//
|
|
35
35
|
// So the 08-25 resolver, restored unchanged, would have been a silent reversal
|
|
36
|
-
// of
|
|
36
|
+
// of the decision to withhold Codex: those rows would start choosing Codex again the moment this
|
|
37
37
|
// module landed, with no picker, nothing in Settings, and no approval path
|
|
38
38
|
// built. The resolver is therefore CLOSED unless the caller hands it
|
|
39
39
|
// `ENGINE_CHOICE_ENABLED` below. A caller that passes nothing gets Claude
|
|
@@ -143,7 +143,7 @@ export const ENGINE_CHOICE_ENABLED = Symbol('the second engine is wired up in th
|
|
|
143
143
|
* in the app's own state rather than in her file: a fresh install, a state file
|
|
144
144
|
* she deleted, or a second Mac would each invent a different moment, and the
|
|
145
145
|
* one thing this value must be is the same on every machine reading the same
|
|
146
|
-
* store. A date
|
|
146
|
+
* store. A date the user typed is a fact about their decision; a date we noticed is a
|
|
147
147
|
* fact about a process.
|
|
148
148
|
*
|
|
149
149
|
* THE WORKSPACE DEFAULT (`config.engine`) IS TIME-SCOPED TOO, SINCE 2026-09-05,
|
|
@@ -210,7 +210,7 @@ export function engineDefaultSince(config = {}) {
|
|
|
210
210
|
* gate withholds — the same rule `engineChoiceOnRowIsStale` follows below, and
|
|
211
211
|
* for the same reason: discarding it could only ever move work TO the second
|
|
212
212
|
* engine, which is the one direction the gate exists to prevent. False when
|
|
213
|
-
* there is no stamp, which is a default
|
|
213
|
+
* there is no stamp, which is a default typed beside the moment itself.
|
|
214
214
|
*/
|
|
215
215
|
export function engineDefaultIsStale(config = {}) {
|
|
216
216
|
const since = engineChoiceSince(config);
|
|
@@ -271,9 +271,9 @@ export function engineLabel(id) {
|
|
|
271
271
|
* `found` is a map of id to boolean. An engine whose binary is not on the
|
|
272
272
|
* machine is not offered, because a picker that offers something that cannot
|
|
273
273
|
* run is a picker that hands her a session that dies on arrival. Claude Code
|
|
274
|
-
* is
|
|
275
|
-
*
|
|
276
|
-
*
|
|
274
|
+
* is in the list even when it was not found, UNLESS Codex was: a Mac with only
|
|
275
|
+
* Codex is offered only Codex (`homeEngine` below). With neither, the app
|
|
276
|
+
* refuses to open an inbox and says so in its own words.
|
|
277
277
|
*
|
|
278
278
|
* UNGATED, AND THE INVARIANT IS THEREFORE SCOPED TO ROUTING. Say it plainly,
|
|
279
279
|
* because the file must not claim more than the code delivers: this function,
|
|
@@ -296,7 +296,21 @@ export function engineLabel(id) {
|
|
|
296
296
|
* holds the caller list exactly, so the next one has to argue for itself here.
|
|
297
297
|
*/
|
|
298
298
|
export function availableEngines(found = {}) {
|
|
299
|
-
|
|
299
|
+
const home = homeEngine(found);
|
|
300
|
+
return ENGINES.filter((e) => e.id === home || (e.id !== DEFAULT_ENGINE && found[e.id]));
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* WHAT RUNS WHEN NOBODY HAS CHOSEN, ON THIS MAC. Claude Code, unless this Mac
|
|
305
|
+
* has said for certain that Claude Code is not here and Codex is. The app needs
|
|
306
|
+
* one of the two, not both, so a Mac with only Codex runs everything on Codex.
|
|
307
|
+
*
|
|
308
|
+
* `found.claude` has to be an explicit `false`. A caller that never asked
|
|
309
|
+
* (every call written before this, and every test config) leaves it undefined,
|
|
310
|
+
* and that reads as Claude Code being here, which is what it always meant.
|
|
311
|
+
*/
|
|
312
|
+
export function homeEngine(found = {}) {
|
|
313
|
+
return found.claude === false && found.codex ? 'codex' : DEFAULT_ENGINE;
|
|
300
314
|
}
|
|
301
315
|
|
|
302
316
|
/** Whether there is a choice to make at all. One engine is not a choice. */
|
|
@@ -334,6 +348,9 @@ export function engineChoiceExists(found = {}) {
|
|
|
334
348
|
* token FROM that same value, so in her app the two cannot come apart.
|
|
335
349
|
*/
|
|
336
350
|
export function engineFor(item, { config = {}, found = {}, enabled } = {}) {
|
|
351
|
+
// ONE ENGINE ON THE MAC IS NOT A CHOICE, so the gate has nothing to guard.
|
|
352
|
+
// Without Claude Code, a row marked `claude` would only die on arrival.
|
|
353
|
+
if (homeEngine(found) !== DEFAULT_ENGINE) return homeEngine(found);
|
|
337
354
|
if (enabled !== ENGINE_CHOICE_ENABLED) return DEFAULT_ENGINE;
|
|
338
355
|
const wanted = isEngine(item?.engine) && !engineChoiceOnRowIsStale(item, config) ? item.engine : null;
|
|
339
356
|
const fallback = isEngine(config?.engine) && !engineDefaultIsStale(config) ? config.engine : DEFAULT_ENGINE;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// Types for shared/feedback.mjs, which is plain ESM so the Feedback card and
|
|
2
|
+
// the main process read one copy of the limits.
|
|
3
|
+
|
|
4
|
+
export const FEEDBACK_LIMITS: Readonly<{ text: number; files: number; bytes: number }>;
|
|
5
|
+
|
|
6
|
+
export function totalBytes(files?: { size?: number }[]): number;
|
|
7
|
+
|
|
8
|
+
export function checkFeedback(p?: { text?: string; files?: { size?: number }[] }): { ok: true } | { ok: false; reason: string };
|
|
9
|
+
|
|
10
|
+
export function feedbackPayload(p?: {
|
|
11
|
+
text?: string;
|
|
12
|
+
files?: { name: string; type: string; data: string }[];
|
|
13
|
+
app?: { version?: string; os?: string };
|
|
14
|
+
}): { text: string; files: { name: string; type: string; data: string }[]; app: { version: string; os: string } };
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// WHAT A PIECE OF FEEDBACK MAY BE, in one place, read by the card before it
|
|
2
|
+
// lets you press Send and by the main process again before anything leaves the
|
|
3
|
+
// machine (w-1b574413db). The server function checks the same limits a third
|
|
4
|
+
// time, because it is the only one of the three a stranger can reach directly.
|
|
5
|
+
//
|
|
6
|
+
// Words, files, or both, and never nothing. The size limit keeps one request
|
|
7
|
+
// well inside what the mail provider takes as attachments.
|
|
8
|
+
|
|
9
|
+
export const FEEDBACK_LIMITS = Object.freeze({
|
|
10
|
+
text: 20_000,
|
|
11
|
+
files: 10,
|
|
12
|
+
bytes: 8 * 1024 * 1024,
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
export function totalBytes(files = []) {
|
|
16
|
+
return files.reduce((sum, f) => sum + (Number.isFinite(f?.size) ? f.size : 0), 0);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// { ok: true } or { ok: false, reason } where the reason is a sentence the
|
|
20
|
+
// card can show as it is.
|
|
21
|
+
export function checkFeedback({ text = '', files = [] } = {}) {
|
|
22
|
+
const words = String(text ?? '').trim();
|
|
23
|
+
const list = Array.isArray(files) ? files : [];
|
|
24
|
+
if (!words && list.length === 0) return { ok: false, reason: 'Write something or attach a file first.' };
|
|
25
|
+
if (words.length > FEEDBACK_LIMITS.text) {
|
|
26
|
+
return { ok: false, reason: `Keep it under ${FEEDBACK_LIMITS.text.toLocaleString('en-US')} characters.` };
|
|
27
|
+
}
|
|
28
|
+
if (list.length > FEEDBACK_LIMITS.files) return { ok: false, reason: `Attach up to ${FEEDBACK_LIMITS.files} files.` };
|
|
29
|
+
if (totalBytes(list) > FEEDBACK_LIMITS.bytes) {
|
|
30
|
+
return { ok: false, reason: `Files can add up to ${FEEDBACK_LIMITS.bytes / 1024 / 1024} MB.` };
|
|
31
|
+
}
|
|
32
|
+
return { ok: true };
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Exactly what travels: the words trimmed, each file as name, type and its
|
|
36
|
+
// base64, and the app's version so a report can be matched to a release.
|
|
37
|
+
// Nothing else the card happened to hold rides along.
|
|
38
|
+
export function feedbackPayload({ text = '', files = [], app = {} } = {}) {
|
|
39
|
+
return {
|
|
40
|
+
text: String(text ?? '').trim(),
|
|
41
|
+
files: (files ?? []).map(({ name, type, data }) => ({ name: String(name ?? 'file'), type: String(type || 'application/octet-stream'), data: String(data ?? '') })),
|
|
42
|
+
app: { version: String(app.version ?? ''), os: String(app.os ?? '') },
|
|
43
|
+
};
|
|
44
|
+
}
|
|
@@ -21,19 +21,19 @@
|
|
|
21
21
|
export const EXAMPLES = [
|
|
22
22
|
{
|
|
23
23
|
kind: 'question',
|
|
24
|
-
title: 'Example: which of these two
|
|
25
|
-
result: 'Example. Both are free. Say either one and I will
|
|
24
|
+
title: 'Example: which of these two dates should the offsite use?',
|
|
25
|
+
result: 'Example. Both are free. Say either one and I will book it.',
|
|
26
26
|
agoMs: 4 * 60_000,
|
|
27
27
|
},
|
|
28
28
|
{
|
|
29
29
|
kind: 'task',
|
|
30
|
-
title: 'Example: the
|
|
30
|
+
title: 'Example: the meeting notes are summarised and shared.',
|
|
31
31
|
result: 'Example. Nothing here needs you. Close it and it is gone.',
|
|
32
32
|
agoMs: 11 * 60_000,
|
|
33
33
|
},
|
|
34
34
|
{
|
|
35
35
|
kind: 'review',
|
|
36
|
-
title: 'Example: I
|
|
36
|
+
title: 'Example: I picked the cheaper venue, say if you disagree.',
|
|
37
37
|
result: 'Example. This is what an agent looks like when it made a call without you.',
|
|
38
38
|
agoMs: 26 * 60_000,
|
|
39
39
|
},
|
|
@@ -7,10 +7,26 @@ export const PRACTICE_SLUG: string;
|
|
|
7
7
|
export const PRACTICE_FLAG: string;
|
|
8
8
|
export const PRACTICE_TASK: { title: string; body: string };
|
|
9
9
|
export const PRACTICE_ANSWER: string;
|
|
10
|
+
export const PRACTICE_REPLY: string;
|
|
11
|
+
export const PRACTICE_REPLY_ANSWER: string;
|
|
10
12
|
export const PRACTICE_TASK_TRACE: string[];
|
|
11
13
|
/** The practice project's sidebar note, written to its `pinned.md` and drawn
|
|
12
14
|
* beside the third introduction slab. */
|
|
13
15
|
export const PRACTICE_NOTE: string;
|
|
16
|
+
/** The rest of the practice team's work, drawn from the tab tour onward so
|
|
17
|
+
* the list and the board are not empty. `state` is the column it lands in. */
|
|
18
|
+
export const PRACTICE_BACKDROP: {
|
|
19
|
+
state: 'needs' | 'working' | 'scheduled';
|
|
20
|
+
kind: string;
|
|
21
|
+
title: string;
|
|
22
|
+
body: string;
|
|
23
|
+
trace: string[];
|
|
24
|
+
/** Only on the `needs` rows: what the agent handed back. */
|
|
25
|
+
result?: string;
|
|
26
|
+
agoMs: number;
|
|
27
|
+
/** Only on the `scheduled` row: how long after staging it is set to run. */
|
|
28
|
+
inMs?: number;
|
|
29
|
+
}[];
|
|
14
30
|
export const PRACTICE_ROWS: {
|
|
15
31
|
kind: string;
|
|
16
32
|
title: string;
|