@astrosheep/square 0.3.82 → 0.3.84
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/dist/claude-delivery-status.d.ts +7 -0
- package/dist/claude-delivery-status.js +24 -0
- package/dist/claude-delivery.js +9 -15
- package/dist/claude-mod.js +5 -0
- package/dist/cli/catch-presentation.d.ts +2 -6
- package/dist/cli/catch-presentation.js +2 -50
- package/dist/cli/express-presentation.d.ts +2 -2
- package/dist/cli/express-presentation.js +6 -29
- package/dist/cli/observation-commands.js +10 -142
- package/dist/cli/program.js +5 -28
- package/dist/cli/square-commands.js +14 -56
- package/dist/delivery-health.d.ts +2 -2
- package/dist/delivery-health.js +20 -2
- package/dist/harness-pi.js +26 -2
- package/dist/host-ledger-file-adapter.d.ts +3 -0
- package/dist/host-ledger-file-adapter.js +12 -0
- package/dist/host-ledger.d.ts +12 -0
- package/dist/mcp.js +17 -6
- package/dist/operation-presentation.d.ts +45 -0
- package/dist/operation-presentation.js +370 -0
- package/dist/packages/agent-delivery/src/claude-native.js +3 -1
- package/dist/routes.js +7 -2
- package/dist/square-tools.d.ts +14 -2
- package/dist/square-tools.js +36 -17
- package/dist/wake-evidence.d.ts +2 -1
- package/dist/wake-evidence.js +2 -1
- package/guides/catch-cold-path-optimization.md +1 -1
- package/guides/claude-native.md +32 -0
- package/package.json +1 -1
- package/plugins/claude/.claude-plugin/plugin.json +1 -1
- package/plugins/codex/.codex-plugin/plugin.json +1 -1
- package/plugins/paseo/OVERVIEW.md +7 -4
- package/plugins/paseo/README.md +30 -6
- package/plugins/paseo/index.server.ts +10 -0
- package/plugins/paseo/package.json +3 -3
- package/plugins/paseo/paseo-plugin.json +1 -1
- package/plugins/paseo/server/record-delivery.ts +28 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { NativeDeliveryObservation } from './host-ledger.js';
|
|
2
|
+
export interface ClaudeDeliveryStatus extends NativeDeliveryObservation {
|
|
3
|
+
readonly provider: 'claude';
|
|
4
|
+
readonly sessionId: string;
|
|
5
|
+
}
|
|
6
|
+
/** This receiver-owned observation is not a model tool and grants no delivery authority. */
|
|
7
|
+
export declare function recordClaudeDeliveryStatus(input: ClaudeDeliveryStatus, env?: NodeJS.ProcessEnv): Promise<boolean>;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { hostLedgerForEnv } from './registry.js';
|
|
2
|
+
const holdReasons = new Set(['explicit-setting', 'managed-setting', 'repo-setting', 'invalid-setting', 'bypass-default', 'mode-unknown', 'mode-mismatch', 'no-mode-asserted']);
|
|
3
|
+
const dropReasons = new Set(['expired', 'refused', 'dropped', 'discarded']);
|
|
4
|
+
const uuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
5
|
+
/** This receiver-owned observation is not a model tool and grants no delivery authority. */
|
|
6
|
+
export async function recordClaudeDeliveryStatus(input, env = process.env) {
|
|
7
|
+
if (!input || input.provider !== 'claude' || typeof input.sessionId !== 'string' || !input.sessionId
|
|
8
|
+
|| typeof input.messageId !== 'string' || !uuid.test(input.messageId)
|
|
9
|
+
|| typeof input.eventId !== 'string' || !uuid.test(input.eventId)
|
|
10
|
+
|| !Number.isFinite(input.observedAt) || input.observedAt < 0
|
|
11
|
+
|| !['held', 'released', 'dropped'].includes(input.state)
|
|
12
|
+
|| (input.state === 'held' ? !holdReasons.has(input.reason ?? '')
|
|
13
|
+
: input.state === 'dropped' ? !dropReasons.has(input.reason ?? '') : input.reason !== undefined))
|
|
14
|
+
return false;
|
|
15
|
+
const ledger = hostLedgerForEnv(env);
|
|
16
|
+
const rows = await ledger.listEvidence({ kind: 'wake', session: input.sessionId, includeReleased: true });
|
|
17
|
+
const row = rows.find((row) => row.nativeDelivery?.harness === 'claude' && row.nativeDelivery.messageId === input.messageId);
|
|
18
|
+
if (!row?.claimToken)
|
|
19
|
+
return false;
|
|
20
|
+
const { eventId, messageId, state, reason, observedAt } = input;
|
|
21
|
+
return ledger.observeNativeDelivery({ ...row, claimToken: row.claimToken }, {
|
|
22
|
+
eventId, messageId, state, ...(reason === undefined ? {} : { reason }), observedAt,
|
|
23
|
+
});
|
|
24
|
+
}
|
package/dist/claude-delivery.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { stat } from 'node:fs/promises';
|
|
2
|
+
import { randomUUID } from 'node:crypto';
|
|
2
3
|
import { openSquare } from './open-square.js';
|
|
3
4
|
import { closeOpenSquare } from './open-square.js';
|
|
4
5
|
import { hostLedgerForEnv } from './registry.js';
|
|
@@ -7,7 +8,7 @@ import { nativePendingPreview } from './inbox.js';
|
|
|
7
8
|
import { presentPending } from './presentation-operations.js';
|
|
8
9
|
import { canonicalPath } from './canonical-path.js';
|
|
9
10
|
import { parseActivityId } from './square-core.js';
|
|
10
|
-
import {
|
|
11
|
+
import { writeClaudeNative } from './packages/agent-delivery/src/claude-native.js';
|
|
11
12
|
const marker = /(?:^|\n)\[square-inbox:([a-zA-Z0-9-]+)\](?:\n|$)/g;
|
|
12
13
|
export function nativeTokens(text) { return [...text.matchAll(marker)].map((match) => match[1]); }
|
|
13
14
|
export function nativePayload(token, preview) { return `[square-inbox:${token}]\n${preview}\n[/square-inbox:${token}]`; }
|
|
@@ -17,18 +18,11 @@ function nativeSupported(route) { return route.address.loaded === 'true' && !!ro
|
|
|
17
18
|
* owns the payload, the correlation and the evidence. A local write is never proof
|
|
18
19
|
* of native admission.
|
|
19
20
|
*/
|
|
20
|
-
async function writeClaudeWake(sessionId, endpoint, payload, timeoutMs, signal) {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
}
|
|
26
|
-
catch (error) {
|
|
27
|
-
if (error instanceof DeliveryError && !error.maybeDelivered) {
|
|
28
|
-
return { outcome: 'failed', unavailable: true, retainRoute: true, signature: 'claude_endpoint_unavailable', message: error.message };
|
|
29
|
-
}
|
|
30
|
-
return { outcome: 'unknown', signature: 'native_admission_unconfirmed', message: error instanceof Error ? error.message : String(error) };
|
|
31
|
-
}
|
|
21
|
+
async function writeClaudeWake(sessionId, endpoint, messageId, payload, timeoutMs, signal) {
|
|
22
|
+
const result = await writeClaudeNative({ sessionId, endpoint, messageId }, payload, { deadline: Date.now() + timeoutMs, signal });
|
|
23
|
+
if (result.outcome === 'unavailable')
|
|
24
|
+
return { outcome: 'failed', unavailable: true, retainRoute: true, signature: 'claude_endpoint_unavailable', message: result.message };
|
|
25
|
+
return { outcome: 'unknown', signature: 'native_admission_unconfirmed', message: result.outcome === 'written' ? 'Claude accepted the local write; native admission is unconfirmed.' : result.message };
|
|
32
26
|
}
|
|
33
27
|
export function createClaudeWakeTransport(hostLedger, env = process.env) {
|
|
34
28
|
return {
|
|
@@ -92,13 +86,13 @@ async function dispatchClaude(request, hostLedger, timeoutMs, beforeSend, env =
|
|
|
92
86
|
}
|
|
93
87
|
if (!await (beforeSend?.() ?? Promise.resolve(true)))
|
|
94
88
|
return { outcome: 'not-capable', diagnostic: 'Native activity was consumed before send.' };
|
|
95
|
-
const native = { harness: 'claude', payload, epoch: owner.epoch ?? 0, endpoint: request.route.address.endpoint };
|
|
89
|
+
const native = { harness: 'claude', payload, epoch: owner.epoch ?? 0, endpoint: request.route.address.endpoint, messageId: randomUUID() };
|
|
96
90
|
const row = { location: request.location, participant: request.participant, session: request.route.sessionId, activity: request.activity, kind: 'wake', outcome: 'dispatching', routeKind: 'claude-native', attemptN: request.attemptN, claimToken: request.claimToken, nativeDelivery: native };
|
|
97
91
|
if (!await currentDelivery(row, hostLedger) || !await hostLedger.prepareNativeWake(row))
|
|
98
92
|
return { outcome: 'not-capable', diagnostic: 'Native delivery is no longer current.' };
|
|
99
93
|
if (!await (beforeSend?.() ?? Promise.resolve(true)) || !await currentDelivery(row, hostLedger))
|
|
100
94
|
return { outcome: 'not-capable', diagnostic: 'Catch, cancellation or consumption won before native write.' };
|
|
101
|
-
return writeClaudeWake(row.session, native.endpoint, payload, timeoutMs, signal);
|
|
95
|
+
return writeClaudeWake(row.session, native.endpoint, native.messageId, payload, timeoutMs, signal);
|
|
102
96
|
}, signal);
|
|
103
97
|
}
|
|
104
98
|
/** Retired tokens veto a frame; only live correlations and bound memberships confer authority. */
|
package/dist/claude-mod.js
CHANGED
|
@@ -8,6 +8,7 @@ import { observeClaudeDelivery } from './claude-delivery.js';
|
|
|
8
8
|
import { processActNotificationsOnce } from './notifications.js';
|
|
9
9
|
import { sweepPending } from './delivery-operations.js';
|
|
10
10
|
import { beginClaudeMcpCall, endClaudeMcpCall } from './claude-mcp-context.js';
|
|
11
|
+
import { recordClaudeDeliveryStatus } from './claude-delivery-status.js';
|
|
11
12
|
/** JSON stdin bridge. Identity is explicit per operation; process.env is never rewritten. */
|
|
12
13
|
export async function runClaudeMod(inputText, env = process.env) {
|
|
13
14
|
if (inputText.length > 512_000)
|
|
@@ -15,6 +16,10 @@ export async function runClaudeMod(inputText, env = process.env) {
|
|
|
15
16
|
const input = JSON.parse(inputText);
|
|
16
17
|
if (!input || typeof input.sessionId !== 'string' || !input.sessionId || typeof input.cwd !== 'string')
|
|
17
18
|
throw new Error('Claude bridge coordinate missing.');
|
|
19
|
+
if (input.operation === 'status') {
|
|
20
|
+
const recorded = input.status?.sessionId === input.sessionId && await recordClaudeDeliveryStatus(input.status, env);
|
|
21
|
+
return `${JSON.stringify({ recorded })}\n`;
|
|
22
|
+
}
|
|
18
23
|
if (input.operation === 'tool-begin') {
|
|
19
24
|
return `${JSON.stringify(await beginClaudeMcpCall({ toolUseId: input.toolUseId, sessionId: input.sessionId, cwd: input.cwd, agentId: input.agentId }, env))}\n`;
|
|
20
25
|
}
|
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { OperationProgress } from '../square-facade.js';
|
|
2
|
+
export { renderCatchOutcome } from '../operation-presentation.js';
|
|
2
3
|
export declare function renderCatchProgress(squarePath: string, progress: OperationProgress): string | undefined;
|
|
3
|
-
/** Render settled catch facts; no selection, terminal decisions, receipts or wait machinery. */
|
|
4
|
-
export declare function renderCatchOutcome(squarePath: string, data: CatchResult, options?: CatchOptions): {
|
|
5
|
-
stdout: string;
|
|
6
|
-
exitCode: number;
|
|
7
|
-
};
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
import { style } from '../tty-style.js';
|
|
1
|
+
import { renderWatchForceTakeover, renderWatchReplaceMissing } from '../presentation.js';
|
|
2
|
+
export { renderCatchOutcome } from '../operation-presentation.js';
|
|
4
3
|
export function renderCatchProgress(squarePath, progress) {
|
|
5
4
|
if (progress.kind !== 'catch-started' || !progress.replacementRequested)
|
|
6
5
|
return undefined;
|
|
@@ -8,50 +7,3 @@ export function renderCatchProgress(squarePath, progress) {
|
|
|
8
7
|
return (progress.replaced
|
|
9
8
|
? renderWatchForceTakeover(options) : renderWatchReplaceMissing(options)) + '\n';
|
|
10
9
|
}
|
|
11
|
-
function continuationCommand(squarePath, name, options) {
|
|
12
|
-
const args = ['--now'];
|
|
13
|
-
if (options.from?.length)
|
|
14
|
-
args.push('--from', options.from.join(','));
|
|
15
|
-
if (options.mention)
|
|
16
|
-
args.push('--mention');
|
|
17
|
-
if (options.limit !== undefined)
|
|
18
|
-
args.push('--limit', String(options.limit));
|
|
19
|
-
return `${participantCommandPrefix(squarePath, name)} catch ${args.join(' ')}`;
|
|
20
|
-
}
|
|
21
|
-
/** Render settled catch facts; no selection, terminal decisions, receipts or wait machinery. */
|
|
22
|
-
export function renderCatchOutcome(squarePath, data, options = {}) {
|
|
23
|
-
const projection = data.observation;
|
|
24
|
-
const location = projection.location ?? squarePath;
|
|
25
|
-
const name = projection.participant;
|
|
26
|
-
const stop = projection.stop ?? data.status;
|
|
27
|
-
const header = { participantCount: projection.standingCount, held: projection.held };
|
|
28
|
-
const statusOptions = {
|
|
29
|
-
squarePath: location, name, presence: projection.presence,
|
|
30
|
-
showCatchHint: !projection.automaticDeliveryAvailable,
|
|
31
|
-
ownActivityCount: projection.ownActivityCount, hardCap: projection.hardCap,
|
|
32
|
-
};
|
|
33
|
-
if (stop === 'already-active' || stop === 'replaced') {
|
|
34
|
-
return {
|
|
35
|
-
stdout: withPathOutput(location, stop === 'already-active'
|
|
36
|
-
? renderWatchAlreadyActive(statusOptions) : renderWatchReplaced(statusOptions), header),
|
|
37
|
-
exitCode: stop === 'already-active' ? 1 : 0,
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
const rendered = data.activities.map((activity) => renderAmbientEvent(activity, name, {
|
|
41
|
-
now: projection.now, actNumber: projection.sayNumbers[parseActivityId(activity.id)],
|
|
42
|
-
perception: activity.perception, mention: options.mention ? name : undefined,
|
|
43
|
-
})).filter(Boolean).join('\n\n');
|
|
44
|
-
const remaining = data.remaining === 0 ? ''
|
|
45
|
-
: `○ ${data.remaining} matching ${data.remaining === 1 ? 'activity remains' : 'activities remain'}\n${continuationCommand(location, name, options)}`;
|
|
46
|
-
const terminal = stop === undefined ? '' : renderWatchStatus({
|
|
47
|
-
...statusOptions, status: stop,
|
|
48
|
-
...(stop === 'stale' && options.idle !== undefined ? { idleMs: options.idle } : {}),
|
|
49
|
-
});
|
|
50
|
-
const fallback = stop === undefined && !projection.automaticDeliveryAvailable && data.remaining === 0
|
|
51
|
-
? `${participantCommandPrefix(location, name)} catch --idle 30m\n stay available for new activity` : '';
|
|
52
|
-
const hint = data.hint === undefined ? '' : style('dim', `· ${data.hint}`);
|
|
53
|
-
return {
|
|
54
|
-
stdout: withPathOutput(location, [terminal, rendered, hint, remaining, fallback].filter(Boolean).join('\n\n'), header),
|
|
55
|
-
exitCode: stop === 'capped' ? 1 : 0,
|
|
56
|
-
};
|
|
57
|
-
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { type Square } from '../square-api.js';
|
|
2
|
-
import type { OperationControl,
|
|
2
|
+
import type { OperationControl, ExpressOptions } from '../square-facade.js';
|
|
3
|
+
export { renderExpression } from '../operation-presentation.js';
|
|
3
4
|
export interface ActivityOptions extends Omit<ExpressOptions, 'reply'> {
|
|
4
5
|
readonly reply?: string;
|
|
5
6
|
}
|
|
6
7
|
export declare function saveActivityDraft(squarePath: string, name: string, body: string, now?: number): string;
|
|
7
8
|
/** Retry choices are transport syntax, never a second admission decision. */
|
|
8
9
|
export declare function activityRetryCommand(squarePath: string, name: string, opts: ActivityOptions, force?: boolean): string;
|
|
9
|
-
export declare function renderExpression(squarePath: string, data: ExpressResult): string;
|
|
10
10
|
/** Body adaptation, terminal IO and drafts only; Participant owns every attempt and wait. */
|
|
11
11
|
export declare function executeExpression(open: (control?: OperationControl) => Promise<Square>, squarePath: string, requestedName: string | undefined, rawInput: string, opts: ActivityOptions): Promise<void>;
|
|
@@ -3,9 +3,10 @@ import fs from 'node:fs';
|
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { isSquareError } from '../model.js';
|
|
5
5
|
import { formatActivityId, parseActivityId } from '../square-api.js';
|
|
6
|
-
import { formatRefusal, refusalText, renderActivityBlocked, renderActivityLimit, renderActivityUncertain, renderExpressNoWait, renderExpressWaiting,
|
|
6
|
+
import { formatRefusal, refusalText, renderActivityBlocked, renderActivityLimit, renderActivityUncertain, renderExpressNoWait, renderExpressWaiting, joinRecoveryCommand, participantsRecoveryCommand, participantCommandPrefix, commandPrefix, quoteShell, takeoverRecoveryLines, withPathOutput, } from '../presentation.js';
|
|
7
|
+
import { renderExpression } from '../operation-presentation.js';
|
|
7
8
|
import { formatDuration } from '../time.js';
|
|
8
|
-
|
|
9
|
+
export { renderExpression } from '../operation-presentation.js';
|
|
9
10
|
export function saveActivityDraft(squarePath, name, body, now = Date.now()) {
|
|
10
11
|
const draftDir = path.join(path.dirname(squarePath), 'drafts');
|
|
11
12
|
fs.mkdirSync(draftDir, { recursive: true });
|
|
@@ -38,32 +39,6 @@ export function activityRetryCommand(squarePath, name, opts, force = opts.force
|
|
|
38
39
|
+ (opts.noMention === true ? ' --no-mention' : '');
|
|
39
40
|
return `${participantCommandPrefix(squarePath, name)} express${force ? ' --force' : ''}${opts.noWait ? ' --no-wait' : ''}${reach}${replyArgument(opts.reply)} -`;
|
|
40
41
|
}
|
|
41
|
-
function isGestureOnly(body) {
|
|
42
|
-
return /\*[^*]*\*/.test(body) && body.replace(/\*[^*]*\*/g, '').trim() === '';
|
|
43
|
-
}
|
|
44
|
-
export function renderExpression(squarePath, data) {
|
|
45
|
-
const projection = data.observation;
|
|
46
|
-
const name = projection.participant;
|
|
47
|
-
const pendingSpeaker = projection.pendingPublic[0]?.actor;
|
|
48
|
-
const pendingLead = pendingSpeaker === undefined ? ''
|
|
49
|
-
: `▲ while you spoke, ${participantIdentity(pendingSpeaker)} said something behind you\n\n`;
|
|
50
|
-
const pending = projection.pendingPublic.length === 0 ? ''
|
|
51
|
-
: `\n\n${pendingLead}${renderPendingFeed(projection.pendingPublic, projection.sayNumbers, projection.perceptions, name)}`;
|
|
52
|
-
const ownCount = projection.ownActivityCount;
|
|
53
|
-
const capCount = projection.hardCap === null ? '' : ` · ${ownCount}/${projection.hardCap}`;
|
|
54
|
-
const activity = data.activity;
|
|
55
|
-
const confirmation = activity.reach === 'bell'
|
|
56
|
-
? `● you ring the bell — everyone turns · ${activity.id}${style('dim', capCount)}`
|
|
57
|
-
: `● ${activity.mentions.length > 0
|
|
58
|
-
? `you walk over to ${activity.mentions.map((target) => participantIdentity(target)).join(', ')}`
|
|
59
|
-
: isGestureOnly(activity.body ?? '') ? 'your gesture lands' : 'your words land'} — ${activity.id}${style('dim', capCount)}`;
|
|
60
|
-
const replyNotice = data.replyAuthorNotHere === undefined ? ''
|
|
61
|
-
: `\n○ ${participantIdentity(data.replyAuthorNotHere)} isn't in the square right now — the reply landed without reaching them`;
|
|
62
|
-
const unmatchedNotice = data.unmatchedMentions?.length
|
|
63
|
-
? `\n · ${data.unmatchedMentions.map((token) => `@${token} isn't standing here`).join('; ')} — ${activity.mentions.length === 0 && activity.reply === undefined ? 'activity landed bare' : 'left as literal text'}` : '';
|
|
64
|
-
return withPathOutput(projection.location ?? squarePath, (projection.reentry === undefined ? '' : '● you stepped back into the square\n')
|
|
65
|
-
+ confirmation + (data.hint ? `\n${style('dim', `· ${data.hint}`)}` : '') + replyNotice + unmatchedNotice + pending, { participantCount: projection.standingCount, held: projection.held });
|
|
66
|
-
}
|
|
67
42
|
/** Body adaptation, terminal IO and drafts only; Participant owns every attempt and wait. */
|
|
68
43
|
export async function executeExpression(open, squarePath, requestedName, rawInput, opts) {
|
|
69
44
|
let square;
|
|
@@ -92,7 +67,9 @@ export async function executeExpression(open, squarePath, requestedName, rawInpu
|
|
|
92
67
|
});
|
|
93
68
|
landedId = outcome.activity.id;
|
|
94
69
|
name = outcome.observation.participant;
|
|
95
|
-
|
|
70
|
+
const rendered = renderExpression(squarePath, outcome);
|
|
71
|
+
if (rendered !== undefined)
|
|
72
|
+
process.stdout.write(rendered);
|
|
96
73
|
}
|
|
97
74
|
catch (error) {
|
|
98
75
|
const detail = error?.operation;
|
|
@@ -2,16 +2,14 @@ import path from 'node:path';
|
|
|
2
2
|
import { once } from 'node:events';
|
|
3
3
|
import { runClaudeMod } from '../claude-mod.js';
|
|
4
4
|
import { runCodexHookAsync } from '../codex-hook.js';
|
|
5
|
-
import { isSquareError
|
|
6
|
-
import { commandPrefix, participantIdentity,
|
|
5
|
+
import { isSquareError } from '../model.js';
|
|
6
|
+
import { commandPrefix, participantIdentity, truncateChars, withPathOutput, quoteShell, } from '../presentation.js';
|
|
7
|
+
import { PARTICIPANTS_DEFAULT_LIMIT, PARTICIPANTS_MAX_LIMIT, renderHistoryResult, renderParticipantsResult, renderStatusResult, } from '../operation-presentation.js';
|
|
7
8
|
import { style } from '../tty-style.js';
|
|
8
9
|
import { formatRelativeTime, formatTimestamp, parseTimeOrRelative } from '../time.js';
|
|
9
10
|
import { discover, inbox, formatActivityId, parseActivityId, CATCH_DEFAULT_LIMIT, CATCH_MAX_LIMIT, HISTORY_MAX_LIMIT, DEFAULT_LIST_DEPTH, MAX_LIST_DEPTH, DEFAULT_LIST_LIMIT, MAX_LIST_LIMIT } from '../square-api.js';
|
|
10
11
|
import { renderCatchOutcome, renderCatchProgress } from './catch-presentation.js';
|
|
11
12
|
import { withSquare, squareInput, now, fail, parseBoundedLimit, parseDurationMs, parseNameList, parseNonNegativeInteger, readStdin, requireSquarePath, requireValue, usage, } from './context.js';
|
|
12
|
-
const STATUS_PARTICIPANT_PREVIEW_LIMIT = 10;
|
|
13
|
-
const PARTICIPANTS_DEFAULT_LIMIT = 20;
|
|
14
|
-
const PARTICIPANTS_MAX_LIMIT = 100;
|
|
15
13
|
const INBOX_DEFAULT_LIMIT = 20;
|
|
16
14
|
const INBOX_MAX_LIMIT = 100;
|
|
17
15
|
const INBOX_DISPLAY_CHARS = 160;
|
|
@@ -414,34 +412,6 @@ function jsonLine(sayNumbers, item) {
|
|
|
414
412
|
reply: act.kind === 'say' && act.reply !== undefined ? formatActivityId(act.reply) : null,
|
|
415
413
|
});
|
|
416
414
|
}
|
|
417
|
-
function renderHistoryProjection(projection, visible, noTruncate, squarePath) {
|
|
418
|
-
const shown = visible;
|
|
419
|
-
const preview = noTruncate || shown.length <= 1 ? undefined : 200;
|
|
420
|
-
const chunks = [];
|
|
421
|
-
// Presence anchors collect into one closing line instead of interrupting the page.
|
|
422
|
-
const anchored = [];
|
|
423
|
-
for (const activity of shown) {
|
|
424
|
-
const options = {
|
|
425
|
-
preview,
|
|
426
|
-
actNumber: activity.kind === 'say' ? projection.sayNumbers[activity.index] : undefined,
|
|
427
|
-
};
|
|
428
|
-
const rendered = renderEventCli(activity, options);
|
|
429
|
-
if (rendered !== '')
|
|
430
|
-
chunks.push(rendered);
|
|
431
|
-
for (const participant of projection.presenceAnchors[activity.index] ?? []) {
|
|
432
|
-
if (!anchored.some((existing) => sameName(existing, participant)))
|
|
433
|
-
anchored.push(participant);
|
|
434
|
-
}
|
|
435
|
-
}
|
|
436
|
-
if (chunks.length === 0)
|
|
437
|
-
return 'latest\n ○ no public activity in this view';
|
|
438
|
-
if (preview !== undefined && shown.some((activity) => activity.kind === 'say' && activity.body.length > preview)) {
|
|
439
|
-
chunks.push(`${commandPrefix(squarePath)} history --no-truncate`);
|
|
440
|
-
}
|
|
441
|
-
if (anchored.length > 0)
|
|
442
|
-
chunks.push(renderPresenceAnchor(anchored));
|
|
443
|
-
return chunks.join('\n\n');
|
|
444
|
-
}
|
|
445
415
|
export const historyCommand = {
|
|
446
416
|
parse(argv, context) { return parseHistory(argv, context); },
|
|
447
417
|
async execute(options, context) {
|
|
@@ -463,13 +433,11 @@ export const historyCommand = {
|
|
|
463
433
|
if (options.format !== undefined && options.format.length > 0) {
|
|
464
434
|
return events.map((item) => renderFields(projection.sayNumbers, item, options.format)).join('\n') + (events.length > 0 ? '\n' : '');
|
|
465
435
|
}
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
:
|
|
470
|
-
|
|
471
|
-
const continuation = next === undefined ? '' : `\n\n${historyContinuationCommand(options, squarePath, [`--${next.direction}`, next.cursor, '--limit', String(next.limit)])}`;
|
|
472
|
-
return withPathOutput(squarePath, output + continuation, { participantCount: projection.standingCount });
|
|
436
|
+
return renderHistoryResult(squarePath, outcome, {
|
|
437
|
+
query: options.query,
|
|
438
|
+
noTruncate: options.noTruncate,
|
|
439
|
+
continuationArgs: options.continuationArgs,
|
|
440
|
+
});
|
|
473
441
|
},
|
|
474
442
|
present: (result) => process.stdout.write(result),
|
|
475
443
|
};
|
|
@@ -491,26 +459,7 @@ export const participantsCommand = {
|
|
|
491
459
|
async execute(intent, context) {
|
|
492
460
|
const squarePath = requireSquarePath(context);
|
|
493
461
|
const data = await withSquare(context, (square) => square.participants({ observe: true }));
|
|
494
|
-
|
|
495
|
-
const now = projection.now;
|
|
496
|
-
const participants = data.participants;
|
|
497
|
-
const lines = participants.slice(0, intent.limit).map((participant) => {
|
|
498
|
-
const glyph = participant.state === 'done' ? '○' : participant.presence === 'watching' ? '◎' : participant.activityCount > 0 && projection.classificationByName[participant.name] === 'here' ? '●' : '○';
|
|
499
|
-
const state = participant.state === 'done' ? 'done' : participant.presence === 'watching' ? 'catching' : participant.state;
|
|
500
|
-
const last = participant.lastActiveAt === undefined ? '—' : formatRelativeTime(participant.lastActiveAt, now);
|
|
501
|
-
return ` ${glyph} ${participant.name}${style('dim', ` · ${state} · ${participant.activityCount} ${participant.activityCount === 1 ? 'activity' : 'activities'} · ${last}`)}`;
|
|
502
|
-
});
|
|
503
|
-
const tail = participants.length <= intent.limit
|
|
504
|
-
? []
|
|
505
|
-
: [
|
|
506
|
-
style('dim', ` ○ ${lines.length} of ${participants.length} participants shown`),
|
|
507
|
-
...(participants.length <= PARTICIPANTS_MAX_LIMIT ? [
|
|
508
|
-
`${participantsLimitCommand(squarePath, participants.length)}`,
|
|
509
|
-
] : []),
|
|
510
|
-
];
|
|
511
|
-
return withPathOutput(squarePath, ['participants', ...lines, ...tail].join('\n'), {
|
|
512
|
-
participantCount: projection.standingCount,
|
|
513
|
-
});
|
|
462
|
+
return renderParticipantsResult(squarePath, data, intent.limit);
|
|
514
463
|
},
|
|
515
464
|
present: (result) => process.stdout.write(result),
|
|
516
465
|
};
|
|
@@ -520,88 +469,7 @@ export const statusCommand = {
|
|
|
520
469
|
async execute(_intent, context) {
|
|
521
470
|
const squarePath = requireSquarePath(context);
|
|
522
471
|
const result = await withSquare(context, (square) => square.status({ viewer: context.name, observe: true }));
|
|
523
|
-
|
|
524
|
-
const participantsByName = new Map(result.participants.map((participant) => [participant.name, participant]));
|
|
525
|
-
const orderedHere = presentation.orderedHereNames.map((name) => participantsByName.get(name));
|
|
526
|
-
const lingering = presentation.lingeringCount;
|
|
527
|
-
const people = [];
|
|
528
|
-
if (result.activeCount === 0) {
|
|
529
|
-
people.push(' ○ nobody in the square');
|
|
530
|
-
}
|
|
531
|
-
else {
|
|
532
|
-
if (orderedHere.length === 0)
|
|
533
|
-
people.push(' ○ nobody here right now');
|
|
534
|
-
people.push(...orderedHere.slice(0, STATUS_PARTICIPANT_PREVIEW_LIMIT).map((participant) => {
|
|
535
|
-
const glyph = participant.presence === 'watching'
|
|
536
|
-
? '◎'
|
|
537
|
-
: participant.activityCount > 0 ? '●' : '○';
|
|
538
|
-
const summary = participant.presence === 'watching'
|
|
539
|
-
? 'is nearby · catching'
|
|
540
|
-
: participant.activityCount > 0
|
|
541
|
-
? `is nearby · ${formatRelativeTime(participant.lastActiveAt ?? result.now, result.now)}`
|
|
542
|
-
: `is nearby · quiet · ${participant.lastActiveAt === undefined ? 'just now' : formatRelativeTime(participant.lastActiveAt, result.now)}`;
|
|
543
|
-
const showAttention = presentation.attentionNames.includes(participant.name);
|
|
544
|
-
const attention = !showAttention
|
|
545
|
-
? ''
|
|
546
|
-
: participant.pendingMentionCount > 0
|
|
547
|
-
? `${participant.pendingMentionCount} ${participant.pendingMentionCount === 1 ? 'mention' : 'mentions'} waiting`
|
|
548
|
-
: participant.unreadActivityCount > 0
|
|
549
|
-
? `${participant.unreadActivityCount} change${participant.unreadActivityCount === 1 ? '' : 's'} waiting`
|
|
550
|
-
: 'caught up';
|
|
551
|
-
return ` ${glyph} ${participantIdentity(participant.name)}${style('dim', ` ${summary}${attention === '' ? '' : ` · ${attention}`}`)}`;
|
|
552
|
-
}));
|
|
553
|
-
const unshown = Math.max(0, orderedHere.length - STATUS_PARTICIPANT_PREVIEW_LIMIT) + lingering;
|
|
554
|
-
if (orderedHere.length > STATUS_PARTICIPANT_PREVIEW_LIMIT) {
|
|
555
|
-
people.push(` ○ … ${orderedHere.length - STATUS_PARTICIPANT_PREVIEW_LIMIT} more here`);
|
|
556
|
-
}
|
|
557
|
-
if (lingering > 0)
|
|
558
|
-
people.push(` ○ … ${lingering} lingering`);
|
|
559
|
-
if (unshown > 0) {
|
|
560
|
-
people.push(`${presentation.knownParticipantCount <= PARTICIPANTS_MAX_LIMIT
|
|
561
|
-
? participantsLimitCommand(squarePath, presentation.knownParticipantCount)
|
|
562
|
-
: `${commandPrefix(squarePath)} participants`}`);
|
|
563
|
-
}
|
|
564
|
-
}
|
|
565
|
-
const cap = result.hardCap === null ? 'unlimited' : `${result.hardCap} each`;
|
|
566
|
-
const holdTime = result.hold?.at === undefined ? 'just now' : formatRelativeTime(result.hold.at, result.now);
|
|
567
|
-
const hold = result.hold !== null
|
|
568
|
-
? `· ${result.hold.by === undefined ? 'someone' : participantIdentity(result.hold.by)} raised a hand${result.hold.reason ? ` — ${result.hold.reason}` : ''}${style('dim', ` · ${holdTime}`)}`
|
|
569
|
-
: undefined;
|
|
570
|
-
const visible = result.latestActivity === undefined
|
|
571
|
-
? { text: '', bodyClipped: false }
|
|
572
|
-
: renderAmbientEventFacts(result.latestActivity, presentation.viewer, {
|
|
573
|
-
now: result.now,
|
|
574
|
-
preview: 200,
|
|
575
|
-
actNumber: presentation.latestActNumber,
|
|
576
|
-
perception: presentation.latestPerception,
|
|
577
|
-
});
|
|
578
|
-
const latest = visible.text === ''
|
|
579
|
-
? [result.latestActivity === undefined
|
|
580
|
-
? ' ○ no public activity yet'
|
|
581
|
-
: ' · the latest words were meant for other ears']
|
|
582
|
-
: [` ${visible.text.replace(/\n/g, '\n ')}`];
|
|
583
|
-
// Presence events after the latest public act: otherwise the roster can say someone is
|
|
584
|
-
// here while the latest line shows them leaving, with nothing to reconcile the two.
|
|
585
|
-
for (const { activity, rejoined } of presentation.joins) {
|
|
586
|
-
latest.push(style('dim', ` → ${participantIdentity(activity.actor)} ${rejoined ? 'stepped back in' : 'stepped in'} · ${formatRelativeTime(activity.at, result.now)}`));
|
|
587
|
-
}
|
|
588
|
-
if (presentation.joinCount > 3)
|
|
589
|
-
latest.push(style('dim', ` → … ${presentation.joinCount - 3} more stepped in`));
|
|
590
|
-
if (visible.bodyClipped && result.latestActivity !== undefined) {
|
|
591
|
-
latest.push(`${commandPrefix(squarePath)} history --at ${result.latestActivity.id} -C 2 --no-truncate`);
|
|
592
|
-
}
|
|
593
|
-
const counts = [
|
|
594
|
-
`${orderedHere.length} here`,
|
|
595
|
-
...(lingering > 0 ? [`${lingering} lingering`] : []),
|
|
596
|
-
`${result.doneCount} done`,
|
|
597
|
-
`cap ${cap}`,
|
|
598
|
-
`throttle ${result.throttlePerMinute === undefined ? 'none' : `${result.throttlePerMinute}/min`}`,
|
|
599
|
-
].join(' · ');
|
|
600
|
-
const output = [
|
|
601
|
-
style('dim', counts),
|
|
602
|
-
...(hold === undefined ? [] : ['', hold]), '', style('dim', 'around the square'), ...people, '', style('dim', 'latest'), ...latest,
|
|
603
|
-
].join('\n');
|
|
604
|
-
return withPathOutput(squarePath, output, { participantCount: presentation.standingCount, held: presentation.held });
|
|
472
|
+
return renderStatusResult(squarePath, result);
|
|
605
473
|
},
|
|
606
474
|
present: (result) => process.stdout.write(result),
|
|
607
475
|
};
|
package/dist/cli/program.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { helpRequest } from '../help.js';
|
|
2
2
|
import { isSquareError } from '../model.js';
|
|
3
|
-
import {
|
|
3
|
+
import { formatRefusal } from '../presentation.js';
|
|
4
|
+
import { renderFailureLines } from '../operation-presentation.js';
|
|
4
5
|
import { withSquare, defaultContext, parseGlobalArgs } from './context.js';
|
|
5
6
|
import { executeRegisteredCommand, findCommand } from './registry.js';
|
|
6
7
|
async function handleSquareError(error, context) {
|
|
@@ -11,35 +12,11 @@ async function handleSquareError(error, context) {
|
|
|
11
12
|
const recovery = error.facts?.reason === 'migration_required' || context === undefined || squarePath === undefined ? undefined
|
|
12
13
|
: await withSquare({ ...context, name: detail?.participant ?? context.name }, (square) => square.recovery(detail?.participant ?? context.name)).catch(() => undefined);
|
|
13
14
|
const name = detail?.participant ?? recovery?.participant ?? context?.name;
|
|
14
|
-
const
|
|
15
|
-
if (error.facts?.reason === 'migration_required') {
|
|
16
|
-
if (error.facts.ledgerRoot !== undefined)
|
|
17
|
-
existing.push('square ledger migrate', 'square ledger verify');
|
|
18
|
-
else if (squarePath !== undefined)
|
|
19
|
-
existing.push(`${commandPrefix(squarePath)} migrate`);
|
|
20
|
-
}
|
|
21
|
-
else if (squarePath !== undefined && name !== undefined && error.code === 'already_joined') {
|
|
22
|
-
existing.splice(0, 1, `✕ ${participantIdentity(name)} shoos you out of the square`, ` · ${participantIdentity(name)} already stands here — another session holds the name`);
|
|
23
|
-
existing.push(...takeoverRecoveryLines(squarePath, name));
|
|
24
|
-
}
|
|
25
|
-
else if (squarePath !== undefined && error.facts?.reason === 'never_joined') {
|
|
26
|
-
existing.push(detail?.subject !== 'filter' && name !== undefined
|
|
27
|
-
? joinRecoveryCommand(squarePath, name) : participantsRecoveryCommand(squarePath));
|
|
28
|
-
}
|
|
29
|
-
else if (squarePath !== undefined && error.facts?.reason === 'not_standing') {
|
|
30
|
-
existing.push(participantsRecoveryCommand(squarePath));
|
|
31
|
-
}
|
|
32
|
-
else if (squarePath !== undefined && error.facts?.reason === 'not_addressed' && typeof error.facts.activityId === 'string') {
|
|
33
|
-
existing.push(error.facts.activityExists === true
|
|
34
|
-
? `${commandPrefix(squarePath)} history --at ${error.facts.activityId} -C 2`
|
|
35
|
-
: `${commandPrefix(squarePath)} history --limit 10`);
|
|
36
|
-
}
|
|
37
|
-
if (error.facts?.reason === 'invalid_done_body')
|
|
38
|
-
existing.push('square done --help');
|
|
15
|
+
const lines = renderFailureLines(error, { squarePath, name });
|
|
39
16
|
if (squarePath === undefined)
|
|
40
|
-
process.stderr.write(`${
|
|
17
|
+
process.stderr.write(`${lines.join('\n')}\n`);
|
|
41
18
|
else
|
|
42
|
-
process.stderr.write(formatRefusal(squarePath,
|
|
19
|
+
process.stderr.write(formatRefusal(squarePath, lines, {
|
|
43
20
|
participantCount: recovery?.standingCount, held: recovery?.held,
|
|
44
21
|
}));
|
|
45
22
|
process.exit(error.code === 'not_found' ? 1 : 2);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { formatHardCap } from '../model.js';
|
|
2
|
-
import { commandPrefix, participantCommandPrefix,
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
2
|
+
import { commandPrefix, participantCommandPrefix, withPathOutput, } from '../presentation.js';
|
|
3
|
+
import { renderJoinResult, renderLifecycleResult, renderListenerChange, renderListeningResult, } from '../operation-presentation.js';
|
|
4
|
+
import { Square } from '../square-api.js';
|
|
5
5
|
import { executeExpression } from './express-presentation.js';
|
|
6
6
|
import { squareInput, withSquare, fail, parseBoundedLimit, parseHardCap, parsePositiveInteger, readStdin, requireSquarePath, requireValue, resolveBody, usage, } from './context.js';
|
|
7
7
|
const JOIN_DEFAULT_LAST = 10;
|
|
@@ -76,33 +76,7 @@ export const joinCommand = {
|
|
|
76
76
|
},
|
|
77
77
|
async execute(intent, context) {
|
|
78
78
|
const data = await withSquare(context, (square) => square.join(context.name, { takeover: intent.kick, last: intent.lastN, observe: true }));
|
|
79
|
-
|
|
80
|
-
const entry = after.entry;
|
|
81
|
-
const name = data.participant.name;
|
|
82
|
-
const activities = (entry?.recentActivities ?? []).map((event) => renderAmbientEvent(event, name, {
|
|
83
|
-
now: after.now, preview: 200,
|
|
84
|
-
actNumber: event.kind === 'say' ? entry.sayNumbers[event.index] : undefined,
|
|
85
|
-
perception: entry.perceptions[event.index],
|
|
86
|
-
})).filter(Boolean).join('\n\n');
|
|
87
|
-
const fallback = after.automaticDeliveryAvailable ? [] : [
|
|
88
|
-
'', `${participantCommandPrefix(after.location, name)} catch --idle 30m`,
|
|
89
|
-
' the square has no way to call you — keep this catch open and stay within earshot',
|
|
90
|
-
];
|
|
91
|
-
const entryLine = data.kind === 'joined' ? '● you stepped into the square'
|
|
92
|
-
: data.kind === 'reconnected' ? '● you are already in the square'
|
|
93
|
-
: `✓ you banished the original ${participantIdentity(name)} — the name is yours`;
|
|
94
|
-
const isRejoin = data.kind !== 'joined';
|
|
95
|
-
const entryScene = isRejoin || entry === undefined ? '' : entry.joinedBefore
|
|
96
|
-
? '*the flagstones are where you left them. so is your shadow.*' : entry.scene;
|
|
97
|
-
return withPathOutput(after.location, [
|
|
98
|
-
entryLine, '',
|
|
99
|
-
"· carved into the fountain's edge: every word here lands on a real ear — speak when someone needs it.",
|
|
100
|
-
...(entryScene === '' ? [] : ['', entryScene]),
|
|
101
|
-
...(isRejoin || !entry?.joinContext ? [] : ['', style('dim', 'context'), entry.joinContext]),
|
|
102
|
-
...(after.enrichmentUnavailable ? [' · joined; recent activity and context are unavailable right now'] : []),
|
|
103
|
-
...(isRejoin || activities === '' ? [] : ['', style('dim', 'recent activity'), activities]),
|
|
104
|
-
...fallback,
|
|
105
|
-
].join('\n'), { participantCount: after.standingCount, held: after.held });
|
|
79
|
+
return renderJoinResult(data);
|
|
106
80
|
},
|
|
107
81
|
present: (result) => process.stdout.write(result),
|
|
108
82
|
};
|
|
@@ -166,20 +140,9 @@ function listenerCommand(verb) {
|
|
|
166
140
|
return {
|
|
167
141
|
parse(argv, context) { return parseListener(argv, context, true); },
|
|
168
142
|
async execute(intent, context) {
|
|
143
|
+
const squarePath = requireSquarePath(context);
|
|
169
144
|
const data = await withSquare(context, async (square) => (await square.participant(context.name))[verb](intent.target, { observe: true }));
|
|
170
|
-
|
|
171
|
-
const actor = participantIdentity(projection.participant);
|
|
172
|
-
const target = participantIdentity(projection.target);
|
|
173
|
-
const action = data.activity !== null
|
|
174
|
-
? verb === 'listen' ? `${actor} turns an ear toward ${target}`
|
|
175
|
-
: verb === 'ignore' ? `${actor} turns away from ${target}`
|
|
176
|
-
: `${actor} stops listening to ${target}`
|
|
177
|
-
: verb === 'listen' ? `${actor} already turns an ear toward ${target}`
|
|
178
|
-
: verb === 'ignore' ? `${actor} is not turned toward ${target}`
|
|
179
|
-
: `${actor} is not listening to ${target}`;
|
|
180
|
-
return withPathOutput(projection.location, `${data.activity === null ? '○' : '·'} ${action}`, {
|
|
181
|
-
participantCount: projection.standingCount, held: projection.held,
|
|
182
|
-
});
|
|
145
|
+
return renderListenerChange(squarePath, verb, data);
|
|
183
146
|
},
|
|
184
147
|
present: (result) => process.stdout.write(result),
|
|
185
148
|
};
|
|
@@ -190,12 +153,9 @@ export const unlistenCommand = listenerCommand('unlisten');
|
|
|
190
153
|
export const listeningCommand = {
|
|
191
154
|
parse(argv, context) { return parseListener(argv, context, false); },
|
|
192
155
|
async execute(_intent, context) {
|
|
156
|
+
const squarePath = requireSquarePath(context);
|
|
193
157
|
const data = await withSquare(context, async (square) => (await square.participant(context.name)).listening({ observe: true }));
|
|
194
|
-
|
|
195
|
-
const body = data.listening.length === 0
|
|
196
|
-
? `○ ${participantIdentity(projection.participant)} is not turned toward anyone`
|
|
197
|
-
: ['listening', ...data.listening.map((target) => ` · ${participantIdentity(target)}`)].join('\n');
|
|
198
|
-
return withPathOutput(projection.location, body, { participantCount: projection.standingCount, held: projection.held });
|
|
158
|
+
return renderListeningResult(squarePath, data);
|
|
199
159
|
},
|
|
200
160
|
present: (result) => process.stdout.write(result),
|
|
201
161
|
};
|
|
@@ -208,11 +168,9 @@ export const doneCommand = {
|
|
|
208
168
|
async execute(intent, context) {
|
|
209
169
|
const body = intent.body === '-' || ((intent.body === undefined || intent.body === '') && !process.stdin.isTTY)
|
|
210
170
|
? await readStdin() : intent.body;
|
|
171
|
+
const squarePath = requireSquarePath(context);
|
|
211
172
|
const data = await withSquare(context, async (square) => (await square.participant(context.name)).done(body, { observe: true }));
|
|
212
|
-
|
|
213
|
-
return withPathOutput(projection.location, `○ you stepped out — your footsteps fade · ${data.activity.id}`, {
|
|
214
|
-
participantCount: projection.standingCount, held: projection.held,
|
|
215
|
-
});
|
|
173
|
+
return renderLifecycleResult(squarePath, 'done', data);
|
|
216
174
|
},
|
|
217
175
|
present: (result) => process.stdout.write(result),
|
|
218
176
|
};
|
|
@@ -224,9 +182,9 @@ export const holdCommand = {
|
|
|
224
182
|
},
|
|
225
183
|
async execute(intent, context) {
|
|
226
184
|
const body = (await resolveBody(intent.body ?? '')).replace(/\r\n/g, '\n').trim();
|
|
185
|
+
const squarePath = requireSquarePath(context);
|
|
227
186
|
const result = await withSquare(context, async (square) => (await square.participant(context.name)).hold(body, { observe: true }));
|
|
228
|
-
|
|
229
|
-
return withPathOutput(projection.location, `· ${renderRoomChangeText(projection.activity)} · ${formatActivityId(projection.activity.index)} · just now`, { participantCount: projection.standingCount, held: projection.held });
|
|
187
|
+
return renderLifecycleResult(squarePath, 'hold', result);
|
|
230
188
|
},
|
|
231
189
|
present: (result) => process.stdout.write(result),
|
|
232
190
|
};
|
|
@@ -237,9 +195,9 @@ export const resumeCommand = {
|
|
|
237
195
|
return {};
|
|
238
196
|
},
|
|
239
197
|
async execute(_intent, context) {
|
|
198
|
+
const squarePath = requireSquarePath(context);
|
|
240
199
|
const result = await withSquare(context, async (square) => (await square.participant(context.name)).resume({ observe: true }));
|
|
241
|
-
|
|
242
|
-
return withPathOutput(projection.location, `✓ ${renderRoomChangeText(projection.activity)} · ${formatActivityId(projection.activity.index)} · just now`, { participantCount: projection.standingCount, held: projection.held });
|
|
200
|
+
return renderLifecycleResult(squarePath, 'resume', result);
|
|
243
201
|
},
|
|
244
202
|
present: (result) => process.stdout.write(result),
|
|
245
203
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type DirectedNotificationRoute } from './delivery.js';
|
|
2
|
-
import type
|
|
2
|
+
import { type WakeAttempt, type WakeReleaseDiagnostic } from './wake-evidence.js';
|
|
3
3
|
export type DeliveryHealthKind = 'awaiting' | 'wake-accepted' | 'wake-unknown' | 'presented-not-delivered' | 'unreachable';
|
|
4
4
|
export interface DeliveryHealthItem {
|
|
5
5
|
squarePath: string;
|
|
@@ -18,5 +18,5 @@ export declare function classifyDeliveryHealth(squarePath: string, opts: {
|
|
|
18
18
|
now?: number;
|
|
19
19
|
env?: NodeJS.ProcessEnv;
|
|
20
20
|
}): Promise<DeliveryHealthItem[]>;
|
|
21
|
-
export declare function renderDeliveryHealth(items: readonly DeliveryHealthItem[], releases?: readonly WakeReleaseDiagnostic[], now?: number): string[];
|
|
21
|
+
export declare function renderDeliveryHealth(items: readonly DeliveryHealthItem[], releases?: readonly WakeReleaseDiagnostic[], now?: number, nativeAttempts?: readonly WakeAttempt[]): string[];
|
|
22
22
|
export declare function doctorDeliveryHealth(squarePath: string, graceMs: number, now?: number, env?: NodeJS.ProcessEnv): Promise<string[]>;
|