agent-office-studio 0.0.0-stage → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +57 -0
- package/LICENSE +21 -0
- package/README.md +85 -2
- package/bin/agentoffice.js +38 -0
- package/dist/apple-touch-icon.png +0 -0
- package/dist/assets/_commonjsHelpers-CqkleIqs.js +1 -0
- package/dist/assets/addon-fit-BwprjgOP.js +1 -0
- package/dist/assets/index-CozPk6R9.js +4457 -0
- package/dist/assets/index-i7sU9SN-.css +32 -0
- package/dist/assets/inter-cyrillic-ext-wght-normal-B2xhLi22.woff2 +0 -0
- package/dist/assets/inter-cyrillic-wght-normal-CMZtQduZ.woff2 +0 -0
- package/dist/assets/inter-greek-ext-wght-normal-CGAr0uHJ.woff2 +0 -0
- package/dist/assets/inter-greek-wght-normal-CaVNZxsx.woff2 +0 -0
- package/dist/assets/inter-latin-ext-wght-normal-CFHvXkgd.woff2 +0 -0
- package/dist/assets/inter-latin-wght-normal-C2S99t-D.woff2 +0 -0
- package/dist/assets/inter-vietnamese-wght-normal-CBcvBZtf.woff2 +0 -0
- package/dist/assets/jetbrains-mono-cyrillic-400-normal-BEIGL1Tu.woff2 +0 -0
- package/dist/assets/jetbrains-mono-cyrillic-400-normal-CIEtRijs.woff +0 -0
- package/dist/assets/jetbrains-mono-greek-400-normal-C190GLew.woff2 +0 -0
- package/dist/assets/jetbrains-mono-greek-400-normal-CNojz0t3.woff +0 -0
- package/dist/assets/jetbrains-mono-latin-400-normal-B11XCQ5g.woff +0 -0
- package/dist/assets/jetbrains-mono-latin-400-normal-V6pRDFza.woff2 +0 -0
- package/dist/assets/jetbrains-mono-latin-ext-400-normal-Bc8Ftmh3.woff2 +0 -0
- package/dist/assets/jetbrains-mono-latin-ext-400-normal-DHMOLxAi.woff +0 -0
- package/dist/assets/jetbrains-mono-vietnamese-400-normal-BeU3T8wf.woff +0 -0
- package/dist/assets/xterm-C7kOH91j.js +9 -0
- package/dist/icon-192.png +0 -0
- package/dist/icon-512.png +0 -0
- package/dist/icon.svg +9 -0
- package/dist/index.html +240 -0
- package/dist/manifest.webmanifest +16 -0
- package/dist/sw.js +39 -0
- package/docs/README.md +26 -0
- package/docs/claude-access.md +31 -0
- package/docs/configuration.md +53 -0
- package/docs/development.md +76 -0
- package/docs/getting-started.md +54 -0
- package/docs/guides/troubleshooting.md +99 -0
- package/docs/guides/updating.md +36 -0
- package/docs/guides/working-with-the-team.md +56 -0
- package/docs/guides/your-first-job.md +65 -0
- package/docs/how-it-works.md +80 -0
- package/docs/images/office.jpg +0 -0
- package/docs/jobs.md +54 -0
- package/docs/leaderboard.md +65 -0
- package/docs/packaging.md +49 -0
- package/docs/phone.md +28 -0
- package/docs/security.md +48 -0
- package/docs/terminal.md +46 -0
- package/docs/using-the-office.md +109 -0
- package/docs/voice.md +44 -0
- package/package.json +64 -4
- package/server/auth.js +89 -0
- package/server/banter.js +53 -0
- package/server/changes.js +72 -0
- package/server/chief.js +130 -0
- package/server/index.js +1952 -0
- package/server/leaderboard.js +190 -0
- package/server/office-mcp.js +101 -0
- package/server/procstat.js +85 -0
- package/server/standup.js +78 -0
- package/server/supervise.js +51 -0
- package/server/terminal.js +255 -0
- package/server/tools.js +52 -0
- package/server/usage.js +40 -0
- package/server/voice.js +172 -0
- package/shared/speakable.js +50 -0
|
Binary file
|
|
Binary file
|
package/dist/icon.svg
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
|
2
|
+
<rect width="512" height="512" fill="#1d1b18"/>
|
|
3
|
+
<rect x="136" y="160" width="240" height="176" rx="32" fill="#fbf9f5"/>
|
|
4
|
+
<rect x="216" y="336" width="80" height="28" fill="#fbf9f5"/>
|
|
5
|
+
<rect x="180" y="356" width="152" height="24" rx="12" fill="#fbf9f5"/>
|
|
6
|
+
<circle cx="206" cy="248" r="16" fill="#1d1b18"/>
|
|
7
|
+
<circle cx="256" cy="248" r="16" fill="#1d1b18"/>
|
|
8
|
+
<circle cx="306" cy="248" r="16" fill="#1d1b18"/>
|
|
9
|
+
</svg>
|
package/dist/index.html
ADDED
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
|
6
|
+
<meta name="theme-color" content="#fbf9f5" />
|
|
7
|
+
<meta name="mobile-web-app-capable" content="yes" />
|
|
8
|
+
<meta name="apple-mobile-web-app-capable" content="yes" />
|
|
9
|
+
<meta name="apple-mobile-web-app-status-bar-style" content="default" />
|
|
10
|
+
<meta name="apple-mobile-web-app-title" content="Office" />
|
|
11
|
+
<link rel="manifest" href="/manifest.webmanifest" />
|
|
12
|
+
<link rel="icon" href="/icon.svg" type="image/svg+xml" />
|
|
13
|
+
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
|
|
14
|
+
<script>
|
|
15
|
+
// Before first paint, so a saved theme never flashes the default. theme.js owns it after that.
|
|
16
|
+
(function () {
|
|
17
|
+
try {
|
|
18
|
+
var t = localStorage.getItem('office.theme') || 'paper';
|
|
19
|
+
var m = localStorage.getItem('office.mode') || 'auto';
|
|
20
|
+
var d = m === 'dark' || (m === 'auto' && matchMedia('(prefers-color-scheme: dark)').matches);
|
|
21
|
+
var r = document.documentElement;
|
|
22
|
+
r.dataset.theme = t;
|
|
23
|
+
r.dataset.mode = d ? 'dark' : 'light';
|
|
24
|
+
} catch (e) {}
|
|
25
|
+
})();
|
|
26
|
+
</script>
|
|
27
|
+
<title>Agent Office</title>
|
|
28
|
+
<script type="module" crossorigin src="/assets/index-CozPk6R9.js"></script>
|
|
29
|
+
<link rel="stylesheet" crossorigin href="/assets/index-i7sU9SN-.css">
|
|
30
|
+
</head>
|
|
31
|
+
<body>
|
|
32
|
+
<div class="app" id="app" data-m="office">
|
|
33
|
+
<aside class="side">
|
|
34
|
+
<header class="brand">
|
|
35
|
+
<div class="title">
|
|
36
|
+
<h1>Agent Office</h1>
|
|
37
|
+
<span class="title-end">
|
|
38
|
+
<span class="lv" id="lv">Lv 1</span>
|
|
39
|
+
<button type="button" class="theme-btn" id="lbBtn" aria-label="Leaderboard" aria-haspopup="true" aria-expanded="false" title="Leaderboard">
|
|
40
|
+
<svg viewBox="0 0 24 24"><path d="M8 4h8v5a4 4 0 0 1-8 0z"/><path d="M8 6H5v1a3 3 0 0 0 3 3"/><path d="M16 6h3v1a3 3 0 0 1-3 3"/><path d="M12 13v4"/><path d="M8.5 20h7"/></svg>
|
|
41
|
+
</button>
|
|
42
|
+
<button type="button" class="theme-btn" id="acctBtn" aria-label="Claude access" aria-haspopup="true" aria-expanded="false" title="Claude access">
|
|
43
|
+
<svg viewBox="0 0 24 24"><circle cx="8" cy="15" r="4"/><path d="M10.8 12.2 20 3"/><path d="m17 6 3 3"/><path d="m14.5 8.5 2 2"/></svg>
|
|
44
|
+
</button>
|
|
45
|
+
<button type="button" class="theme-btn" id="themeBtn" aria-label="Appearance" aria-haspopup="true" aria-expanded="false" title="Appearance">
|
|
46
|
+
<svg viewBox="0 0 24 24"><path d="M12 3a9 9 0 1 0 0 18c1.4 0 2-.9 2-1.8 0-.9-.6-1.3-.6-2.2 0-1 .8-1.6 1.8-1.6H17a4 4 0 0 0 4-4C21 6.7 17 3 12 3z"/><circle cx="7.5" cy="11" r="1"/><circle cx="10" cy="7" r="1"/><circle cx="15" cy="7.5" r="1"/></svg>
|
|
47
|
+
</button>
|
|
48
|
+
</span>
|
|
49
|
+
<div class="theme-pop" id="themePop" role="dialog" aria-label="Appearance" hidden></div>
|
|
50
|
+
<div class="theme-pop lb-pop" id="lbPop" role="dialog" aria-label="Leaderboard" hidden></div>
|
|
51
|
+
<div class="theme-pop acct-pop" id="acctPop" role="dialog" aria-label="Claude access" hidden></div>
|
|
52
|
+
</div>
|
|
53
|
+
<div class="level">
|
|
54
|
+
<div class="xpbar"><i id="xpbar"></i></div>
|
|
55
|
+
<span class="xp" id="xptext">0 / 100 XP</span>
|
|
56
|
+
</div>
|
|
57
|
+
<div class="usage" id="usage" aria-label="Plan usage">
|
|
58
|
+
<div class="meter" id="useSession">
|
|
59
|
+
<span class="k">Session</span>
|
|
60
|
+
<span class="v"></span>
|
|
61
|
+
<div class="bar"><i></i></div>
|
|
62
|
+
<span class="r"></span>
|
|
63
|
+
</div>
|
|
64
|
+
<div class="meter" id="useWeek">
|
|
65
|
+
<span class="k">Week</span>
|
|
66
|
+
<span class="v"></span>
|
|
67
|
+
<div class="bar"><i></i></div>
|
|
68
|
+
<span class="r"></span>
|
|
69
|
+
</div>
|
|
70
|
+
<p class="u-err" id="useErr" hidden></p>
|
|
71
|
+
</div>
|
|
72
|
+
<div class="usage" id="load" aria-label="What the agents are using on this machine" hidden>
|
|
73
|
+
<div class="meter" id="loadCpu">
|
|
74
|
+
<span class="k">CPU</span>
|
|
75
|
+
<span class="v"></span>
|
|
76
|
+
<div class="bar"><i></i></div>
|
|
77
|
+
<span class="r"></span>
|
|
78
|
+
</div>
|
|
79
|
+
<div class="meter" id="loadMem">
|
|
80
|
+
<span class="k">Memory</span>
|
|
81
|
+
<span class="v"></span>
|
|
82
|
+
<div class="bar"><i></i></div>
|
|
83
|
+
<span class="r"></span>
|
|
84
|
+
</div>
|
|
85
|
+
</div>
|
|
86
|
+
</header>
|
|
87
|
+
<nav class="tabs">
|
|
88
|
+
<button type="button" data-tab="chat" class="on">Chat</button>
|
|
89
|
+
<button type="button" data-tab="jobs">Jobs <span id="jobCount"></span></button>
|
|
90
|
+
<button type="button" data-tab="projects">Projects</button>
|
|
91
|
+
<button type="button" data-tab="team">Team</button>
|
|
92
|
+
</nav>
|
|
93
|
+
<section class="pane" id="chatPane">
|
|
94
|
+
<div class="channels" id="channels" role="tablist" aria-label="Channels"></div>
|
|
95
|
+
<div class="msgs" id="msgs"></div>
|
|
96
|
+
<div class="typing" id="typing" hidden><span></span><span></span><span></span> Chief is reading</div>
|
|
97
|
+
<form class="composer" id="composer">
|
|
98
|
+
<div class="ac" id="ac" hidden></div>
|
|
99
|
+
<div class="tray" id="tray" hidden></div>
|
|
100
|
+
<div class="rec" id="rec" hidden><i></i><span id="recText">Recording</span><button type="button" id="recStop" class="link">Stop</button><button type="button" id="recDrop" class="link">Discard</button></div>
|
|
101
|
+
<textarea id="input" rows="1" placeholder="Message the office · @agent #project" aria-label="Message the office"></textarea>
|
|
102
|
+
<div class="controls">
|
|
103
|
+
<button type="button" class="mic" id="mic" title="Record a voice note (hold ⌥M)" aria-label="Record a voice note">
|
|
104
|
+
<svg viewBox="0 0 24 24"><path d="M12 3a3 3 0 0 1 3 3v5a3 3 0 0 1-6 0V6a3 3 0 0 1 3-3z"/><path d="M5 11a7 7 0 0 0 14 0"/><path d="M12 18v3"/></svg>
|
|
105
|
+
</button>
|
|
106
|
+
<button type="button" class="attach" id="attach" title="Attach files or images (or paste / drop them)" aria-label="Attach files">
|
|
107
|
+
<svg viewBox="0 0 24 24"><path d="M21 11.5l-8.6 8.6a5.5 5.5 0 0 1-7.8-7.8l8.6-8.6a3.7 3.7 0 0 1 5.2 5.2l-8.6 8.6a1.8 1.8 0 0 1-2.6-2.6l7.9-7.9"/></svg>
|
|
108
|
+
</button>
|
|
109
|
+
<input type="file" id="file" multiple hidden />
|
|
110
|
+
<select id="mode" aria-label="Clearance for new work">
|
|
111
|
+
<option value="plan">Plan only</option>
|
|
112
|
+
<option value="edit" selected>Edit files</option>
|
|
113
|
+
<option value="auto">Full autonomy</option>
|
|
114
|
+
</select>
|
|
115
|
+
<select id="model" aria-label="Model for new work">
|
|
116
|
+
<option value="">Chief picks</option>
|
|
117
|
+
<optgroup label="Fable">
|
|
118
|
+
<option value="claude-fable-5-1">Fable 5.1</option>
|
|
119
|
+
<option value="claude-fable-5">Fable 5</option>
|
|
120
|
+
</optgroup>
|
|
121
|
+
<optgroup label="Opus">
|
|
122
|
+
<option value="claude-opus-5-5">Opus 5.5</option>
|
|
123
|
+
<option value="claude-opus-5">Opus 5</option>
|
|
124
|
+
<option value="claude-opus-4-8">Opus 4.8</option>
|
|
125
|
+
<option value="claude-opus-4-7">Opus 4.7</option>
|
|
126
|
+
<option value="claude-opus-4-6">Opus 4.6</option>
|
|
127
|
+
</optgroup>
|
|
128
|
+
<optgroup label="Sonnet">
|
|
129
|
+
<option value="claude-sonnet-5-5">Sonnet 5.5</option>
|
|
130
|
+
<option value="claude-sonnet-5">Sonnet 5</option>
|
|
131
|
+
<option value="claude-sonnet-4-6">Sonnet 4.6</option>
|
|
132
|
+
</optgroup>
|
|
133
|
+
<optgroup label="Haiku">
|
|
134
|
+
<option value="claude-haiku-5-5">Haiku 5.5</option>
|
|
135
|
+
<option value="claude-haiku-4-5">Haiku 4.5</option>
|
|
136
|
+
</optgroup>
|
|
137
|
+
</select>
|
|
138
|
+
<button class="primary small" type="submit">Send</button>
|
|
139
|
+
</div>
|
|
140
|
+
</form>
|
|
141
|
+
</section>
|
|
142
|
+
<section class="pane" id="threadPane" hidden>
|
|
143
|
+
<header class="thread-head">
|
|
144
|
+
<button type="button" class="link" id="threadBack">← Chat</button>
|
|
145
|
+
<b id="threadWhere">Thread</b>
|
|
146
|
+
</header>
|
|
147
|
+
<div class="msgs" id="threadMsgs"></div>
|
|
148
|
+
<form class="composer" id="threadComposer">
|
|
149
|
+
<textarea id="threadInput" rows="1" placeholder="Reply in thread" aria-label="Reply in thread"></textarea>
|
|
150
|
+
<div class="controls">
|
|
151
|
+
<button class="primary small" type="submit">Reply</button>
|
|
152
|
+
</div>
|
|
153
|
+
</form>
|
|
154
|
+
</section>
|
|
155
|
+
<section class="pane" id="teamPane" hidden>
|
|
156
|
+
<div class="team" id="team"></div>
|
|
157
|
+
</section>
|
|
158
|
+
<section class="pane" id="projectsPane" hidden>
|
|
159
|
+
<div class="projects" id="projects"></div>
|
|
160
|
+
</section>
|
|
161
|
+
<section class="pane" id="jobsPane" hidden>
|
|
162
|
+
<div class="jobs" id="jobs"></div>
|
|
163
|
+
<button class="ghost" id="clear" hidden>Clear finished</button>
|
|
164
|
+
</section>
|
|
165
|
+
</aside>
|
|
166
|
+
|
|
167
|
+
<main class="view" id="view">
|
|
168
|
+
<div id="stage"></div>
|
|
169
|
+
<div id="labels"></div>
|
|
170
|
+
|
|
171
|
+
<div class="hud">
|
|
172
|
+
<div class="chip away" id="away" hidden></div>
|
|
173
|
+
<div class="chip" id="stats"></div>
|
|
174
|
+
<div class="chip tools">
|
|
175
|
+
<button type="button" id="turnLeft" title="Turn left (Q)" aria-label="Turn left">
|
|
176
|
+
<svg viewBox="0 0 24 24"><path d="M9 7H4V2"/><path d="M4.6 7A9 9 0 1 1 3 13"/></svg>
|
|
177
|
+
</button>
|
|
178
|
+
<button type="button" id="turnRight" title="Turn right (E)" aria-label="Turn right">
|
|
179
|
+
<svg viewBox="0 0 24 24"><path d="M15 7h5V2"/><path d="M19.4 7A9 9 0 1 0 21 13"/></svg>
|
|
180
|
+
</button>
|
|
181
|
+
<button type="button" id="recenter" title="Recenter (R)" aria-label="Recenter">
|
|
182
|
+
<svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="3"/><path d="M12 2v3M12 19v3M2 12h3M19 12h3"/></svg>
|
|
183
|
+
</button>
|
|
184
|
+
<button type="button" id="standup" title="Call a standup" aria-label="Call a standup">
|
|
185
|
+
<svg viewBox="0 0 24 24"><circle cx="12" cy="5" r="2"/><circle cx="5" cy="15" r="2"/><circle cx="19" cy="15" r="2"/><path d="M8.5 20.5a7.5 7.5 0 0 0 7 0M3.5 10.5a8.5 8.5 0 0 1 4.5-5M20.5 10.5a8.5 8.5 0 0 0-4.5-5"/></svg>
|
|
186
|
+
</button>
|
|
187
|
+
<button type="button" id="termToggle" title="Terminal (⌃`)" aria-label="Terminal">
|
|
188
|
+
<svg viewBox="0 0 24 24"><rect x="2.5" y="4" width="19" height="16" rx="2.5"/><path d="M7 9.5l2.6 2.5L7 14.5"/><path d="M12.6 15h4.6"/></svg>
|
|
189
|
+
</button>
|
|
190
|
+
<span class="sep"></span>
|
|
191
|
+
<button type="button" class="sound" id="sound" aria-label="Sound on" title="Sound on"></button>
|
|
192
|
+
<button type="button" class="sound" id="speak" aria-label="Read replies aloud" title="Read replies aloud"></button>
|
|
193
|
+
</div>
|
|
194
|
+
</div>
|
|
195
|
+
|
|
196
|
+
<div class="banner" id="banner"></div>
|
|
197
|
+
<div class="toast" id="toast"></div>
|
|
198
|
+
<p class="hint">Drag to move · Right-drag or Q / E to turn · Scroll to zoom · Double-click to go there</p>
|
|
199
|
+
|
|
200
|
+
<section class="term" id="term" hidden aria-label="Terminal">
|
|
201
|
+
<div class="term-grip" id="termGrip" role="separator" aria-orientation="horizontal" aria-label="Resize the terminal" tabindex="0"></div>
|
|
202
|
+
<header class="term-bar">
|
|
203
|
+
<div class="term-tabs" id="termTabs" role="tablist" aria-label="Terminal sessions"></div>
|
|
204
|
+
<select id="termFolder" aria-label="Folder for the next terminal"></select>
|
|
205
|
+
<button type="button" class="term-icon" id="termNew" title="New terminal" aria-label="New terminal">
|
|
206
|
+
<svg viewBox="0 0 24 24"><path d="M12 5v14M5 12h14"/></svg>
|
|
207
|
+
</button>
|
|
208
|
+
<span class="term-fill"></span>
|
|
209
|
+
<span class="term-note" id="termNote"></span>
|
|
210
|
+
<button type="button" class="term-icon" id="termHide" title="Hide the terminal (⌃`)" aria-label="Hide the terminal">
|
|
211
|
+
<svg viewBox="0 0 24 24"><path d="M6 18L18 6M6 6l12 12"/></svg>
|
|
212
|
+
</button>
|
|
213
|
+
</header>
|
|
214
|
+
<div class="term-body" id="termBody"></div>
|
|
215
|
+
<div class="term-off" id="termOff" hidden></div>
|
|
216
|
+
</section>
|
|
217
|
+
</main>
|
|
218
|
+
|
|
219
|
+
<aside class="detail" id="detail" hidden></aside>
|
|
220
|
+
|
|
221
|
+
<nav class="mnav" id="mnav" aria-label="Sections">
|
|
222
|
+
<button type="button" data-m="office" class="on">
|
|
223
|
+
<svg viewBox="0 0 24 24"><path d="M3 10.5L12 4l9 6.5"/><path d="M5 9.5V20h14V9.5"/><path d="M10 20v-5h4v5"/></svg>Office
|
|
224
|
+
</button>
|
|
225
|
+
<button type="button" data-m="chat">
|
|
226
|
+
<svg viewBox="0 0 24 24"><path d="M4 5h16v11H9l-5 4z"/></svg>Chat<i class="dot" id="mChatDot" hidden></i>
|
|
227
|
+
</button>
|
|
228
|
+
<button type="button" data-m="jobs">
|
|
229
|
+
<svg viewBox="0 0 24 24"><path d="M4 7h16M4 12h16M4 17h10"/></svg>Jobs<b id="mJobCount"></b>
|
|
230
|
+
</button>
|
|
231
|
+
<button type="button" data-m="projects">
|
|
232
|
+
<svg viewBox="0 0 24 24"><path d="M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/></svg>Projects
|
|
233
|
+
</button>
|
|
234
|
+
<button type="button" data-m="team">
|
|
235
|
+
<svg viewBox="0 0 24 24"><circle cx="9" cy="8" r="3.2"/><path d="M3 20a6 6 0 0 1 12 0"/><circle cx="17" cy="9" r="2.4"/><path d="M17 14.5a4.6 4.6 0 0 1 4 5.5"/></svg>Team
|
|
236
|
+
</button>
|
|
237
|
+
</nav>
|
|
238
|
+
</div>
|
|
239
|
+
</body>
|
|
240
|
+
</html>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Agent Office",
|
|
3
|
+
"short_name": "Office",
|
|
4
|
+
"description": "Your office of agents, from anywhere.",
|
|
5
|
+
"start_url": "/",
|
|
6
|
+
"scope": "/",
|
|
7
|
+
"display": "standalone",
|
|
8
|
+
"orientation": "any",
|
|
9
|
+
"background_color": "#fbf9f5",
|
|
10
|
+
"theme_color": "#fbf9f5",
|
|
11
|
+
"icons": [
|
|
12
|
+
{ "src": "/icon-192.png", "sizes": "192x192", "type": "image/png", "purpose": "any" },
|
|
13
|
+
{ "src": "/icon-512.png", "sizes": "512x512", "type": "image/png", "purpose": "any" },
|
|
14
|
+
{ "src": "/icon-512.png", "sizes": "512x512", "type": "image/png", "purpose": "maskable" }
|
|
15
|
+
]
|
|
16
|
+
}
|
package/dist/sw.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// Keeps the app shell openable when the connection drops. Live data (/api,
|
|
2
|
+
// the websocket) is never cached: stale office state is worse than none.
|
|
3
|
+
const SHELL = 'office-shell-v1';
|
|
4
|
+
|
|
5
|
+
self.addEventListener('install', () => self.skipWaiting());
|
|
6
|
+
self.addEventListener('activate', (e) => {
|
|
7
|
+
e.waitUntil(
|
|
8
|
+
caches.keys()
|
|
9
|
+
.then((keys) => Promise.all(keys.filter((k) => k !== SHELL).map((k) => caches.delete(k))))
|
|
10
|
+
.then(() => self.clients.claim()),
|
|
11
|
+
);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
self.addEventListener('fetch', (e) => {
|
|
15
|
+
const req = e.request;
|
|
16
|
+
const url = new URL(req.url);
|
|
17
|
+
if (req.method !== 'GET' || url.origin !== self.location.origin || url.pathname.startsWith('/api')) return;
|
|
18
|
+
|
|
19
|
+
// Hashed build files never change: serve from cache, fill on first sight.
|
|
20
|
+
if (url.pathname.startsWith('/assets/')) {
|
|
21
|
+
e.respondWith(caches.open(SHELL).then(async (cache) => {
|
|
22
|
+
const hit = await cache.match(req);
|
|
23
|
+
if (hit) return hit;
|
|
24
|
+
const res = await fetch(req);
|
|
25
|
+
if (res.ok) cache.put(req, res.clone());
|
|
26
|
+
return res;
|
|
27
|
+
}));
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// The page itself: fresh when online, last copy when not.
|
|
32
|
+
if (req.mode === 'navigate') {
|
|
33
|
+
e.respondWith(
|
|
34
|
+
fetch(req)
|
|
35
|
+
.then((res) => { if (res.ok) caches.open(SHELL).then((c) => c.put('/', res.clone())); return res; })
|
|
36
|
+
.catch(() => caches.match('/')),
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
});
|
package/docs/README.md
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Agent Office documentation
|
|
2
|
+
|
|
3
|
+
**Guides**
|
|
4
|
+
- [Your first job](guides/your-first-job.md) — from a fresh install to a change you've reviewed
|
|
5
|
+
- [Working with the team](guides/working-with-the-team.md) — briefs that work, clearance, channels, cost
|
|
6
|
+
- [Troubleshooting](guides/troubleshooting.md) — common problems and their fixes
|
|
7
|
+
- [Updating](guides/updating.md) — new versions without losing your office
|
|
8
|
+
|
|
9
|
+
**Reference**
|
|
10
|
+
- [Getting started](getting-started.md) — install, run, point it at your projects
|
|
11
|
+
- [Using the office](using-the-office.md) — the chat, channels, threads, standup, the break room
|
|
12
|
+
- [Jobs](jobs.md) — clearance, which model, what changed
|
|
13
|
+
- [The leaderboard](leaderboard.md) — an optional board of jobs, tokens and agent time
|
|
14
|
+
|
|
15
|
+
**Setting it up**
|
|
16
|
+
- [Claude access](claude-access.md) — Claude Code login or API key, and the plan meters
|
|
17
|
+
- [Configuration](configuration.md) — every setting
|
|
18
|
+
- [Talking out loud](voice.md) — speech in and voices out, all on this machine
|
|
19
|
+
- [The terminal](terminal.md) — a real shell under the office
|
|
20
|
+
- [On your phone](phone.md) — install it like an app, reach it over Tailscale
|
|
21
|
+
|
|
22
|
+
**Under the hood**
|
|
23
|
+
- [How the office works](how-it-works.md) — jobs, agents' office tools, where things are kept
|
|
24
|
+
- [Security](security.md) — who can reach it and what jobs may do
|
|
25
|
+
- [Development](development.md) — dev server, shipping, testing safely
|
|
26
|
+
- [Packaging roadmap](packaging.md) — from a clone to an install
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Claude access
|
|
2
|
+
|
|
3
|
+
The key button beside Appearance chooses how the office signs in to Claude:
|
|
4
|
+
|
|
5
|
+
- **Claude Code login** — the login Claude Code keeps on this machine, so jobs
|
|
6
|
+
run on your Claude plan and the plan meters show how much of it is used.
|
|
7
|
+
- **API key** — an Anthropic API key, billed to that API account. Paste it
|
|
8
|
+
once; it's checked with Anthropic, kept in `data/auth.json` (readable only by
|
|
9
|
+
you) and never sent back to the browser. A key already in
|
|
10
|
+
`ANTHROPIC_API_KEY` is used until you paste another. The plan meters hide,
|
|
11
|
+
because there's no plan.
|
|
12
|
+
|
|
13
|
+
The choice applies to every `claude` the office starts: jobs, the chief,
|
|
14
|
+
standup and break-room talk. With the login chosen, a stray
|
|
15
|
+
`ANTHROPIC_API_KEY` in your shell is kept away from them, since `claude` would
|
|
16
|
+
otherwise prefer it. Jobs already running finish the way they started. The
|
|
17
|
+
in-app terminal is your own shell and never gets the office's key.
|
|
18
|
+
|
|
19
|
+
## Plan usage
|
|
20
|
+
|
|
21
|
+
Under the level bar, two meters show how much of your Claude plan is used:
|
|
22
|
+
**This session** (the 5-hour window) and **This week**, each with when it
|
|
23
|
+
resets and a countdown. They turn amber at 70% and red at 90%. The server reads
|
|
24
|
+
the same numbers as Claude Code's `/usage`, using the login Claude Code keeps
|
|
25
|
+
on this machine (the macOS keychain, `~/.claude/.credentials.json`, or
|
|
26
|
+
`CLAUDE_CODE_OAUTH_TOKEN`). It checks every two minutes and shortly after each
|
|
27
|
+
turn finishes.
|
|
28
|
+
|
|
29
|
+
The meters only apply to the Claude Code login. They use the same endpoint
|
|
30
|
+
Claude Code does, which isn't a published API, so if it stops answering the
|
|
31
|
+
meters say so and the rest of the office carries on.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Configuration
|
|
2
|
+
|
|
3
|
+
Everything is set with environment variables when the server starts, e.g.
|
|
4
|
+
`PORT=4400 CHIEF_MODEL=haiku npm start`. In-app choices — Claude access, the
|
|
5
|
+
voice toggle, team profiles, theme — are made in the office and remembered.
|
|
6
|
+
|
|
7
|
+
## The office
|
|
8
|
+
|
|
9
|
+
| Env | Default | |
|
|
10
|
+
|---|---|---|
|
|
11
|
+
| `OFFICE_ROOT` | the folder above this one; with `agentoffice`, the folder you run it from | its subfolders are the projects |
|
|
12
|
+
| `OFFICE_DATA` | `data/` here; with `agentoffice`, `~/.agent-office` | where the office keeps its state |
|
|
13
|
+
| `PORT` | `4317` | |
|
|
14
|
+
| `OFFICE_ALLOWED_HOSTS` | none | extra hostnames to accept, comma-separated; see [On your phone](phone.md) |
|
|
15
|
+
|
|
16
|
+
## Claude
|
|
17
|
+
|
|
18
|
+
| Env | Default | |
|
|
19
|
+
|---|---|---|
|
|
20
|
+
| `CLAUDE_BIN` | `claude` | the Claude Code binary |
|
|
21
|
+
| `ANTHROPIC_API_KEY` | none | used when Claude access is set to *API key* and none was pasted; see [Claude access](claude-access.md) |
|
|
22
|
+
| `CLAUDE_CODE_OAUTH_TOKEN` | none | a Claude Code login token, for the login mode and the plan meters |
|
|
23
|
+
| `CHIEF_MODEL` | `sonnet` | the chief of staff, and the standup write-up |
|
|
24
|
+
| `AGENT_COMPACT_PCT` | `60` | how full an agent's context gets before Claude Code compacts it |
|
|
25
|
+
|
|
26
|
+
## Standup and the break room
|
|
27
|
+
|
|
28
|
+
| Env | Default | |
|
|
29
|
+
|---|---|---|
|
|
30
|
+
| `STANDUP_AT` | `09:30` | local time, or `off` |
|
|
31
|
+
| `STANDUP_WEEKENDS` | unset | `1` holds standups on weekends too |
|
|
32
|
+
| `BANTER` | on | `off` keeps break-room talk to the canned lines |
|
|
33
|
+
| `BANTER_MODEL` | `haiku` | the model that writes break-room talk |
|
|
34
|
+
| `BANTER_GAP_SECONDS` | `120` | at most one written conversation per this many seconds |
|
|
35
|
+
|
|
36
|
+
## Voice
|
|
37
|
+
|
|
38
|
+
| Env | Default | |
|
|
39
|
+
|---|---|---|
|
|
40
|
+
| `WHISPER_BIN` | `whisper-cli` | |
|
|
41
|
+
| `WHISPER_MODEL` | the best model in `data/whisper` | point it at a bigger one (`ggml-small.en.bin`) to trade speed for accuracy |
|
|
42
|
+
| `PIPER_BIN` | `data/piper/venv/bin/python` | the voices live in `data/piper/voices` |
|
|
43
|
+
| `FFMPEG_BIN` | `ffmpeg` | |
|
|
44
|
+
|
|
45
|
+
## Terminal
|
|
46
|
+
|
|
47
|
+
| Env | Default | |
|
|
48
|
+
|---|---|---|
|
|
49
|
+
| `OFFICE_LEADERBOARD_URL` | unset | address of a leaderboard service; see [The leaderboard](leaderboard.md) |
|
|
50
|
+
| `OFFICE_TERMINAL` | unset | `1` opens the in-app terminal |
|
|
51
|
+
| `OFFICE_TERMINAL_SHELL` | your `$SHELL` | |
|
|
52
|
+
| `OFFICE_TERMINAL_MAX` | `4` | sessions at once |
|
|
53
|
+
| `OFFICE_TERMINAL_IDLE_MIN` | `30` | `0` never closes an idle shell |
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# Development
|
|
2
|
+
|
|
3
|
+
```bash
|
|
4
|
+
npm install
|
|
5
|
+
npm run dev # server with --watch on :4317, Vite with hot reload on :5317
|
|
6
|
+
```
|
|
7
|
+
|
|
8
|
+
Use <http://localhost:5317> while developing; Vite proxies `/api` and `/ws`
|
|
9
|
+
to the server.
|
|
10
|
+
|
|
11
|
+
## Checking a change
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm run build
|
|
15
|
+
npm test
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
`npm test` is a smoke test: it starts the office from a temporary copy with
|
|
19
|
+
its own data, against a stand-in `claude`, and checks that it serves the app,
|
|
20
|
+
refuses other sites, runs a job with the right clearance and records what
|
|
21
|
+
changed. It costs no tokens and can't touch an office you're using. CI runs
|
|
22
|
+
it on macOS and Linux for every push and pull request.
|
|
23
|
+
|
|
24
|
+
## Shipping a web change
|
|
25
|
+
|
|
26
|
+
`npm run build` writes `dist/`, which the server reads from disk on every
|
|
27
|
+
request. A web-only change goes live with a build and a reload — no server
|
|
28
|
+
restart.
|
|
29
|
+
|
|
30
|
+
## Shipping a server change
|
|
31
|
+
|
|
32
|
+
Server changes need a restart. `npm start` runs the server under a small
|
|
33
|
+
supervisor (`server/supervise.js`) so the office can restart itself:
|
|
34
|
+
|
|
35
|
+
- **You:** type `/restart` in the chat (`/restart now` skips the wait).
|
|
36
|
+
- **An agent:** calls its `restart_office` tool, then ends its turn. It gets a
|
|
37
|
+
message when the office is back, so it can check its change.
|
|
38
|
+
|
|
39
|
+
A restart waits until nobody is mid-turn (up to 10 minutes, then it goes
|
|
40
|
+
anyway), exits with code 75, and the supervisor starts a fresh server. Open
|
|
41
|
+
jobs resume on their sessions. Before exiting, the server checks that its own
|
|
42
|
+
code parses and loads, and refuses if it doesn't, because a broken server would
|
|
43
|
+
leave nothing running to fix it. If the server crashes three times in a row
|
|
44
|
+
within seconds of starting, the supervisor gives up.
|
|
45
|
+
|
|
46
|
+
A server started with plain `node server/index.js`, or with `npm run dev`, has
|
|
47
|
+
no supervisor and refuses to restart itself. Agents must never kill the server
|
|
48
|
+
by signal: its shutdown ends their own process along with everyone else's.
|
|
49
|
+
|
|
50
|
+
## Testing without touching the live office
|
|
51
|
+
|
|
52
|
+
A second server pointed at the same `data/` resumes the live office's jobs.
|
|
53
|
+
Test from a copy instead, on another port, with its own data and a scratch
|
|
54
|
+
project folder:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
rsync -a --exclude data --exclude dist --exclude .git --exclude node_modules ./ /tmp/office-test/
|
|
58
|
+
ln -s "$PWD/node_modules" /tmp/office-test/node_modules
|
|
59
|
+
cd /tmp/office-test && npx vite build
|
|
60
|
+
PORT=4398 OFFICE_ROOT=/tmp/office-test-projects CLAUDE_BIN=/path/to/stub \
|
|
61
|
+
STANDUP_AT=off BANTER=off node server/index.js
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
`CLAUDE_BIN` can point at a stub that records its arguments and environment,
|
|
65
|
+
so you can check what a job was started with without spending tokens.
|
|
66
|
+
`launch/stub.mjs` is a fuller one that plays scripted jobs.
|
|
67
|
+
|
|
68
|
+
When you stop a test server, kill it by PID, not with `pkill -f`, which can't
|
|
69
|
+
tell it from the live one.
|
|
70
|
+
|
|
71
|
+
## The launch video
|
|
72
|
+
|
|
73
|
+
`launch/` holds the tooling that recorded the launch video: `setup.sh` resets a
|
|
74
|
+
sandbox office on port 4399 under `/tmp/office-demo`, `stub.mjs` plays the
|
|
75
|
+
scripted agents, and the Python scripts drive and capture the browser. The
|
|
76
|
+
rendered video itself isn't kept in git.
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Getting started
|
|
2
|
+
|
|
3
|
+
## What you need
|
|
4
|
+
|
|
5
|
+
- **Node.js 20 or newer.**
|
|
6
|
+
- **Claude Code**, installed and on your `PATH` as `claude`. Either sign in
|
|
7
|
+
once by running `claude` in a terminal, or have an Anthropic API key ready
|
|
8
|
+
(see [Claude access](claude-access.md)).
|
|
9
|
+
- **macOS or Linux.** Windows works under WSL.
|
|
10
|
+
- **git**, for the "what changed" card on each job.
|
|
11
|
+
|
|
12
|
+
## Install and run
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
git clone https://github.com/onuohasilver/agent-office.git
|
|
16
|
+
cd agent-office
|
|
17
|
+
npm install
|
|
18
|
+
npm start # builds, then serves on http://localhost:4317
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Open <http://localhost:4317>.
|
|
22
|
+
|
|
23
|
+
## Where your projects are
|
|
24
|
+
|
|
25
|
+
The office's projects are the subfolders of one folder, `OFFICE_ROOT`. By
|
|
26
|
+
default that is the folder the office itself sits in, so a layout like this
|
|
27
|
+
works with no settings:
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
~/code/
|
|
31
|
+
├── agent-office/
|
|
32
|
+
├── storefront/ ← a project
|
|
33
|
+
└── payments-api/ ← a project
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Point it somewhere else with `OFFICE_ROOT=~/work npm start`. Name a project in
|
|
37
|
+
the chat with `#`, e.g. `#storefront`.
|
|
38
|
+
|
|
39
|
+
## Optional extras
|
|
40
|
+
|
|
41
|
+
| Extra | What it adds | How |
|
|
42
|
+
|---|---|---|
|
|
43
|
+
| Voice | talk to the office, hear it answer | [Talking out loud](voice.md) |
|
|
44
|
+
| Terminal | a real shell in a drawer under the office | [The terminal](terminal.md) |
|
|
45
|
+
| Phone | the office on your phone, installed like an app | [On your phone](phone.md) |
|
|
46
|
+
|
|
47
|
+
## Next
|
|
48
|
+
|
|
49
|
+
Run [your first job](guides/your-first-job.md).
|
|
50
|
+
|
|
51
|
+
## Developing
|
|
52
|
+
|
|
53
|
+
`npm run dev` serves with hot reload on <http://localhost:5317>. See
|
|
54
|
+
[Development](development.md).
|