allaboard 0.0.0-stage → 0.4.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/LICENSE +21 -0
- package/README.md +43 -2
- package/dist/agent/claude/backend.js +124 -0
- package/dist/agent/claude/capabilities.js +30 -0
- package/dist/agent/claude/chrome.js +42 -0
- package/dist/agent/claude/hooks.js +37 -0
- package/dist/agent/claude/info.js +61 -0
- package/dist/agent/claude/listing.js +230 -0
- package/dist/agent/claude/module.js +82 -0
- package/dist/agent/claude/prompt.js +24 -0
- package/dist/agent/claude/record.js +9 -0
- package/dist/agent/claude/requests.js +122 -0
- package/dist/agent/claude/session.js +441 -0
- package/dist/agent/claude/translate.js +581 -0
- package/dist/agent/claude/trust.js +576 -0
- package/dist/agent/claude/usage-probe.js +103 -0
- package/dist/agent/claude/usage.js +110 -0
- package/dist/agent/claude/wire.js +22 -0
- package/dist/agent/seam.js +21 -0
- package/dist/chat/seam.js +10 -0
- package/dist/chat/slack/app/answers.js +209 -0
- package/dist/chat/slack/app/app.js +262 -0
- package/dist/chat/slack/app/clip.js +191 -0
- package/dist/chat/slack/app/guards.js +162 -0
- package/dist/chat/slack/app/home-controls.js +91 -0
- package/dist/chat/slack/app/messages.js +181 -0
- package/dist/chat/slack/app/open.js +392 -0
- package/dist/chat/slack/app/order.js +37 -0
- package/dist/chat/slack/app/requests.js +482 -0
- package/dist/chat/slack/app/resume-bind.js +71 -0
- package/dist/chat/slack/app/wire.js +83 -0
- package/dist/chat/slack/attachments.js +348 -0
- package/dist/chat/slack/bind.js +67 -0
- package/dist/chat/slack/channel.js +67 -0
- package/dist/chat/slack/channels.js +43 -0
- package/dist/chat/slack/delete.js +278 -0
- package/dist/chat/slack/footer.js +43 -0
- package/dist/chat/slack/hold.js +37 -0
- package/dist/chat/slack/home.js +1069 -0
- package/dist/chat/slack/module.js +174 -0
- package/dist/chat/slack/notice.js +64 -0
- package/dist/chat/slack/openfile/modal.js +362 -0
- package/dist/chat/slack/openfile/read.js +29 -0
- package/dist/chat/slack/quiet-logger.js +52 -0
- package/dist/chat/slack/repair.js +123 -0
- package/dist/chat/slack/reply/blocks.js +372 -0
- package/dist/chat/slack/reply/chars.js +59 -0
- package/dist/chat/slack/reply/clients.js +171 -0
- package/dist/chat/slack/reply/errors.js +125 -0
- package/dist/chat/slack/reply/escape.js +25 -0
- package/dist/chat/slack/reply/limiter.js +86 -0
- package/dist/chat/slack/reply/markdown.js +210 -0
- package/dist/chat/slack/reply/places.js +262 -0
- package/dist/chat/slack/reply/sinks.js +2403 -0
- package/dist/chat/slack/reply/status.js +433 -0
- package/dist/chat/slack/reply/tasks.js +11 -0
- package/dist/chat/slack/requests.js +552 -0
- package/dist/chat/slack/resume.js +127 -0
- package/dist/chat/slack/setup.js +114 -0
- package/dist/chat/slack/texts.js +185 -0
- package/dist/chat/slack/thread.js +537 -0
- package/dist/chat/slack/update.js +71 -0
- package/dist/chat/slack/voice.js +84 -0
- package/dist/cli.js +326 -0
- package/dist/clock.js +21 -0
- package/dist/core/cleanup.js +145 -0
- package/dist/core/commands.js +172 -0
- package/dist/core/config.js +174 -0
- package/dist/core/files/changed.js +125 -0
- package/dist/core/files/listing.js +382 -0
- package/dist/core/files/paths.js +9 -0
- package/dist/core/files/read.js +191 -0
- package/dist/core/files/waiting.js +34 -0
- package/dist/core/flows/answers.js +133 -0
- package/dist/core/flows/ask-owner.js +95 -0
- package/dist/core/flows/asking.js +14 -0
- package/dist/core/flows/bind.js +95 -0
- package/dist/core/flows/contract.js +1 -0
- package/dist/core/flows/flows.js +35 -0
- package/dist/core/flows/hold.js +22 -0
- package/dist/core/flows/inbound.js +24 -0
- package/dist/core/flows/lists.js +21 -0
- package/dist/core/flows/messages.js +293 -0
- package/dist/core/flows/notices.js +51 -0
- package/dist/core/flows/repair.js +106 -0
- package/dist/core/flows/resume.js +163 -0
- package/dist/core/flows/setup.js +130 -0
- package/dist/core/flows/status.js +98 -0
- package/dist/core/flows/talk.js +207 -0
- package/dist/core/flows/update.js +370 -0
- package/dist/core/flows/words.js +171 -0
- package/dist/core/folders.js +93 -0
- package/dist/core/footer.js +313 -0
- package/dist/core/guide.js +50 -0
- package/dist/core/hold.js +126 -0
- package/dist/core/instance.js +46 -0
- package/dist/core/lock.js +412 -0
- package/dist/core/models.js +10 -0
- package/dist/core/paths.js +75 -0
- package/dist/core/port/file-flows.js +1 -0
- package/dist/core/port/home.js +1 -0
- package/dist/core/port/requests.js +1 -0
- package/dist/core/port/threads.js +1 -0
- package/dist/core/port/updates.js +1 -0
- package/dist/core/port.js +17 -0
- package/dist/core/reply/fold.js +175 -0
- package/dist/core/reply/previews.js +258 -0
- package/dist/core/reply/renderer.js +846 -0
- package/dist/core/reply/tail.js +24 -0
- package/dist/core/reply/words.js +32 -0
- package/dist/core/requests.js +158 -0
- package/dist/core/sessions/constants.js +61 -0
- package/dist/core/sessions/deps.js +1 -0
- package/dist/core/sessions/directory.js +86 -0
- package/dist/core/sessions/errors.js +79 -0
- package/dist/core/sessions/manager.js +378 -0
- package/dist/core/sessions/session.js +3297 -0
- package/dist/core/sessions/tasks.js +266 -0
- package/dist/core/sessions/turn.js +45 -0
- package/dist/core/setup.js +28 -0
- package/dist/core/state.js +724 -0
- package/dist/core/texts.js +451 -0
- package/dist/core/updates.js +332 -0
- package/dist/daemon.js +566 -0
- package/dist/host/npm.js +134 -0
- package/dist/host/program.js +49 -0
- package/dist/host/run.js +52 -0
- package/dist/host/service/launchd.js +385 -0
- package/dist/host/service/listing.js +42 -0
- package/dist/host/service/seam.js +1 -0
- package/dist/log.js +37 -0
- package/dist/main.js +29 -0
- package/dist/node-version.js +40 -0
- package/dist/registry.js +12 -0
- package/dist/semver.js +53 -0
- package/dist/text.js +89 -0
- package/dist/updates-host.js +113 -0
- package/dist/values.js +30 -0
- package/dist/version.js +54 -0
- package/package.json +32 -4
- package/slack-app-manifest.json +50 -0
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where the messages of one thread sit, as far as the daemon saw them: the owner's, and the last
|
|
3
|
+
* message of each reply. Kept in memory only (a restart forgets it), and decided by `isLast`,
|
|
4
|
+
* `isOvertaken` and `tails` of the core. The session's footer is not placed here: the session
|
|
5
|
+
* names the reply it goes under. A reply the places let go of leaves its position behind
|
|
6
|
+
* in `floor`, so that the answers do not change when it goes, and keeps showing what it showed.
|
|
7
|
+
*/
|
|
8
|
+
import { isLast, isOvertaken, Mutex, tails, } from "../../../core/port.js";
|
|
9
|
+
/**
|
|
10
|
+
* A Slack `ts` as an integer of microseconds: exact below 2^53, ordered as the thread is. Null
|
|
11
|
+
* for text that is no `ts`, which no position is made of.
|
|
12
|
+
*/
|
|
13
|
+
export function positionOf(ts) {
|
|
14
|
+
if (!/^\d+(\.\d+)?$/.test(ts))
|
|
15
|
+
return null;
|
|
16
|
+
const [seconds = "0", fraction = ""] = ts.split(".");
|
|
17
|
+
const position = Number(seconds) * 1_000_000 + Number(fraction.padEnd(6, "0").slice(0, 6));
|
|
18
|
+
return Number.isSafeInteger(position) ? position : null;
|
|
19
|
+
}
|
|
20
|
+
export class ThreadPlaces {
|
|
21
|
+
/**
|
|
22
|
+
* Held by whoever creates a message of a reply in this thread (a stream's start, a
|
|
23
|
+
* continuation, an ending, a closing message), and by the end's decision whether to create one:
|
|
24
|
+
* two replies cannot each decide on the other's absence. Taken after a sink's own lock, and
|
|
25
|
+
* never while waiting for one.
|
|
26
|
+
*/
|
|
27
|
+
lock = new Mutex();
|
|
28
|
+
replies = new Set();
|
|
29
|
+
/** The replies whose end has landed. */
|
|
30
|
+
done = new Set();
|
|
31
|
+
/** The replies whose opening thread object closed. */
|
|
32
|
+
shut = new Set();
|
|
33
|
+
/** What still runs in the thread, drawn under the reply `tails` names. */
|
|
34
|
+
list = null;
|
|
35
|
+
/** The reply that holds the list now: it is not let go of while it does. */
|
|
36
|
+
holder = null;
|
|
37
|
+
/** The replies that held the list, for a change of it that only debounced. */
|
|
38
|
+
listed = new Set();
|
|
39
|
+
/** The replies about to create their first message: below every other from then on. */
|
|
40
|
+
opening = new Set();
|
|
41
|
+
marks = [];
|
|
42
|
+
/** The highest position of a reply let go of: it still sits in the thread. */
|
|
43
|
+
floor = null;
|
|
44
|
+
/** The highest position of a message of the owner's or of one the app posted outside a reply. */
|
|
45
|
+
latest = null;
|
|
46
|
+
onEmpty;
|
|
47
|
+
/** `onEmpty` is told when the last registered reply is let go of. */
|
|
48
|
+
constructor(onEmpty = () => { }) {
|
|
49
|
+
this.onEmpty = onEmpty;
|
|
50
|
+
}
|
|
51
|
+
/** A reply exists, with a message or without. */
|
|
52
|
+
join(reply) {
|
|
53
|
+
this.replies.add(reply);
|
|
54
|
+
}
|
|
55
|
+
/** Whether the reply is registered and not let go of. */
|
|
56
|
+
holds(reply) {
|
|
57
|
+
return this.replies.has(reply);
|
|
58
|
+
}
|
|
59
|
+
/** Whether any reply is registered. */
|
|
60
|
+
get held() {
|
|
61
|
+
return this.replies.size > 0;
|
|
62
|
+
}
|
|
63
|
+
/** The owner wrote a message of this thread at `ts`. */
|
|
64
|
+
ownerPosted(ts) {
|
|
65
|
+
const at = positionOf(ts);
|
|
66
|
+
if (at === null)
|
|
67
|
+
return;
|
|
68
|
+
this.latest = Math.max(this.latest ?? at, at);
|
|
69
|
+
this.marks.push(at);
|
|
70
|
+
this.place();
|
|
71
|
+
this.release();
|
|
72
|
+
this.prune();
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* The app posted a message of its own in the thread, outside its replies (a notice, a request).
|
|
76
|
+
* It changes no reply's place: it only counts in `newestAt`.
|
|
77
|
+
*/
|
|
78
|
+
posted(ts) {
|
|
79
|
+
const at = positionOf(ts);
|
|
80
|
+
if (at !== null)
|
|
81
|
+
this.latest = Math.max(this.latest ?? at, at);
|
|
82
|
+
}
|
|
83
|
+
/** The position of the newest message of the thread the places know of; null when none. */
|
|
84
|
+
get newestAt() {
|
|
85
|
+
let newest = this.latest ?? this.floor;
|
|
86
|
+
if (this.floor !== null && newest !== null)
|
|
87
|
+
newest = Math.max(newest, this.floor);
|
|
88
|
+
for (const reply of this.replies) {
|
|
89
|
+
if (reply.lastAt !== null)
|
|
90
|
+
newest = Math.max(newest ?? reply.lastAt, reply.lastAt);
|
|
91
|
+
}
|
|
92
|
+
return newest;
|
|
93
|
+
}
|
|
94
|
+
/** A reply got its first message, or its last message moved. */
|
|
95
|
+
moved() {
|
|
96
|
+
this.prune();
|
|
97
|
+
this.place();
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* The reply's end has landed: it is let go of once an owner message sits below it.
|
|
101
|
+
*/
|
|
102
|
+
ended(reply) {
|
|
103
|
+
if (!this.replies.has(reply))
|
|
104
|
+
return;
|
|
105
|
+
this.done.add(reply);
|
|
106
|
+
this.place();
|
|
107
|
+
this.release();
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* `reply` is about to create its first message, below every other: the list leaves the reply
|
|
111
|
+
* that shows it, and that reply's edit is written before the message is created. Created first,
|
|
112
|
+
* the message showed under the list for as long as the edit waited (seen on Slack desktop,
|
|
113
|
+
* 2026-10-15). Returns the call that ends the wait for the message, created or not. Not to be
|
|
114
|
+
* called with the places' lock held: the holder's write may need it.
|
|
115
|
+
*/
|
|
116
|
+
async opens(reply) {
|
|
117
|
+
this.opening.add(reply);
|
|
118
|
+
const before = this.holder;
|
|
119
|
+
this.place();
|
|
120
|
+
if (before !== null && before !== this.holder)
|
|
121
|
+
await before.unlist().catch(() => false);
|
|
122
|
+
return () => {
|
|
123
|
+
if (this.opening.delete(reply))
|
|
124
|
+
this.place();
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
/** What still runs in the thread changed; null for nothing. The holder is written at once. */
|
|
128
|
+
showRunning(list) {
|
|
129
|
+
this.list = list;
|
|
130
|
+
this.place();
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* The reply no longer shows the list and is not to: the close has nothing to settle on it. The
|
|
134
|
+
* holder stays, since the list may be handed to it again.
|
|
135
|
+
*/
|
|
136
|
+
unlisted(reply) {
|
|
137
|
+
if (reply !== this.holder)
|
|
138
|
+
this.listed.delete(reply);
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* A shutdown's last chance for the changes of the list that only debounced, on every reply that
|
|
142
|
+
* held it, let go of or not, since no session settles a reply whose end landed.
|
|
143
|
+
*/
|
|
144
|
+
async settleListed() {
|
|
145
|
+
const replies = [...this.listed];
|
|
146
|
+
this.listed.clear();
|
|
147
|
+
for (const reply of replies)
|
|
148
|
+
await reply.settle().catch(() => { });
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Work out every reply's tail with `tails` of the core and hand each its own. Sync: a reply
|
|
152
|
+
* whose tail did not change does nothing. Called whenever a reply's position or its resting
|
|
153
|
+
* changes. A reply that stops holding the list may be let go of from then on.
|
|
154
|
+
*/
|
|
155
|
+
place() {
|
|
156
|
+
const result = this.tailsOf();
|
|
157
|
+
let holder = null;
|
|
158
|
+
for (const reply of [...this.replies]) {
|
|
159
|
+
const list = result.get(reply)?.running ? this.list : null;
|
|
160
|
+
if (list !== null) {
|
|
161
|
+
holder = reply;
|
|
162
|
+
this.listed.add(reply);
|
|
163
|
+
}
|
|
164
|
+
reply.assign(list);
|
|
165
|
+
}
|
|
166
|
+
const previous = this.holder;
|
|
167
|
+
this.holder = holder;
|
|
168
|
+
if (previous !== null && previous !== holder)
|
|
169
|
+
this.release();
|
|
170
|
+
}
|
|
171
|
+
/** The tails of the registered replies that have a message. */
|
|
172
|
+
tailsOf() {
|
|
173
|
+
const entries = [];
|
|
174
|
+
for (const reply of this.replies) {
|
|
175
|
+
if (reply.lastAt !== null) {
|
|
176
|
+
entries.push({ key: reply, at: reply.lastAt, resting: reply.resting });
|
|
177
|
+
}
|
|
178
|
+
else if (this.opening.has(reply)) {
|
|
179
|
+
entries.push({ key: reply, at: Number.POSITIVE_INFINITY, resting: false });
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
return tails(entries);
|
|
183
|
+
}
|
|
184
|
+
/** The thread object that opened the reply closed: the reply is let go of, its end landed or not. */
|
|
185
|
+
closed(reply) {
|
|
186
|
+
if (!this.replies.has(reply))
|
|
187
|
+
return;
|
|
188
|
+
this.shut.add(reply);
|
|
189
|
+
this.release();
|
|
190
|
+
}
|
|
191
|
+
/** Whether nothing of the owner's and no other reply sits below the reply. */
|
|
192
|
+
last(reply) {
|
|
193
|
+
if (!this.replies.has(reply) || reply.lastAt === null)
|
|
194
|
+
return false;
|
|
195
|
+
return isLast(reply.lastAt, this.others(reply), this.marks);
|
|
196
|
+
}
|
|
197
|
+
/** Whether another reply has a message below the reply; a reply let go of keeps its answer. */
|
|
198
|
+
overtaken(reply) {
|
|
199
|
+
if (reply.lastAt === null)
|
|
200
|
+
return false;
|
|
201
|
+
return isOvertaken(reply.lastAt, this.others(reply));
|
|
202
|
+
}
|
|
203
|
+
others(reply) {
|
|
204
|
+
const at = this.floor === null ? [] : [this.floor];
|
|
205
|
+
for (const other of this.replies) {
|
|
206
|
+
if (other !== reply && other.lastAt !== null)
|
|
207
|
+
at.push(other.lastAt);
|
|
208
|
+
}
|
|
209
|
+
return at;
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Lets go of the replies a closed thread or an owner message seals (`sealed`). The holder of the
|
|
213
|
+
* list stays while it holds it, unless its thread closed.
|
|
214
|
+
*/
|
|
215
|
+
release() {
|
|
216
|
+
const top = this.marks.length === 0 ? null : Math.max(...this.marks);
|
|
217
|
+
let gone = false;
|
|
218
|
+
for (const reply of [...this.replies]) {
|
|
219
|
+
// A closed thread lets go of its replies whether or not their end landed: the session is
|
|
220
|
+
// gone, and nothing else would drop a reply whose end never lands.
|
|
221
|
+
if (!this.shut.has(reply) && !this.done.has(reply))
|
|
222
|
+
continue;
|
|
223
|
+
// The reply that holds the list stays while it does: the list could never be taken off a
|
|
224
|
+
// reply that is gone. A closed thread lets go of it all the same.
|
|
225
|
+
if (reply === this.holder && !this.shut.has(reply))
|
|
226
|
+
continue;
|
|
227
|
+
if (!this.sealed(reply, top))
|
|
228
|
+
continue;
|
|
229
|
+
const at = reply.lastAt;
|
|
230
|
+
if (at !== null)
|
|
231
|
+
this.floor = Math.max(this.floor ?? at, at);
|
|
232
|
+
this.done.delete(reply);
|
|
233
|
+
this.shut.delete(reply);
|
|
234
|
+
this.replies.delete(reply);
|
|
235
|
+
if (this.holder === reply)
|
|
236
|
+
this.holder = null;
|
|
237
|
+
gone = true;
|
|
238
|
+
}
|
|
239
|
+
if (gone && this.replies.size === 0)
|
|
240
|
+
this.onEmpty();
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Whether a reply is let go of: its thread closed, or an owner message sits below it. The
|
|
244
|
+
* holder of the list counts as still to end while it holds it (`release`). A reply with no
|
|
245
|
+
* message yet is let go of with its thread alone.
|
|
246
|
+
*/
|
|
247
|
+
sealed(reply, top) {
|
|
248
|
+
const at = reply.lastAt;
|
|
249
|
+
if (this.shut.has(reply) || at === null)
|
|
250
|
+
return true;
|
|
251
|
+
return top !== null && top > at;
|
|
252
|
+
}
|
|
253
|
+
/** Keeps the marks not below the lowest placed reply, and always the highest. */
|
|
254
|
+
prune() {
|
|
255
|
+
if (this.marks.length === 0)
|
|
256
|
+
return;
|
|
257
|
+
const top = Math.max(...this.marks);
|
|
258
|
+
const placed = [...this.replies].flatMap((reply) => reply.lastAt === null ? [] : [reply.lastAt]);
|
|
259
|
+
const lowest = Math.min(...placed);
|
|
260
|
+
this.marks = this.marks.filter((mark) => mark === top || mark >= lowest);
|
|
261
|
+
}
|
|
262
|
+
}
|