@howaboua/pi-agent-board 0.0.0-stage → 0.0.1

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.
@@ -0,0 +1,481 @@
1
+ :root {
2
+ color-scheme: light;
3
+ --ink: #242522;
4
+ --ink-soft: #30312d;
5
+ --paper: #f5f1e8;
6
+ --text: #282924;
7
+ --muted: #69685f;
8
+ --rule: #d7d1c5;
9
+ --accent: #ac482b;
10
+ --rail-text: #e7e3d9;
11
+ --rail-muted: #b5b3a8;
12
+ font-family:
13
+ system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
14
+ font-size: 14px;
15
+ }
16
+ * {
17
+ box-sizing: border-box;
18
+ }
19
+ body {
20
+ margin: 0;
21
+ background: var(--paper);
22
+ color: var(--text);
23
+ }
24
+ button,
25
+ input,
26
+ select {
27
+ font: inherit;
28
+ }
29
+ button,
30
+ select {
31
+ cursor: pointer;
32
+ }
33
+ button {
34
+ border: 1px solid var(--rule);
35
+ background: transparent;
36
+ color: inherit;
37
+ padding: 7px 11px;
38
+ border-radius: 2px;
39
+ }
40
+ button:hover {
41
+ background: #ded7c9;
42
+ }
43
+ input,
44
+ select {
45
+ min-width: 0;
46
+ border: 1px solid var(--rule);
47
+ border-radius: 2px;
48
+ padding: 8px;
49
+ background: transparent;
50
+ color: inherit;
51
+ }
52
+ input[type="checkbox"] {
53
+ accent-color: var(--accent);
54
+ }
55
+ :focus-visible {
56
+ outline: 2px solid #cc6847;
57
+ outline-offset: 3px;
58
+ }
59
+ label {
60
+ display: block;
61
+ font-size: 12px;
62
+ font-weight: 600;
63
+ margin-bottom: 7px;
64
+ }
65
+ h1,
66
+ h2,
67
+ p {
68
+ margin-top: 0;
69
+ }
70
+ .masthead {
71
+ height: 65px;
72
+ display: flex;
73
+ align-items: center;
74
+ gap: 20px;
75
+ padding: 0 24px;
76
+ background: var(--ink);
77
+ color: var(--rail-text);
78
+ border-bottom: 1px solid #44453f;
79
+ }
80
+ .masthead h1 {
81
+ font-family: Georgia, serif;
82
+ font-size: 23px;
83
+ font-weight: normal;
84
+ margin: 0;
85
+ }
86
+ .live-controls {
87
+ margin-left: auto;
88
+ display: flex;
89
+ align-items: center;
90
+ gap: 16px;
91
+ }
92
+ .live-controls label {
93
+ margin: 0;
94
+ display: flex;
95
+ align-items: center;
96
+ gap: 6px;
97
+ }
98
+ .live-controls button {
99
+ border-color: #626358;
100
+ }
101
+ .live-controls button:hover {
102
+ background: #40413b;
103
+ }
104
+ #status {
105
+ background: #e9ddca;
106
+ color: #713821;
107
+ padding: 9px 24px;
108
+ border-bottom: 1px solid var(--rule);
109
+ }
110
+ #status:empty {
111
+ display: none;
112
+ }
113
+ .workspace {
114
+ display: grid;
115
+ grid-template-columns: 225px 330px minmax(0, 1fr);
116
+ height: calc(100dvh - 65px);
117
+ }
118
+ body:has(#status:not(:empty)) .workspace {
119
+ height: calc(100dvh - 104px);
120
+ }
121
+ .rail,
122
+ .index,
123
+ .conversation {
124
+ overflow: auto;
125
+ }
126
+ .rail {
127
+ background: var(--ink);
128
+ color: var(--rail-text);
129
+ padding: 25px 18px;
130
+ }
131
+ .rail select {
132
+ width: 100%;
133
+ border-color: #616258;
134
+ background: var(--ink);
135
+ }
136
+ .context {
137
+ color: var(--rail-muted);
138
+ font-size: 12px;
139
+ line-height: 1.5;
140
+ margin: 10px 0 28px;
141
+ overflow-wrap: anywhere;
142
+ }
143
+ .rail nav {
144
+ display: grid;
145
+ gap: 3px;
146
+ }
147
+ .rail nav button {
148
+ text-align: left;
149
+ display: flex;
150
+ justify-content: space-between;
151
+ gap: 8px;
152
+ border: 0;
153
+ padding: 10px 9px;
154
+ border-radius: 0;
155
+ overflow-wrap: anywhere;
156
+ }
157
+ .rail nav button:hover {
158
+ background: #3b3c35;
159
+ }
160
+ .rail nav button[aria-current="true"] {
161
+ background: #3b3c35;
162
+ border-left: 3px solid #d77650;
163
+ padding-left: 6px;
164
+ }
165
+ .rail nav small {
166
+ color: var(--rail-muted);
167
+ }
168
+ .agent-filter {
169
+ margin-top: 30px;
170
+ }
171
+ details {
172
+ border-top: 1px solid #4a4b43;
173
+ margin-top: 25px;
174
+ padding-top: 16px;
175
+ font-size: 12px;
176
+ color: var(--rail-muted);
177
+ }
178
+ summary {
179
+ cursor: pointer;
180
+ padding: 5px 0;
181
+ }
182
+ #subscriptions p {
183
+ line-height: 1.6;
184
+ overflow-wrap: anywhere;
185
+ margin: 12px 0;
186
+ }
187
+ .index {
188
+ border-right: 1px solid var(--rule);
189
+ background: #eae6dd;
190
+ }
191
+ .index-head {
192
+ padding: 25px 20px 20px;
193
+ border-bottom: 1px solid var(--rule);
194
+ }
195
+ .index-head h2 {
196
+ font-size: 19px;
197
+ font-weight: 600;
198
+ margin-bottom: 21px;
199
+ overflow-wrap: anywhere;
200
+ }
201
+ .search-row {
202
+ display: flex;
203
+ gap: 6px;
204
+ }
205
+ .search-row input {
206
+ width: 100%;
207
+ background: var(--paper);
208
+ }
209
+ .search-row button {
210
+ padding: 7px;
211
+ }
212
+ .thread {
213
+ display: block;
214
+ text-decoration: none;
215
+ color: inherit;
216
+ padding: 18px 20px;
217
+ border-bottom: 1px solid var(--rule);
218
+ border-left: 3px solid transparent;
219
+ }
220
+ .thread:hover {
221
+ background: #f1ede5;
222
+ }
223
+ .thread[aria-current="true"] {
224
+ background: var(--paper);
225
+ border-left-color: var(--accent);
226
+ }
227
+ .thread-meta {
228
+ display: flex;
229
+ gap: 8px;
230
+ align-items: center;
231
+ font-size: 11px;
232
+ color: var(--muted);
233
+ margin-bottom: 9px;
234
+ }
235
+ .thread-meta .author {
236
+ flex: 1;
237
+ min-width: 0;
238
+ }
239
+ .author {
240
+ white-space: nowrap;
241
+ overflow: hidden;
242
+ text-overflow: ellipsis;
243
+ max-width: 100%;
244
+ display: inline-block;
245
+ vertical-align: bottom;
246
+ }
247
+ .thread-preview {
248
+ font-size: 14px;
249
+ line-height: 1.55;
250
+ margin: 0 0 10px;
251
+ display: -webkit-box;
252
+ -webkit-line-clamp: 3;
253
+ -webkit-box-orient: vertical;
254
+ overflow: hidden;
255
+ overflow-wrap: anywhere;
256
+ }
257
+ .thread-foot {
258
+ font-size: 11px;
259
+ color: var(--muted);
260
+ display: flex;
261
+ justify-content: space-between;
262
+ gap: 8px;
263
+ }
264
+ .conversation {
265
+ padding: 30px clamp(22px, 4vw, 64px) 60px;
266
+ }
267
+ .post {
268
+ max-width: 800px;
269
+ margin: 0 auto;
270
+ padding: 26px 0;
271
+ border-bottom: 1px solid var(--rule);
272
+ }
273
+ .post:first-child {
274
+ padding-top: 0;
275
+ }
276
+ .post-header {
277
+ display: flex;
278
+ align-items: baseline;
279
+ gap: 14px;
280
+ margin-bottom: 21px;
281
+ font-size: 12px;
282
+ color: var(--muted);
283
+ }
284
+ .post-header .author {
285
+ font-weight: 650;
286
+ color: var(--text);
287
+ max-width: 65%;
288
+ }
289
+ .post-header time {
290
+ margin-left: auto;
291
+ white-space: nowrap;
292
+ font-size: 11px;
293
+ }
294
+ .post-channel {
295
+ font-size: 12px;
296
+ color: var(--accent);
297
+ margin-bottom: 12px;
298
+ overflow-wrap: anywhere;
299
+ }
300
+ .prose {
301
+ font-size: 15px;
302
+ line-height: 1.75;
303
+ overflow-wrap: anywhere;
304
+ }
305
+ .prose p {
306
+ margin-bottom: 1em;
307
+ }
308
+ .prose h1,
309
+ .prose h2,
310
+ .prose h3 {
311
+ line-height: 1.3;
312
+ margin: 1.5em 0 0.7em;
313
+ }
314
+ .prose h1 {
315
+ font-size: 27px;
316
+ }
317
+ .prose h2 {
318
+ font-size: 22px;
319
+ }
320
+ .prose h3 {
321
+ font-size: 18px;
322
+ }
323
+ .prose a {
324
+ color: #974127;
325
+ text-underline-offset: 3px;
326
+ }
327
+ .prose pre {
328
+ overflow: auto;
329
+ background: #e8e2d7;
330
+ padding: 16px;
331
+ font-size: 12px;
332
+ line-height: 1.6;
333
+ }
334
+ .prose code {
335
+ font-family: ui-monospace, SFMono-Regular, Consolas, monospace;
336
+ font-size: 0.88em;
337
+ }
338
+ .prose :not(pre) > code {
339
+ background: #e8e2d7;
340
+ padding: 2px 4px;
341
+ }
342
+ .prose blockquote {
343
+ margin: 1em 0;
344
+ padding-left: 20px;
345
+ border-left: 2px solid #baa88c;
346
+ color: var(--muted);
347
+ }
348
+ .prose table {
349
+ display: block;
350
+ overflow: auto;
351
+ border-collapse: collapse;
352
+ }
353
+ .prose td,
354
+ .prose th {
355
+ border: 1px solid var(--rule);
356
+ padding: 7px 12px;
357
+ }
358
+ .prose img {
359
+ display: none;
360
+ }
361
+ .empty {
362
+ padding: 48px 8px;
363
+ color: var(--muted);
364
+ max-width: 600px;
365
+ }
366
+ .index .empty {
367
+ padding: 25px 20px;
368
+ }
369
+ .page-button {
370
+ display: block;
371
+ margin: 24px auto;
372
+ }
373
+ button[hidden] {
374
+ display: none;
375
+ }
376
+ #back {
377
+ display: none;
378
+ }
379
+ .rail nav small {
380
+ flex-shrink: 0;
381
+ white-space: nowrap;
382
+ }
383
+ @media (min-width: 1500px) {
384
+ .workspace {
385
+ grid-template-columns: 245px 380px minmax(0, 1fr);
386
+ }
387
+ }
388
+ @media (max-width: 1000px) {
389
+ .workspace {
390
+ grid-template-columns: 190px 280px minmax(0, 1fr);
391
+ }
392
+ .rail {
393
+ padding: 20px 12px;
394
+ }
395
+ .conversation {
396
+ padding: 25px 22px;
397
+ }
398
+ .post-header {
399
+ flex-wrap: wrap;
400
+ gap: 8px;
401
+ }
402
+ .post-header time {
403
+ margin-left: 0;
404
+ }
405
+ .post-header .author {
406
+ max-width: 100%;
407
+ }
408
+ }
409
+ @media (max-width: 760px) {
410
+ .masthead {
411
+ height: 60px;
412
+ padding: 0 16px;
413
+ gap: 12px;
414
+ }
415
+ .masthead h1 {
416
+ font-size: 21px;
417
+ }
418
+ .live-controls {
419
+ gap: 8px;
420
+ }
421
+ .live-controls button {
422
+ padding: 6px 8px;
423
+ }
424
+ .workspace,
425
+ body:has(#status:not(:empty)) .workspace {
426
+ display: block;
427
+ height: auto;
428
+ }
429
+ .rail {
430
+ padding: 16px;
431
+ }
432
+ .rail .context {
433
+ margin-bottom: 12px;
434
+ }
435
+ .rail nav {
436
+ display: flex;
437
+ overflow: auto;
438
+ margin-top: 12px;
439
+ }
440
+ .rail nav button {
441
+ flex-shrink: 0;
442
+ max-width: 240px;
443
+ }
444
+ .agent-filter {
445
+ margin-top: 14px;
446
+ }
447
+ .rail details {
448
+ margin-top: 14px;
449
+ padding-top: 10px;
450
+ }
451
+ .index {
452
+ border-right: 0;
453
+ }
454
+ .conversation {
455
+ display: none;
456
+ }
457
+ .detail-open .rail,
458
+ .detail-open .index {
459
+ display: none;
460
+ }
461
+ .detail-open .conversation {
462
+ display: block;
463
+ min-height: calc(100dvh - 60px);
464
+ }
465
+ #back {
466
+ display: block;
467
+ margin-bottom: 28px;
468
+ }
469
+ .index-head {
470
+ padding: 22px 16px;
471
+ }
472
+ .thread {
473
+ padding: 18px 16px;
474
+ }
475
+ .post-header {
476
+ display: flex;
477
+ }
478
+ .empty {
479
+ padding-top: 25px;
480
+ }
481
+ }
package/index.ts ADDED
@@ -0,0 +1,63 @@
1
+ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
2
+ import { binding } from "./src/identity.js";
3
+ import { acquireBoard } from "./src/runtime.js";
4
+ import { openBoardViewer } from "./src/viewer/index.js";
5
+
6
+ export default async function agentBoardExtension(pi: ExtensionAPI) {
7
+ const board = await acquireBoard(pi);
8
+ pi.registerCommand("board", {
9
+ description: "Board viewer; on|off|inherit [session|folder|global], status",
10
+ async handler(args, ctx) {
11
+ const [command = "", scope = "session", ...extra] = args
12
+ .trim()
13
+ .split(/\s+/);
14
+ if (
15
+ (command === "on" || command === "off" || command === "inherit") &&
16
+ (scope === "session" || scope === "folder" || scope === "global") &&
17
+ !extra.length
18
+ ) {
19
+ try {
20
+ if (command === "inherit" && scope === "global")
21
+ throw new Error("Global enablement must be on or off");
22
+ await board.setSetting(
23
+ ctx,
24
+ scope,
25
+ command === "inherit" ? undefined : command === "on",
26
+ );
27
+ ctx.ui.notify(board.status(ctx), "info");
28
+ } catch (error) {
29
+ ctx.ui.notify(
30
+ error instanceof Error ? error.message : String(error),
31
+ "error",
32
+ );
33
+ }
34
+ return;
35
+ }
36
+ if (args.trim() === "status") {
37
+ ctx.ui.notify(board.status(ctx), "info");
38
+ return;
39
+ }
40
+ if (command) {
41
+ ctx.ui.notify(
42
+ "Use /board, /board status or /board on|off|inherit [session|folder|global]",
43
+ "warning",
44
+ );
45
+ return;
46
+ }
47
+ await openBoardViewer(pi, ctx, (context, sessionName) => {
48
+ const own = binding(context);
49
+ if (own.upstream)
50
+ throw new Error(
51
+ "Open /board in the owning root session to view this shared board",
52
+ );
53
+ return {
54
+ sessionId: own.sessionId,
55
+ sessionName: sessionName ?? null,
56
+ boardId: own.boardId,
57
+ folder: own.ownerFolder,
58
+ databasePath: own.databasePath,
59
+ };
60
+ });
61
+ },
62
+ });
63
+ }
package/package.json CHANGED
@@ -1,6 +1,66 @@
1
1
  {
2
- "name": "@howaboua/pi-agent-board",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
2
+ "name": "@howaboua/pi-agent-board",
3
+ "version": "0.0.1",
4
+ "description": "Standalone agent message boards and a read-only browser viewer for Pi",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/IgorWarzocha/howaboua-pi-stuff.git",
10
+ "directory": "packages/pi-agent-board"
11
+ },
12
+ "files": [
13
+ "index.ts",
14
+ "src",
15
+ "dist",
16
+ "README.md",
17
+ "INTEGRATION.md",
18
+ "LICENSE",
19
+ "tsconfig.json",
20
+ "changelog.ts",
21
+ "CHANGELOG.md"
22
+ ],
23
+ "main": "index.ts",
24
+ "exports": {
25
+ ".": "./index.ts",
26
+ "./runtime": "./src/runtime.ts",
27
+ "./integration": "./src/integration.ts"
28
+ },
29
+ "pi": {
30
+ "extensions": [
31
+ "./changelog.ts",
32
+ "./index.ts"
33
+ ]
34
+ },
35
+ "engines": {
36
+ "node": ">=22.18.0"
37
+ },
38
+ "scripts": {
39
+ "build": "node scripts/build-viewer.mjs",
40
+ "check": "bun run lint && bun run typecheck",
41
+ "lint": "biome check .",
42
+ "typecheck": "tsgo --noEmit",
43
+ "prepack": "bun run check && bun run build",
44
+ "pack:dry": "npm pack --dry-run"
45
+ },
46
+ "dependencies": {
47
+ "dompurify": "3.4.16",
48
+ "marked": "18.1.0",
49
+ "unicode-case-folding": "1.1.2"
50
+ },
51
+ "peerDependencies": {
52
+ "@earendil-works/pi-ai": ">=1.1.0",
53
+ "@earendil-works/pi-coding-agent": ">=1.1.0",
54
+ "@earendil-works/pi-tui": ">=1.1.0",
55
+ "@howaboua/pi-codex-conversion": ">=3.0.48",
56
+ "typebox": "*"
57
+ },
58
+ "peerDependenciesMeta": {
59
+ "@howaboua/pi-codex-conversion": {
60
+ "optional": true
61
+ }
62
+ },
63
+ "publishConfig": {
64
+ "access": "public"
65
+ }
66
+ }