@astrosheep/square 0.3.11 → 0.3.13
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/codex-plugin/.codex-plugin/plugin.json +1 -1
- package/codex-plugin/hooks/hooks.json +9 -0
- package/dist/activity-feed.d.ts +14 -0
- package/dist/activity-feed.js +5 -5
- package/dist/activity.d.ts +9 -0
- package/dist/activity.js +112 -96
- package/dist/artifact.d.ts +20 -0
- package/dist/artifact.js +317 -648
- package/dist/automatic-session.d.ts +5 -0
- package/dist/automatic-session.js +86 -0
- package/dist/boundary-presentation.d.ts +5 -0
- package/dist/boundary-presentation.js +6 -5
- package/dist/claude-hook.d.ts +9 -0
- package/dist/claude-hook.js +35 -3
- package/dist/cli/context.d.ts +35 -0
- package/dist/cli/context.js +26 -31
- package/dist/cli/harness-command.d.ts +28 -0
- package/dist/cli/harness-command.js +30 -15
- package/dist/cli/maintenance-commands.d.ts +7 -0
- package/dist/cli/maintenance-commands.js +12 -69
- package/dist/cli/meta-commands.d.ts +5 -0
- package/dist/cli/observation-commands.d.ts +20 -0
- package/dist/cli/observation-commands.js +159 -139
- package/dist/cli/program.d.ts +2 -0
- package/dist/cli/program.js +3 -12
- package/dist/cli/registry.d.ts +9 -0
- package/dist/cli/registry.js +2 -4
- package/dist/cli/square-commands.d.ts +34 -0
- package/dist/cli/square-commands.js +90 -84
- package/dist/cmd/notify-once.d.ts +2 -0
- package/dist/codex-hook.d.ts +10 -0
- package/dist/codex-hook.js +35 -3
- package/dist/decisions.d.ts +92 -0
- package/dist/decisions.js +93 -81
- package/dist/delivery-health.d.ts +21 -0
- package/dist/delivery-health.js +41 -34
- package/dist/delivery.d.ts +81 -0
- package/dist/delivery.js +71 -69
- package/dist/file-lock.d.ts +6 -0
- package/dist/harness-claude.d.ts +19 -0
- package/dist/harness-claude.js +8 -3
- package/dist/harness-codex.d.ts +29 -0
- package/dist/harness-codex.js +2 -2
- package/dist/harness-links.d.ts +17 -0
- package/dist/harness-links.js +2 -2
- package/dist/harness-pi.d.ts +11 -0
- package/dist/harness-pi.js +2 -2
- package/dist/harness-stage.d.ts +6 -0
- package/dist/harness.d.ts +20 -0
- package/dist/harness.js +5 -3
- package/dist/help.d.ts +6 -0
- package/dist/help.js +12 -13
- package/dist/identity.d.ts +13 -0
- package/dist/inbox.d.ts +2 -0
- package/dist/inbox.js +15 -19
- package/dist/index.d.ts +13 -0
- package/dist/index.js +31 -67
- package/dist/landing.d.ts +10 -0
- package/dist/landing.js +95 -0
- package/dist/list.d.ts +1 -0
- package/dist/list.js +39 -61
- package/dist/model.d.ts +147 -0
- package/dist/model.js +12 -8
- package/dist/notifications.d.ts +30 -0
- package/dist/notifications.js +83 -91
- package/dist/open-square.d.ts +11 -0
- package/dist/open-square.js +4 -0
- package/dist/participant-identity.d.ts +1 -0
- package/dist/participant-identity.js +3 -0
- package/dist/paseo-connection.d.ts +15 -0
- package/dist/paseo-delivery.d.ts +14 -0
- package/dist/paseo-state.d.ts +11 -0
- package/dist/paseo-timeline.d.ts +16 -0
- package/dist/presence.d.ts +3 -0
- package/dist/presence.js +42 -0
- package/dist/presentation.d.ts +91 -0
- package/dist/presentation.js +52 -63
- package/dist/presented.d.ts +11 -0
- package/dist/registry.d.ts +58 -0
- package/dist/registry.js +36 -3
- package/dist/routes.d.ts +42 -0
- package/dist/runtime.d.ts +45 -0
- package/dist/runtime.js +48 -55
- package/dist/search.d.ts +11 -0
- package/dist/square-core.d.ts +111 -0
- package/dist/square-core.js +63 -9
- package/dist/square-facade.d.ts +86 -0
- package/dist/square-facade.js +1 -0
- package/dist/square-file-adapter.d.ts +18 -0
- package/dist/square-file-adapter.js +70 -0
- package/dist/square-storage.d.ts +20 -0
- package/dist/square-storage.js +171 -0
- package/dist/square-wiring.d.ts +19 -0
- package/dist/square-wiring.js +70 -0
- package/dist/square.d.ts +2 -0
- package/dist/state-cell.d.ts +14 -0
- package/dist/state-cell.js +1 -0
- package/dist/stream.d.ts +3 -0
- package/dist/stream.js +19 -23
- package/dist/time.d.ts +6 -0
- package/dist/views.d.ts +95 -0
- package/dist/views.js +81 -0
- package/dist/wake-attempts.d.ts +39 -0
- package/dist/wake-attempts.js +8 -4
- package/dist/wake-evidence.d.ts +12 -0
- package/dist/wake-evidence.js +7 -10
- package/dist/wake-port.d.ts +20 -0
- package/dist/wake-sink.d.ts +12 -0
- package/dist/wakes.d.ts +40 -0
- package/dist/wakes.js +62 -0
- package/dist/watch.d.ts +2 -0
- package/dist/watch.js +89 -210
- package/extensions/square-opencode.js +27 -1
- package/extensions/square-pi.js +13 -0
- package/guides/participant.md +7 -174
- package/package.json +5 -4
- package/skills/brainstorm/SKILL.md +30 -30
- package/skills/square/.claude-plugin/plugin.json +1 -1
- package/skills/square/SKILL.md +56 -29
- package/skills/square/hooks/hooks.json +9 -0
- package/skills/square-feedback/SKILL.md +9 -9
- package/dist/compact.js +0 -26
- package/dist/doctor.js +0 -36
- package/dist/square-application.js +0 -262
- package/template.md +0 -4
- package/templates/architect.md +0 -4
- package/templates/brainstorm.md +0 -4
|
@@ -1,21 +1,22 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { runCodexHook } from '../codex-hook.js';
|
|
4
|
-
import { coreActivities, coreParticipants, coreStatus } from '../decisions.js';
|
|
1
|
+
import { runClaudeHookAsync } from '../claude-hook.js';
|
|
2
|
+
import { runCodexHookAsync } from '../codex-hook.js';
|
|
5
3
|
import { sessionInbox } from '../inbox.js';
|
|
6
4
|
import { sweepPendingNotifications } from '../notifications.js';
|
|
7
5
|
import { cmdListSquares } from '../list.js';
|
|
8
|
-
import { sameName } from '../model.js';
|
|
9
|
-
import { commandPrefix, participantCommandPrefix,
|
|
10
|
-
import { actId,
|
|
6
|
+
import { parseActivityId, sameName } from '../model.js';
|
|
7
|
+
import { commandPrefix, participantCommandPrefix, participantIdentity, renderGrepActivitiesView, renderEventCli, renderAmbientEvent, withPathOutput, } from '../presentation.js';
|
|
8
|
+
import { actId, nowMs } from '../runtime.js';
|
|
11
9
|
import { cmdStream, cmdStreamNdjson } from '../stream.js';
|
|
12
10
|
import { formatRelativeTime, formatTimestamp, parseTimeOrRelative } from '../time.js';
|
|
13
11
|
import { cmdWatch } from '../watch.js';
|
|
12
|
+
import { openSquare } from '../square-file-adapter.js';
|
|
13
|
+
import { closeOpenSquare } from '../open-square.js';
|
|
14
|
+
import { historyPresentation, participantsPresentation, statusPresentation } from '../views.js';
|
|
14
15
|
import { fail, parseDurationMs, parseNameList, parseNonNegativeInteger, readStdinSync, requireParticipant, requireValue, usage, } from './context.js';
|
|
15
16
|
export const listCommand = {
|
|
16
17
|
parse: (argv) => argv,
|
|
17
|
-
execute(argv, context) {
|
|
18
|
-
cmdListSquares(argv, () => usage(context.command));
|
|
18
|
+
async execute(argv, context) {
|
|
19
|
+
await cmdListSquares(argv, () => usage(context.command));
|
|
19
20
|
},
|
|
20
21
|
present: () => { },
|
|
21
22
|
};
|
|
@@ -98,10 +99,10 @@ export const catchCommand = {
|
|
|
98
99
|
present: () => { },
|
|
99
100
|
};
|
|
100
101
|
function parseActRef(value, flag) {
|
|
101
|
-
const
|
|
102
|
-
if (
|
|
103
|
-
fail(`Invalid ${flag}: expected an activity id like
|
|
104
|
-
return
|
|
102
|
+
const index = parseActivityId(value);
|
|
103
|
+
if (index === undefined)
|
|
104
|
+
fail(`Invalid ${flag}: expected an activity id like act/12`);
|
|
105
|
+
return index;
|
|
105
106
|
}
|
|
106
107
|
function parseTimestamp(value, flag) {
|
|
107
108
|
const timestamp = parseTimeOrRelative(value, nowMs());
|
|
@@ -116,7 +117,7 @@ function parseHistory(argv, context) {
|
|
|
116
117
|
let before;
|
|
117
118
|
let after;
|
|
118
119
|
let afterIndex;
|
|
119
|
-
|
|
120
|
+
const atIndexes = [];
|
|
120
121
|
let beforeContext;
|
|
121
122
|
let afterContext;
|
|
122
123
|
let mention;
|
|
@@ -124,10 +125,8 @@ function parseHistory(argv, context) {
|
|
|
124
125
|
let full = false;
|
|
125
126
|
let grep;
|
|
126
127
|
let fixed;
|
|
127
|
-
let ids;
|
|
128
128
|
let order;
|
|
129
129
|
let format;
|
|
130
|
-
let countOnly = false;
|
|
131
130
|
let json = false;
|
|
132
131
|
const participants = [];
|
|
133
132
|
for (let index = 0; index < argv.length; index++) {
|
|
@@ -165,7 +164,10 @@ function parseHistory(argv, context) {
|
|
|
165
164
|
index += 1;
|
|
166
165
|
}
|
|
167
166
|
else if (flag === '--at') {
|
|
168
|
-
|
|
167
|
+
const values = requireValue(argv, index, flag).split(',');
|
|
168
|
+
if (values.some((value) => value === ''))
|
|
169
|
+
fail(`Invalid ${flag}: expected an activity id like act/12`);
|
|
170
|
+
atIndexes.push(...values.map((value) => parseActRef(value, flag)));
|
|
169
171
|
index += 1;
|
|
170
172
|
}
|
|
171
173
|
else if (flag === '-B') {
|
|
@@ -198,14 +200,6 @@ function parseHistory(argv, context) {
|
|
|
198
200
|
fixed = requireValue(argv, index, flag);
|
|
199
201
|
index += 1;
|
|
200
202
|
}
|
|
201
|
-
else if (flag === '--ids') {
|
|
202
|
-
ids = requireValue(argv, index, flag)
|
|
203
|
-
.split(',')
|
|
204
|
-
.map((item) => item.trim())
|
|
205
|
-
.filter(Boolean)
|
|
206
|
-
.map((item) => parseActRef(item, flag));
|
|
207
|
-
index += 1;
|
|
208
|
-
}
|
|
209
203
|
else if (flag === '--order') {
|
|
210
204
|
const value = requireValue(argv, index, flag);
|
|
211
205
|
if (value !== 'asc' && value !== 'desc')
|
|
@@ -217,8 +211,6 @@ function parseHistory(argv, context) {
|
|
|
217
211
|
format = requireValue(argv, index, flag).split(',').map((item) => item.trim()).filter(Boolean);
|
|
218
212
|
index += 1;
|
|
219
213
|
}
|
|
220
|
-
else if (flag === '--count')
|
|
221
|
-
countOnly = true;
|
|
222
214
|
else if (flag === '--json')
|
|
223
215
|
json = true;
|
|
224
216
|
else
|
|
@@ -230,7 +222,7 @@ function parseHistory(argv, context) {
|
|
|
230
222
|
fail('--grep and --fixed cannot be combined.');
|
|
231
223
|
if (grep === '' || fixed === '')
|
|
232
224
|
fail('--grep and --fixed require non-empty text.');
|
|
233
|
-
if (!lastNExplicit && (
|
|
225
|
+
if (!lastNExplicit && (atIndexes.length > 0 || pending))
|
|
234
226
|
lastN = null;
|
|
235
227
|
return {
|
|
236
228
|
lastN,
|
|
@@ -238,7 +230,7 @@ function parseHistory(argv, context) {
|
|
|
238
230
|
before,
|
|
239
231
|
after,
|
|
240
232
|
afterIndex,
|
|
241
|
-
|
|
233
|
+
atIndexes: atIndexes.length === 0 ? undefined : atIndexes,
|
|
242
234
|
beforeContext,
|
|
243
235
|
afterContext,
|
|
244
236
|
mention,
|
|
@@ -247,14 +239,12 @@ function parseHistory(argv, context) {
|
|
|
247
239
|
full,
|
|
248
240
|
grep,
|
|
249
241
|
fixed,
|
|
250
|
-
ids,
|
|
251
242
|
order,
|
|
252
243
|
format,
|
|
253
|
-
countOnly,
|
|
254
244
|
json,
|
|
255
245
|
};
|
|
256
246
|
}
|
|
257
|
-
function renderFields(
|
|
247
|
+
function renderFields(sayNumbers, item, fields) {
|
|
258
248
|
return fields.map((field) => {
|
|
259
249
|
switch (field) {
|
|
260
250
|
case 'id': return actId(item.index);
|
|
@@ -264,13 +254,13 @@ function renderFields(doc, item, fields) {
|
|
|
264
254
|
case 'at': return formatTimestamp(item.at);
|
|
265
255
|
case 'kind': return item.kind;
|
|
266
256
|
case 'body': return 'body' in item && typeof item.body === 'string' ? item.body.replace(/\s+/g, ' ').trim() : '';
|
|
267
|
-
case 'number': return item.kind === 'say' ? String(
|
|
257
|
+
case 'number': return item.kind === 'say' ? String(sayNumbers[item.index]) : '';
|
|
268
258
|
case 'reply': return item.kind === 'say' && item.reply !== undefined ? actId(item.reply) : '';
|
|
269
259
|
default: return '';
|
|
270
260
|
}
|
|
271
261
|
}).join('\t');
|
|
272
262
|
}
|
|
273
|
-
function jsonLine(
|
|
263
|
+
function jsonLine(sayNumbers, item) {
|
|
274
264
|
const act = item;
|
|
275
265
|
return JSON.stringify({
|
|
276
266
|
id: actId(item.index),
|
|
@@ -280,130 +270,160 @@ function jsonLine(doc, item) {
|
|
|
280
270
|
at: act.at,
|
|
281
271
|
ts: formatTimestamp(act.at),
|
|
282
272
|
body: 'body' in act && typeof act.body === 'string' ? act.body : '',
|
|
283
|
-
number: act.kind === 'say' ?
|
|
273
|
+
number: act.kind === 'say' ? sayNumbers[act.index] : null,
|
|
284
274
|
reach: act.kind === 'say' ? act.reach ?? null : null,
|
|
285
275
|
reply: act.kind === 'say' && act.reply !== undefined ? actId(act.reply) : null,
|
|
286
276
|
});
|
|
287
277
|
}
|
|
278
|
+
function renderHistoryProjection(projection, visible, full, squarePath, viewer, mode) {
|
|
279
|
+
const shown = visible.filter((activity) => activity.kind === 'say' || activity.kind === 'done');
|
|
280
|
+
const preview = full ? undefined : 200;
|
|
281
|
+
const chunks = [];
|
|
282
|
+
for (const activity of shown) {
|
|
283
|
+
const options = {
|
|
284
|
+
preview,
|
|
285
|
+
actNumber: activity.kind === 'say' ? projection.sayNumbers[activity.index] : undefined,
|
|
286
|
+
};
|
|
287
|
+
const rendered = mode === 'archive'
|
|
288
|
+
? renderEventCli(activity, options)
|
|
289
|
+
: renderAmbientEvent(activity, viewer, options);
|
|
290
|
+
if (rendered !== '')
|
|
291
|
+
chunks.push(rendered);
|
|
292
|
+
for (const name of projection.presenceAnchors[activity.index] ?? [])
|
|
293
|
+
chunks.push(`→ ${participantIdentity(name)} was here`);
|
|
294
|
+
}
|
|
295
|
+
if (chunks.length === 0)
|
|
296
|
+
return 'latest\n ○ no public activity in this view';
|
|
297
|
+
if (preview !== undefined && shown.some((activity) => activity.kind === 'say' && activity.body.length > preview && (mode === 'archive' || activity.perception === 'full'))) {
|
|
298
|
+
chunks.push(`» ${commandPrefix(squarePath)} history --full`);
|
|
299
|
+
}
|
|
300
|
+
return chunks.join('\n\n');
|
|
301
|
+
}
|
|
288
302
|
export const historyCommand = {
|
|
289
303
|
parse(argv, context) { return parseHistory(argv, context); },
|
|
290
|
-
execute(options, context) {
|
|
291
|
-
const
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
304
|
+
async execute(options, context) {
|
|
305
|
+
const square = await openSquare(context.squarePath, { clock: nowMs });
|
|
306
|
+
try {
|
|
307
|
+
const projection = await historyPresentation(square, options);
|
|
308
|
+
let events = [...projection.activities];
|
|
309
|
+
const searching = options.grep !== undefined || options.fixed !== undefined;
|
|
310
|
+
const totalMatches = searching ? events.length : 0;
|
|
311
|
+
if (options.lastN != null) {
|
|
312
|
+
events = options.order === 'desc'
|
|
313
|
+
? events.slice(0, options.lastN)
|
|
314
|
+
: events.slice(-options.lastN);
|
|
315
|
+
}
|
|
316
|
+
if (options.json)
|
|
317
|
+
return events.map((item) => jsonLine(projection.sayNumbers, item)).join('\n') + (events.length > 0 ? '\n' : '');
|
|
318
|
+
if (options.format !== undefined && options.format.length > 0) {
|
|
319
|
+
return events.map((item) => renderFields(projection.sayNumbers, item, options.format)).join('\n') + (events.length > 0 ? '\n' : '');
|
|
320
|
+
}
|
|
321
|
+
const pattern = options.grep ?? options.fixed;
|
|
322
|
+
const anonymous = options.viewer === undefined;
|
|
323
|
+
const archive = (options.atIndexes !== undefined && options.atIndexes.length > 0)
|
|
324
|
+
|| (options.lastN == null && options.full === true)
|
|
325
|
+
|| anonymous;
|
|
326
|
+
const output = pattern === undefined || pattern === ''
|
|
327
|
+
? renderHistoryProjection(projection, events, options.full === true || anonymous, context.squarePath, options.viewer ?? '', archive ? 'archive' : 'ambient')
|
|
328
|
+
: renderGrepActivitiesView(events, totalMatches, options.full, context.squarePath, pattern, options.fixed !== undefined);
|
|
329
|
+
return withPathOutput(context.squarePath, output, { participantCount: projection.participantCount });
|
|
299
330
|
}
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
if (options.json)
|
|
303
|
-
return events.map((item) => jsonLine(doc, item)).join('\n') + (events.length > 0 ? '\n' : '');
|
|
304
|
-
if (options.format !== undefined && options.format.length > 0) {
|
|
305
|
-
return events.map((item) => renderFields(doc, item, options.format)).join('\n') + (events.length > 0 ? '\n' : '');
|
|
331
|
+
finally {
|
|
332
|
+
await closeOpenSquare(square);
|
|
306
333
|
}
|
|
307
|
-
const pattern = options.grep ?? options.fixed;
|
|
308
|
-
const output = pattern === undefined || pattern === ''
|
|
309
|
-
? renderActivitiesView(doc, events, null, options.full, context.squarePath, options.viewer ?? '')
|
|
310
|
-
: renderGrepActivitiesView(events, totalMatches, options.full, context.squarePath, pattern, options.fixed !== undefined);
|
|
311
|
-
return withPathOutput(context.squarePath, output, { participantCount: inSquareCount(doc) });
|
|
312
|
-
},
|
|
313
|
-
present: (result) => process.stdout.write(result),
|
|
314
|
-
};
|
|
315
|
-
export const warmupCommand = {
|
|
316
|
-
parse(argv, context) { if (argv.length > 0)
|
|
317
|
-
usage(context.command); return undefined; },
|
|
318
|
-
execute(_intent, context) {
|
|
319
|
-
const doc = loadSquare(context.squarePath);
|
|
320
|
-
return withPathOutput(context.squarePath, doc.warmup.join('\n'), {
|
|
321
|
-
participantCount: inSquareCount(doc),
|
|
322
|
-
});
|
|
323
334
|
},
|
|
324
335
|
present: (result) => process.stdout.write(result),
|
|
325
336
|
};
|
|
326
337
|
export const participantsCommand = {
|
|
327
338
|
parse(argv, context) { if (argv.length > 0)
|
|
328
339
|
usage(context.command); return undefined; },
|
|
329
|
-
execute(_intent, context) {
|
|
330
|
-
const
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
const
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
340
|
+
async execute(_intent, context) {
|
|
341
|
+
const square = await openSquare(context.squarePath, { clock: nowMs });
|
|
342
|
+
try {
|
|
343
|
+
const now = nowMs();
|
|
344
|
+
const participants = await participantsPresentation(square);
|
|
345
|
+
const lines = participants.map((participant) => {
|
|
346
|
+
const glyph = participant.state === 'done' ? '○' : participant.presence === 'watching' ? '◎' : participant.activityCount > 0 ? '●' : '○';
|
|
347
|
+
const state = participant.state === 'done' ? 'done' : participant.presence === 'watching' ? 'catching' : participant.state;
|
|
348
|
+
const last = participant.lastActiveAt === undefined ? '—' : formatRelativeTime(participant.lastActiveAt, now);
|
|
349
|
+
return ` ${glyph} ${participantIdentity(participant.name)} · ${state} · ${participant.activityCount} ${participant.activityCount === 1 ? 'activity' : 'activities'} · ${last}`;
|
|
350
|
+
});
|
|
351
|
+
const participantCount = participants.filter((participant) => participant.state === 'active').length;
|
|
352
|
+
return withPathOutput(context.squarePath, ['participants', ...lines].join('\n'), {
|
|
353
|
+
participantCount,
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
finally {
|
|
357
|
+
await closeOpenSquare(square);
|
|
358
|
+
}
|
|
343
359
|
},
|
|
344
360
|
present: (result) => process.stdout.write(result),
|
|
345
361
|
};
|
|
346
362
|
export const statusCommand = {
|
|
347
363
|
parse(argv, context) { if (argv.length > 0)
|
|
348
364
|
usage(context.command); return undefined; },
|
|
349
|
-
execute(_intent, context) {
|
|
350
|
-
const
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
const
|
|
354
|
-
const
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
+
async execute(_intent, context) {
|
|
366
|
+
const square = await openSquare(context.squarePath, { clock: nowMs });
|
|
367
|
+
try {
|
|
368
|
+
const presentation = await statusPresentation(square);
|
|
369
|
+
const result = presentation.status;
|
|
370
|
+
const active = result.participants.filter((participant) => participant.state === 'active').sort((a, b) => {
|
|
371
|
+
const aViewer = context.name !== undefined && sameName(a.name, context.name);
|
|
372
|
+
const bViewer = context.name !== undefined && sameName(b.name, context.name);
|
|
373
|
+
if (aViewer !== bViewer)
|
|
374
|
+
return aViewer ? -1 : 1;
|
|
375
|
+
return (b.lastActiveAt ?? -Infinity) - (a.lastActiveAt ?? -Infinity) || a.name.localeCompare(b.name);
|
|
376
|
+
});
|
|
377
|
+
const people = active.length === 0 ? [' ○ nobody in the square'] : active.map((participant) => {
|
|
378
|
+
const glyph = participant.presence === 'watching'
|
|
379
|
+
? '◎'
|
|
380
|
+
: participant.activityCount > 0 ? '●' : '○';
|
|
381
|
+
const summary = participant.activityCount > 0
|
|
382
|
+
? `${participant.activityCount} ${participant.activityCount === 1 ? 'activity' : 'activities'} · ${participant.lastActiveAt === undefined
|
|
383
|
+
? 'just now'
|
|
384
|
+
: formatRelativeTime(participant.lastActiveAt, result.now)}`
|
|
385
|
+
: `quiet · ${participant.lastActiveAt === undefined ? '—' : formatRelativeTime(participant.lastActiveAt, result.now)}`;
|
|
386
|
+
const showAttention = context.name === undefined || sameName(participant.name, context.name);
|
|
387
|
+
const attention = !showAttention
|
|
388
|
+
? ''
|
|
389
|
+
: participant.pendingMentionCount > 0
|
|
390
|
+
? `${participant.pendingMentionCount} mention${participant.pendingMentionCount === 1 ? '' : 's'} waiting`
|
|
391
|
+
: participant.unreadActivityCount > 0
|
|
392
|
+
? `${participant.unreadActivityCount} change${participant.unreadActivityCount === 1 ? '' : 's'} waiting`
|
|
393
|
+
: 'caught up';
|
|
394
|
+
return ` ${glyph} ${participantIdentity(participant.name)} · ${summary}${attention === '' ? '' : ` · ${attention}`}`;
|
|
395
|
+
});
|
|
396
|
+
const cap = result.hardCap === null ? 'unlimited' : String(result.hardCap);
|
|
397
|
+
const hold = result.holdActive
|
|
398
|
+
? `· ${result.holdActor === undefined ? 'someone' : participantIdentity(result.holdActor)} raised a hand${result.holdReason ? ` — ${result.holdReason}` : ''} · ${result.holdAt === undefined
|
|
365
399
|
? 'just now'
|
|
366
|
-
: formatRelativeTime(
|
|
367
|
-
:
|
|
368
|
-
const
|
|
369
|
-
const attention = !showAttention
|
|
400
|
+
: formatRelativeTime(result.holdAt, result.now)}`
|
|
401
|
+
: undefined;
|
|
402
|
+
const visible = result.latestAct === undefined
|
|
370
403
|
? ''
|
|
371
|
-
:
|
|
372
|
-
|
|
373
|
-
:
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
:
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
const latest = visible === ''
|
|
394
|
-
? [result.latestAct === undefined
|
|
395
|
-
? ' ○ no public activity yet'
|
|
396
|
-
: ' · latest activity is private to another participant']
|
|
397
|
-
: [` ${visible.replace(/\n/g, '\n ')}`];
|
|
398
|
-
if (visible.includes('more chars') && result.latestAct !== undefined) {
|
|
399
|
-
const prefix = context.name === undefined ? commandPrefix(context.squarePath) : participantCommandPrefix(context.squarePath, context.name);
|
|
400
|
-
latest.push(`» ${prefix} history --at ${actId(result.latestAct)} -C 2 --full`);
|
|
404
|
+
: renderAmbientEvent(result.latestAct, context.name ?? '', {
|
|
405
|
+
now: result.now,
|
|
406
|
+
preview: 200,
|
|
407
|
+
actNumber: presentation.latestActNumber,
|
|
408
|
+
});
|
|
409
|
+
const latest = visible === ''
|
|
410
|
+
? [result.latestAct === undefined
|
|
411
|
+
? ' ○ no public activity yet'
|
|
412
|
+
: ' · latest activity is private to another participant']
|
|
413
|
+
: [` ${visible.replace(/\n/g, '\n ')}`];
|
|
414
|
+
if (visible.includes('more chars') && result.latestAct !== undefined) {
|
|
415
|
+
const prefix = context.name === undefined ? commandPrefix(context.squarePath) : participantCommandPrefix(context.squarePath, context.name);
|
|
416
|
+
latest.push(`» ${prefix} history --at ${actId(result.latestAct)} -C 2 --full`);
|
|
417
|
+
}
|
|
418
|
+
const output = [
|
|
419
|
+
`${result.activeCount} active · ${result.doneCount} done · cap ${cap} · throttle ${result.throttlePerMinute === undefined ? 'none' : `${result.throttlePerMinute}/min`}`,
|
|
420
|
+
...(hold === undefined ? [] : ['', hold]), '', 'around the square', ...people, '', 'latest', ...latest,
|
|
421
|
+
].join('\n');
|
|
422
|
+
return withPathOutput(context.squarePath, output, { participantCount: result.activeCount, held: result.holdActive });
|
|
423
|
+
}
|
|
424
|
+
finally {
|
|
425
|
+
await closeOpenSquare(square);
|
|
401
426
|
}
|
|
402
|
-
const output = [
|
|
403
|
-
`${result.activeCount} active · ${result.doneCount} done · cap ${cap} · throttle ${result.throttlePerMinute === undefined ? 'none' : `${result.throttlePerMinute}/min`}`,
|
|
404
|
-
...(hold === undefined ? [] : ['', hold]), '', 'around the square', ...people, '', 'latest', ...latest,
|
|
405
|
-
].join('\n');
|
|
406
|
-
return withPathOutput(context.squarePath, output, { participantCount: result.activeCount, held: result.holdActive });
|
|
407
427
|
},
|
|
408
428
|
present: (result) => process.stdout.write(result),
|
|
409
429
|
};
|
|
@@ -425,8 +445,8 @@ export const inboxCommand = {
|
|
|
425
445
|
fail('inbox requires --for-session <session-id>.');
|
|
426
446
|
return { sessionId, json };
|
|
427
447
|
},
|
|
428
|
-
execute(intent) {
|
|
429
|
-
const inbox = sessionInbox(intent.sessionId);
|
|
448
|
+
async execute(intent) {
|
|
449
|
+
const inbox = await sessionInbox(intent.sessionId);
|
|
430
450
|
return intent.json ? `${JSON.stringify(inbox)}\n` : inbox.map((membership) => `${membership.name}\t${membership.squarePath}\t${membership.notifications.length}\n`).join('');
|
|
431
451
|
},
|
|
432
452
|
present: (result) => process.stdout.write(result),
|
|
@@ -439,5 +459,5 @@ function hookCommand(runHook) {
|
|
|
439
459
|
present: (result) => process.stdout.write(result),
|
|
440
460
|
};
|
|
441
461
|
}
|
|
442
|
-
export const claudeHookCommand = hookCommand(
|
|
443
|
-
export const codexHookCommand = hookCommand(
|
|
462
|
+
export const claudeHookCommand = hookCommand(runClaudeHookAsync);
|
|
463
|
+
export const codexHookCommand = hookCommand(runCodexHookAsync);
|
package/dist/cli/program.js
CHANGED
|
@@ -1,14 +1,9 @@
|
|
|
1
1
|
import { helpRequest } from '../help.js';
|
|
2
|
-
import {
|
|
2
|
+
import { isSquareError } from '../model.js';
|
|
3
3
|
import { defaultContext, parseGlobalArgs } from './context.js';
|
|
4
4
|
import { executeRegisteredCommand, findCommand } from './registry.js';
|
|
5
|
-
function isMutatingCommand(command, argv) {
|
|
6
|
-
if (['build', 'join', 'catch', 'express', 'done', 'hold', 'resume', 'compact'].includes(command))
|
|
7
|
-
return true;
|
|
8
|
-
return command === 'doctor' && argv.includes('--fix');
|
|
9
|
-
}
|
|
10
5
|
function handleSquareError(error) {
|
|
11
|
-
if (error
|
|
6
|
+
if (isSquareError(error)) {
|
|
12
7
|
process.stderr.write(`${error.message}\n`);
|
|
13
8
|
process.exit(error.code === 'not_found' ? 1 : 2);
|
|
14
9
|
}
|
|
@@ -19,7 +14,7 @@ export async function runCli(rawArgs = process.argv.slice(2)) {
|
|
|
19
14
|
try {
|
|
20
15
|
const requestedHelp = helpRequest(rawArgs);
|
|
21
16
|
if (requestedHelp !== undefined) {
|
|
22
|
-
await executeRegisteredCommand('help', requestedHelp.command === undefined ? [] : [requestedHelp.command], defaultContext('help', '.square/SQUARE.
|
|
17
|
+
await executeRegisteredCommand('help', requestedHelp.command === undefined ? [] : [requestedHelp.command], defaultContext('help', '.square/SQUARE.square'));
|
|
23
18
|
return;
|
|
24
19
|
}
|
|
25
20
|
const parsed = parseGlobalArgs(rawArgs);
|
|
@@ -32,10 +27,6 @@ export async function runCli(rawArgs = process.argv.slice(2)) {
|
|
|
32
27
|
process.stderr.write(`unknown command: ${command}\nrun 'square' for usage\n`);
|
|
33
28
|
process.exit(2);
|
|
34
29
|
}
|
|
35
|
-
if (!parsed.explicitSquarePath && parsed.multipleSquares && isMutatingCommand(command, parsed.args.slice(1))) {
|
|
36
|
-
process.stderr.write('✕ more than one square is active here; choose the path before changing or consuming activity.\n» square list\n');
|
|
37
|
-
process.exit(2);
|
|
38
|
-
}
|
|
39
30
|
await executeRegisteredCommand(command, parsed.args.slice(1), defaultContext(command, parsed.squarePath, parsed.name));
|
|
40
31
|
}
|
|
41
32
|
catch (error) {
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type CommandContext, type CommandSpec } from './context.js';
|
|
2
|
+
export interface RegisteredCommand {
|
|
3
|
+
names: readonly string[];
|
|
4
|
+
spec: CommandSpec<any, any>;
|
|
5
|
+
}
|
|
6
|
+
/** Every public command is an executable adapter, including aliases and utility commands. */
|
|
7
|
+
export declare const commandRegistry: readonly RegisteredCommand[];
|
|
8
|
+
export declare function findCommand(name: string): RegisteredCommand | undefined;
|
|
9
|
+
export declare function executeRegisteredCommand(name: string, argv: string[], context: CommandContext): Promise<void>;
|
package/dist/cli/registry.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { buildCommand,
|
|
1
|
+
import { buildCommand, doneCommand, expressCommand, holdCommand, joinCommand, resumeCommand } from './square-commands.js';
|
|
2
2
|
import { doctorCommand } from './maintenance-commands.js';
|
|
3
3
|
import { harnessCommand, installCommand, uninstallCommand } from './harness-command.js';
|
|
4
4
|
import { helpCommand, versionCommand } from './meta-commands.js';
|
|
5
|
-
import { catchCommand, claudeHookCommand, codexHookCommand, historyCommand, inboxCommand, listCommand, participantsCommand, statusCommand, streamCommand,
|
|
5
|
+
import { catchCommand, claudeHookCommand, codexHookCommand, historyCommand, inboxCommand, listCommand, participantsCommand, statusCommand, streamCommand, } from './observation-commands.js';
|
|
6
6
|
/** Every public command is an executable adapter, including aliases and utility commands. */
|
|
7
7
|
export const commandRegistry = [
|
|
8
8
|
{ names: ['build'], spec: buildCommand },
|
|
@@ -20,10 +20,8 @@ export const commandRegistry = [
|
|
|
20
20
|
{ names: ['install'], spec: installCommand },
|
|
21
21
|
{ names: ['uninstall'], spec: uninstallCommand },
|
|
22
22
|
{ names: ['harness'], spec: harnessCommand },
|
|
23
|
-
{ names: ['compact'], spec: compactCommand },
|
|
24
23
|
{ names: ['doctor'], spec: doctorCommand },
|
|
25
24
|
{ names: ['history'], spec: historyCommand },
|
|
26
|
-
{ names: ['warmup'], spec: warmupCommand },
|
|
27
25
|
{ names: ['status'], spec: statusCommand },
|
|
28
26
|
{ names: ['participants'], spec: participantsCommand },
|
|
29
27
|
{ names: ['help'], spec: helpCommand },
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { type BuildOptions, type HardCap, type Reach } from '../model.js';
|
|
2
|
+
import { type CommandSpec } from './context.js';
|
|
3
|
+
interface BuildIntent {
|
|
4
|
+
options: BuildOptions & {
|
|
5
|
+
hardCap: HardCap;
|
|
6
|
+
};
|
|
7
|
+
snippet: string;
|
|
8
|
+
}
|
|
9
|
+
interface JoinIntent {
|
|
10
|
+
name: string;
|
|
11
|
+
lastN: number | null;
|
|
12
|
+
kick: boolean;
|
|
13
|
+
}
|
|
14
|
+
interface ActivityIntent {
|
|
15
|
+
name: string;
|
|
16
|
+
activity: string;
|
|
17
|
+
force: boolean;
|
|
18
|
+
noWait: boolean;
|
|
19
|
+
reach?: Reach;
|
|
20
|
+
reply?: number;
|
|
21
|
+
}
|
|
22
|
+
interface BodyIntent {
|
|
23
|
+
name: string;
|
|
24
|
+
body?: string;
|
|
25
|
+
}
|
|
26
|
+
export declare const buildCommand: CommandSpec<BuildIntent, string>;
|
|
27
|
+
export declare const joinCommand: CommandSpec<JoinIntent, string>;
|
|
28
|
+
export declare const expressCommand: CommandSpec<ActivityIntent>;
|
|
29
|
+
export declare const doneCommand: CommandSpec<BodyIntent, string>;
|
|
30
|
+
export declare const holdCommand: CommandSpec<BodyIntent, string>;
|
|
31
|
+
export declare const resumeCommand: CommandSpec<{
|
|
32
|
+
name: string;
|
|
33
|
+
}, string>;
|
|
34
|
+
export {};
|