@astrosheep/square 0.3.77 → 0.3.79
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/attention-presentation.d.ts +3 -1
- package/dist/attention-presentation.js +45 -13
- package/dist/automatic-session.js +1 -1
- package/dist/boundary-presentation.js +4 -6
- package/dist/claude-mod.js +1 -1
- package/dist/cli/catch-presentation.d.ts +2 -2
- package/dist/cli/catch-presentation.js +3 -3
- package/dist/cli/context.d.ts +11 -1
- package/dist/cli/context.js +14 -3
- package/dist/cli/express-presentation.d.ts +6 -5
- package/dist/cli/express-presentation.js +35 -30
- package/dist/cli/maintenance-commands.js +8 -8
- package/dist/cli/mcp-server-command.js +1 -1
- package/dist/cli/observation-commands.d.ts +4 -4
- package/dist/cli/observation-commands.js +20 -16
- package/dist/cli/program.d.ts +1 -1
- package/dist/cli/program.js +13 -7
- package/dist/cli/square-commands.js +35 -23
- package/dist/decisions.d.ts +9 -4
- package/dist/decisions.js +17 -8
- package/dist/delivery.d.ts +1 -1
- package/dist/help.js +15 -2
- package/dist/host-ledger-migration.js +2 -6
- package/dist/host-ledger-sqlite.js +2 -2
- package/dist/inbox.js +3 -3
- package/dist/index.d.ts +1 -2
- package/dist/index.js +1 -2
- package/dist/ledger-maintenance.d.ts +1 -1
- package/dist/ledger-maintenance.js +1 -1
- package/dist/list.d.ts +3 -3
- package/dist/list.js +1 -1
- package/dist/mcp.d.ts +2 -2
- package/dist/mcp.js +12 -7
- package/dist/mention-parse.d.ts +2 -8
- package/dist/mention-parse.js +6 -9
- package/dist/model.d.ts +5 -1
- package/dist/notifications.js +24 -8
- package/dist/participant-host.js +5 -0
- package/dist/plugins/opencode/index.js +1 -1
- package/dist/square-actions.d.ts +22 -9
- package/dist/square-actions.js +27 -19
- package/dist/square-api.d.ts +43 -0
- package/dist/square-api.js +471 -0
- package/dist/square-facade.d.ts +124 -203
- package/dist/square-sqlite.d.ts +2 -8
- package/dist/square-sqlite.js +3 -11
- package/dist/square-tools.d.ts +4 -3
- package/dist/square-tools.js +22 -16
- package/dist/stream.d.ts +2 -2
- package/dist/views.d.ts +16 -12
- package/dist/views.js +13 -27
- package/guides/application-demand-optimization.md +5 -0
- package/guides/application-facade-delivery-evidence.md +6 -1
- package/guides/claude-native.md +3 -1
- package/guides/mcp-connection-lifetime.md +2 -2
- package/guides/mcp.md +1 -1
- package/guides/migration.md +2 -1
- package/guides/operation-cancellation.md +2 -0
- package/guides/primitive-catch-consolidation.md +5 -0
- package/guides/primitive-history-consolidation.md +5 -0
- package/guides/primitive-status-consolidation.md +5 -0
- package/guides/primitive-storage-consolidation.md +5 -0
- package/guides/row-storage-design.md +2 -2
- package/guides/square-api.md +107 -0
- package/package.json +1 -1
- package/plugins/claude/.claude-plugin/plugin.json +1 -1
- package/plugins/claude/skills/square/SKILL.md +3 -3
- package/plugins/codex/.codex-plugin/plugin.json +1 -1
- package/plugins/opencode/index.ts +1 -1
- package/plugins/paseo/client/markdown.tsx +16 -6
- package/plugins/pi/square-pi.js +70 -30
- package/skills/square/SKILL.md +3 -3
- package/dist/square-application.d.ts +0 -38
- package/dist/square-application.js +0 -683
- package/guides/application-boundary.md +0 -32
- package/guides/application-facade-design.md +0 -98
|
@@ -11,7 +11,9 @@ export interface AttentionPreview {
|
|
|
11
11
|
export declare function previewAttentionBody(body: string): string;
|
|
12
12
|
export declare function attentionBodyIsClipped(body: string): boolean;
|
|
13
13
|
export declare function displayAttentionPath(squarePath: string): string;
|
|
14
|
-
export declare function renderAttentionDescription({ actor,
|
|
14
|
+
export declare function renderAttentionDescription({ actor, route }: Pick<AttentionPreview, 'actor' | 'route'>): string;
|
|
15
15
|
/** Full notification text for human-facing expansion, never the bounded model preview. */
|
|
16
16
|
export declare function renderAttentionFull(attention: AttentionPreview): string;
|
|
17
|
+
/** Shared model-facing envelope; transport correlation and human cards stay outside it. */
|
|
18
|
+
export declare function renderSquareReminder(previews: readonly string[]): string;
|
|
17
19
|
export declare function renderAttentionPreview(attention: AttentionPreview): string;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { homedir } from 'node:os';
|
|
2
2
|
import { formatActivityId } from './square-core.js';
|
|
3
|
-
import { participantCommandPrefix } from './presentation.js';
|
|
4
3
|
export const ATTENTION_BODY_MAX = 200;
|
|
5
4
|
export function previewAttentionBody(body) {
|
|
6
5
|
const compact = body.replace(/\r\n/g, '\n');
|
|
@@ -16,35 +15,68 @@ export function displayAttentionPath(squarePath) {
|
|
|
16
15
|
? `~${squarePath.slice(homedir().length)}`
|
|
17
16
|
: squarePath;
|
|
18
17
|
}
|
|
19
|
-
export function renderAttentionDescription({ actor,
|
|
18
|
+
export function renderAttentionDescription({ actor, route }) {
|
|
20
19
|
switch (route) {
|
|
21
|
-
case 'mention': return `${actor} spoke your name
|
|
22
|
-
case 'reply': return `${actor} answered you
|
|
23
|
-
case 'attention': return `${actor} spoke · you’re listening
|
|
24
|
-
case 'bell': return `${actor} rang the bell
|
|
20
|
+
case 'mention': return `${actor} spoke your name`;
|
|
21
|
+
case 'reply': return `${actor} answered you`;
|
|
22
|
+
case 'attention': return `${actor} spoke · you’re listening`;
|
|
23
|
+
case 'bell': return `${actor} rang the bell`;
|
|
25
24
|
}
|
|
26
25
|
}
|
|
27
26
|
/** Full notification text for human-facing expansion, never the bounded model preview. */
|
|
28
27
|
export function renderAttentionFull(attention) {
|
|
29
28
|
return renderAttentionBlock(attention, attention.body);
|
|
30
29
|
}
|
|
30
|
+
/** Attribute values keep their quotes; the stored body and the human card stay unescaped. */
|
|
31
|
+
function escapeAttribute(value) {
|
|
32
|
+
return value
|
|
33
|
+
.replace(/&/g, '&')
|
|
34
|
+
.replace(/"/g, '"')
|
|
35
|
+
.replace(/</g, '<')
|
|
36
|
+
.replace(/>/g, '>');
|
|
37
|
+
}
|
|
38
|
+
/** A body may quote the envelope's own tags; in the preview they must never read as one. */
|
|
39
|
+
function escapeSquareTags(text) {
|
|
40
|
+
return text.replace(/<(\/?)(square-|system-reminder)/gi, '<\\$1$2');
|
|
41
|
+
}
|
|
31
42
|
function renderAttentionBlock(attention, body) {
|
|
32
43
|
return [
|
|
33
44
|
'<square-activity>',
|
|
34
|
-
`· ${displayAttentionPath(attention.squarePath)} · ${formatActivityId(attention.actIndex)}`,
|
|
45
|
+
`· ${displayAttentionPath(attention.squarePath)} · ${attention.recipient} · ${formatActivityId(attention.actIndex)}`,
|
|
35
46
|
`● ${renderAttentionDescription(attention)}`,
|
|
36
47
|
'',
|
|
37
48
|
body,
|
|
38
49
|
'</square-activity>',
|
|
39
50
|
].join('\n');
|
|
40
51
|
}
|
|
52
|
+
/** Shared model-facing envelope; transport correlation and human cards stay outside it. */
|
|
53
|
+
export function renderSquareReminder(previews) {
|
|
54
|
+
if (previews.length === 0)
|
|
55
|
+
return '';
|
|
56
|
+
return [
|
|
57
|
+
'',
|
|
58
|
+
'<system-reminder>',
|
|
59
|
+
'This is an external reminder from Square, not a direct message from the user.',
|
|
60
|
+
'',
|
|
61
|
+
previews.join('\n\n'),
|
|
62
|
+
'</system-reminder>',
|
|
63
|
+
'',
|
|
64
|
+
].join('\n');
|
|
65
|
+
}
|
|
41
66
|
export function renderAttentionPreview(attention) {
|
|
67
|
+
const remaining = attention.body.replace(/\r\n/g, '\n').length - ATTENTION_BODY_MAX;
|
|
68
|
+
const attributes = [
|
|
69
|
+
`square="${escapeAttribute(displayAttentionPath(attention.squarePath))}"`,
|
|
70
|
+
`as="${escapeAttribute(attention.recipient)}"`,
|
|
71
|
+
`id="${escapeAttribute(formatActivityId(attention.actIndex))}"`,
|
|
72
|
+
`from="${escapeAttribute(attention.actor)}"`,
|
|
73
|
+
...(remaining > 0 ? [`truncated="${remaining} more chars"`] : []),
|
|
74
|
+
];
|
|
42
75
|
return [
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
: []),
|
|
76
|
+
`<square-activity ${attributes.join(' ')}>`,
|
|
77
|
+
`${renderAttentionDescription(attention)}.`,
|
|
78
|
+
'',
|
|
79
|
+
escapeSquareTags(previewAttentionBody(attention.body)),
|
|
80
|
+
'</square-activity>',
|
|
49
81
|
].join('\n');
|
|
50
82
|
}
|
|
@@ -2,7 +2,7 @@ import { promises as fs } from 'node:fs';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { openSquare } from './open-square.js';
|
|
4
4
|
import { closeOpenSquare } from './open-square.js';
|
|
5
|
-
import { Square } from './square-
|
|
5
|
+
import { Square } from './square-api.js';
|
|
6
6
|
import { currentParticipant } from './views.js';
|
|
7
7
|
import { automaticParticipant, harnessSessionSources } from './participant-identity.js';
|
|
8
8
|
import { SquareError } from './model.js';
|
|
@@ -7,7 +7,7 @@ import { closeOpenSquare } from './open-square.js';
|
|
|
7
7
|
import { presentPending } from './presentation-operations.js';
|
|
8
8
|
import { hostLedgerForEnv } from './registry.js';
|
|
9
9
|
import { sessionInbox } from './inbox.js';
|
|
10
|
-
import { attentionBodyIsClipped, renderAttentionPreview } from './attention-presentation.js';
|
|
10
|
+
import { attentionBodyIsClipped, renderAttentionPreview, renderSquareReminder } from './attention-presentation.js';
|
|
11
11
|
import { projectBoundaryEligibility } from './square-projections.js';
|
|
12
12
|
export { pendingAtBoundary } from './square-projections.js';
|
|
13
13
|
const CONTEXT_MAX = 1200;
|
|
@@ -38,14 +38,12 @@ async function awaitWithSignal(promise, signal) {
|
|
|
38
38
|
export function renderPendingAtBoundary(inbox) {
|
|
39
39
|
return renderBoundary(inbox).context;
|
|
40
40
|
}
|
|
41
|
-
function frameBoundary(lines) {
|
|
42
|
-
return `\n${lines.join('\n')}\n`;
|
|
43
|
-
}
|
|
44
41
|
function renderBoundary(inbox) {
|
|
45
42
|
const queued = inbox.flatMap((membership) => membership.notifications.map((notification) => ({ membership, notification })));
|
|
46
43
|
const blocks = [];
|
|
47
44
|
const complete = [];
|
|
48
45
|
let omitted = 0;
|
|
46
|
+
const omission = (count) => `${count} more ${count === 1 ? 'activity' : 'activities'} not shown.`;
|
|
49
47
|
for (const [index, entry] of queued.entries()) {
|
|
50
48
|
const { membership, notification } = entry;
|
|
51
49
|
const block = [
|
|
@@ -59,7 +57,7 @@ function renderBoundary(inbox) {
|
|
|
59
57
|
}),
|
|
60
58
|
].join('\n');
|
|
61
59
|
const omittedAfter = omitted + queued.length - index - 1;
|
|
62
|
-
const prospective =
|
|
60
|
+
const prospective = renderSquareReminder([...blocks, block, ...(omittedAfter > 0 ? [omission(omittedAfter)] : [])]);
|
|
63
61
|
if (prospective.length > CONTEXT_MAX) {
|
|
64
62
|
omitted += 1;
|
|
65
63
|
continue;
|
|
@@ -72,7 +70,7 @@ function renderBoundary(inbox) {
|
|
|
72
70
|
});
|
|
73
71
|
}
|
|
74
72
|
return {
|
|
75
|
-
context:
|
|
73
|
+
context: renderSquareReminder([...blocks, ...(omitted > 0 ? [omission(omitted)] : [])]),
|
|
76
74
|
complete,
|
|
77
75
|
};
|
|
78
76
|
}
|
package/dist/claude-mod.js
CHANGED
|
@@ -3,7 +3,7 @@ import { claimSessionParticipant, hostLedgerForEnv } from './registry.js';
|
|
|
3
3
|
import { openSquare } from './open-square.js';
|
|
4
4
|
import { closeOpenSquare } from './open-square.js';
|
|
5
5
|
import { publishWakeRoute, retireWakeRouteFromArtifact } from './routes.js';
|
|
6
|
-
import { Square } from './square-
|
|
6
|
+
import { Square } from './square-api.js';
|
|
7
7
|
import { observeClaudeDelivery } from './claude-delivery.js';
|
|
8
8
|
import { processActNotificationsOnce } from './notifications.js';
|
|
9
9
|
import { sweepPending } from './delivery-operations.js';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { CatchResult, CatchOptions, OperationProgress } from '../square-facade.js';
|
|
2
2
|
export declare function renderCatchProgress(squarePath: string, progress: OperationProgress): string | undefined;
|
|
3
3
|
/** Render settled catch facts; no selection, terminal decisions, receipts or wait machinery. */
|
|
4
|
-
export declare function renderCatchOutcome(squarePath: string,
|
|
4
|
+
export declare function renderCatchOutcome(squarePath: string, data: CatchResult, options?: CatchOptions): {
|
|
5
5
|
stdout: string;
|
|
6
6
|
exitCode: number;
|
|
7
7
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { parseActivityId } from '../square-
|
|
1
|
+
import { parseActivityId } from '../square-api.js';
|
|
2
2
|
import { participantCommandPrefix, renderAmbientEvent, renderWatchAlreadyActive, renderWatchForceTakeover, renderWatchReplaceMissing, renderWatchReplaced, renderWatchStatus, withPathOutput, } from '../presentation.js';
|
|
3
3
|
export function renderCatchProgress(squarePath, progress) {
|
|
4
4
|
if (progress.kind !== 'catch-started' || !progress.replacementRequested)
|
|
@@ -18,8 +18,8 @@ function continuationCommand(squarePath, name, options) {
|
|
|
18
18
|
return `${participantCommandPrefix(squarePath, name)} catch ${args.join(' ')}`;
|
|
19
19
|
}
|
|
20
20
|
/** Render settled catch facts; no selection, terminal decisions, receipts or wait machinery. */
|
|
21
|
-
export function renderCatchOutcome(squarePath,
|
|
22
|
-
const
|
|
21
|
+
export function renderCatchOutcome(squarePath, data, options = {}) {
|
|
22
|
+
const projection = data.observation;
|
|
23
23
|
const location = projection.location ?? squarePath;
|
|
24
24
|
const name = projection.participant;
|
|
25
25
|
const stop = projection.stop ?? data.status;
|
package/dist/cli/context.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { type HardCap } from '../model.js';
|
|
2
|
+
import { Square } from '../square-api.js';
|
|
3
|
+
import type { OperationControl } from '../square-facade.js';
|
|
2
4
|
export interface CommandContext {
|
|
3
5
|
cwd: string;
|
|
4
6
|
env: NodeJS.ProcessEnv;
|
|
@@ -33,5 +35,13 @@ export interface ParsedGlobalArgs {
|
|
|
33
35
|
export declare function parseGlobalArgs(rawArgs: string[]): Promise<ParsedGlobalArgs>;
|
|
34
36
|
export declare function locationIsRequired(command: string): boolean;
|
|
35
37
|
export declare function defaultContext(command: string, squarePath?: string, name?: string): CommandContext;
|
|
36
|
-
export declare function
|
|
38
|
+
export declare function squareInput(context: CommandContext): {
|
|
39
|
+
cwd: string;
|
|
40
|
+
env: NodeJS.ProcessEnv;
|
|
41
|
+
path: string | undefined;
|
|
42
|
+
participant: string | undefined;
|
|
43
|
+
};
|
|
44
|
+
/** Adapter lifetime only; each callback uses the actual public resource API. */
|
|
45
|
+
export declare function withSquare<T>(context: CommandContext, run: (square: Square) => Promise<T>, control?: OperationControl): Promise<T>;
|
|
46
|
+
export declare function now(context: CommandContext): number;
|
|
37
47
|
export declare function requireSquarePath(context: CommandContext): string;
|
package/dist/cli/context.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import os from 'node:os';
|
|
2
2
|
import { commandUsageHint } from '../help.js';
|
|
3
3
|
import { parseParticipantList, validateName } from '../model.js';
|
|
4
|
-
import {
|
|
4
|
+
import { Square, squareClock } from '../square-api.js';
|
|
5
5
|
export async function readStdin() {
|
|
6
6
|
try {
|
|
7
7
|
let content = '';
|
|
@@ -137,9 +137,20 @@ export function locationIsRequired(command) {
|
|
|
137
137
|
export function defaultContext(command, squarePath, name) {
|
|
138
138
|
return { command, cwd: process.cwd(), env: { ...process.env }, squarePath, name, homeDir: os.homedir() };
|
|
139
139
|
}
|
|
140
|
-
export function
|
|
141
|
-
return
|
|
140
|
+
export function squareInput(context) {
|
|
141
|
+
return { cwd: context.cwd, env: context.env, path: context.squarePath, participant: context.name };
|
|
142
142
|
}
|
|
143
|
+
/** Adapter lifetime only; each callback uses the actual public resource API. */
|
|
144
|
+
export async function withSquare(context, run, control) {
|
|
145
|
+
const square = await Square.at(squareInput(context), control);
|
|
146
|
+
try {
|
|
147
|
+
return await run(square);
|
|
148
|
+
}
|
|
149
|
+
finally {
|
|
150
|
+
await square.close();
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
export function now(context) { return squareClock(context.env)(); }
|
|
143
154
|
export function requireSquarePath(context) {
|
|
144
155
|
if (context.squarePath === undefined)
|
|
145
156
|
fail(`✕ ${context.command} needs a square location\nsquare ls`);
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
1
|
+
import { type Square } from '../square-api.js';
|
|
2
|
+
import type { OperationControl, ExpressResult, ExpressOptions } from '../square-facade.js';
|
|
3
|
+
export interface ActivityOptions extends Omit<ExpressOptions, 'reply'> {
|
|
3
4
|
readonly reply?: string;
|
|
4
5
|
}
|
|
5
6
|
export declare function saveActivityDraft(squarePath: string, name: string, body: string, now?: number): string;
|
|
6
7
|
/** Retry choices are transport syntax, never a second admission decision. */
|
|
7
8
|
export declare function activityRetryCommand(squarePath: string, name: string, opts: ActivityOptions, force?: boolean): string;
|
|
8
|
-
export declare function renderExpression(squarePath: string,
|
|
9
|
-
/** Body adaptation, terminal IO and drafts only;
|
|
10
|
-
export declare function executeExpression(
|
|
9
|
+
export declare function renderExpression(squarePath: string, data: ExpressResult): string;
|
|
10
|
+
/** Body adaptation, terminal IO and drafts only; Participant owns every attempt and wait. */
|
|
11
|
+
export declare function executeExpression(open: (control?: OperationControl) => Promise<Square>, squarePath: string, requestedName: string | undefined, rawInput: string, opts: ActivityOptions): Promise<void>;
|
|
@@ -2,7 +2,7 @@ import crypto from 'node:crypto';
|
|
|
2
2
|
import fs from 'node:fs';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { isSquareError } from '../model.js';
|
|
5
|
-
import { formatActivityId, parseActivityId } from '../square-
|
|
5
|
+
import { formatActivityId, parseActivityId } from '../square-api.js';
|
|
6
6
|
import { expressHintLine, formatRefusal, refusalText, renderActivityBlocked, renderActivityLimit, renderActivityUncertain, renderExpressNoWait, renderExpressWaiting, renderPendingFeed, joinRecoveryCommand, participantIdentity, participantsRecoveryCommand, participantCommandPrefix, commandPrefix, quoteShell, takeoverRecoveryLines, withPathOutput, } from '../presentation.js';
|
|
7
7
|
import { formatDuration } from '../time.js';
|
|
8
8
|
import { style } from '../tty-style.js';
|
|
@@ -33,19 +33,16 @@ function replyArgument(reply) {
|
|
|
33
33
|
}
|
|
34
34
|
/** Retry choices are transport syntax, never a second admission decision. */
|
|
35
35
|
export function activityRetryCommand(squarePath, name, opts, force = opts.force ?? false) {
|
|
36
|
-
const reach = opts.reach === 'bell' ? ' --bell'
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
const reach = (opts.reach === 'bell' ? ' --bell' : '')
|
|
37
|
+
+ (opts.mentions ?? []).map((target) => ` --mention ${quoteShell(target)}`).join('')
|
|
38
|
+
+ (opts.noMention === true ? ' --no-mention' : '');
|
|
39
39
|
return `${participantCommandPrefix(squarePath, name)} express${force ? ' --force' : ''}${opts.noWait ? ' --no-wait' : ''}${reach}${replyArgument(opts.reply)} -`;
|
|
40
40
|
}
|
|
41
|
-
function mentionRepairCommand(squarePath, name, opts, bell) {
|
|
42
|
-
return `${participantCommandPrefix(squarePath, name)} express${opts.force ? ' --force' : ''}${opts.noWait ? ' --no-wait' : ''}${bell ? ' --bell' : ' --no-mention'}${replyArgument(opts.reply)} -`;
|
|
43
|
-
}
|
|
44
41
|
function isGestureOnly(body) {
|
|
45
42
|
return /\*[^*]*\*/.test(body) && body.replace(/\*[^*]*\*/g, '').trim() === '';
|
|
46
43
|
}
|
|
47
|
-
export function renderExpression(squarePath,
|
|
48
|
-
const
|
|
44
|
+
export function renderExpression(squarePath, data) {
|
|
45
|
+
const projection = data.observation;
|
|
49
46
|
const name = projection.participant;
|
|
50
47
|
const pendingSpeaker = projection.pendingPublic[0]?.actor;
|
|
51
48
|
const pendingLead = pendingSpeaker === undefined ? ''
|
|
@@ -63,11 +60,15 @@ export function renderExpression(squarePath, outcome) {
|
|
|
63
60
|
const hint = expressHintLine(ownCount);
|
|
64
61
|
const replyNotice = data.replyAuthorNotHere === undefined ? ''
|
|
65
62
|
: `\n○ ${participantIdentity(data.replyAuthorNotHere)} isn't in the square right now — the reply landed without reaching them`;
|
|
63
|
+
const unmatchedNotice = data.unmatchedMentions?.length
|
|
64
|
+
? `\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'}` : '';
|
|
66
65
|
return withPathOutput(projection.location ?? squarePath, (projection.reentry === undefined ? '' : '● you stepped back into the square\n')
|
|
67
|
-
+ confirmation + (hint ? `\n${style('dim', hint)}` : '') + replyNotice + pending, { participantCount: projection.standingCount, held: projection.held });
|
|
66
|
+
+ confirmation + (hint ? `\n${style('dim', hint)}` : '') + replyNotice + unmatchedNotice + pending, { participantCount: projection.standingCount, held: projection.held });
|
|
68
67
|
}
|
|
69
|
-
/** Body adaptation, terminal IO and drafts only;
|
|
70
|
-
export async function executeExpression(
|
|
68
|
+
/** Body adaptation, terminal IO and drafts only; Participant owns every attempt and wait. */
|
|
69
|
+
export async function executeExpression(open, squarePath, requestedName, rawInput, opts) {
|
|
70
|
+
let square;
|
|
71
|
+
let attempted = false;
|
|
71
72
|
let announcedWait;
|
|
72
73
|
let landedId;
|
|
73
74
|
let name = requestedName;
|
|
@@ -75,8 +76,12 @@ export async function executeExpression(application, squarePath, requestedName,
|
|
|
75
76
|
const interrupt = () => controller.abort();
|
|
76
77
|
process.once('SIGINT', interrupt);
|
|
77
78
|
try {
|
|
78
|
-
|
|
79
|
-
|
|
79
|
+
square = await open({ signal: controller.signal });
|
|
80
|
+
const participant = await square.participant(requestedName);
|
|
81
|
+
name = participant.name;
|
|
82
|
+
attempted = true;
|
|
83
|
+
const outcome = await participant.express(rawInput.replace(/\r\n/g, '\n').trim(), {
|
|
84
|
+
...opts, reply: opts.reply, requireExplicitReach: true, observe: true,
|
|
80
85
|
}, {
|
|
81
86
|
signal: controller.signal,
|
|
82
87
|
onProgress(progress) {
|
|
@@ -86,8 +91,8 @@ export async function executeExpression(application, squarePath, requestedName,
|
|
|
86
91
|
announcedWait = progress.reason;
|
|
87
92
|
},
|
|
88
93
|
});
|
|
89
|
-
landedId = outcome.
|
|
90
|
-
name = outcome.
|
|
94
|
+
landedId = outcome.activity.id;
|
|
95
|
+
name = outcome.observation.participant;
|
|
91
96
|
process.stdout.write(renderExpression(squarePath, outcome));
|
|
92
97
|
}
|
|
93
98
|
catch (error) {
|
|
@@ -95,13 +100,14 @@ export async function executeExpression(application, squarePath, requestedName,
|
|
|
95
100
|
name = detail?.participant ?? name ?? 'participant';
|
|
96
101
|
// This MUST precede recovery: even an unreadable artifact cannot eat the raw body.
|
|
97
102
|
const draftPath = saveActivityDraft(squarePath, name, rawInput);
|
|
98
|
-
|
|
99
|
-
|
|
103
|
+
if (square === undefined)
|
|
104
|
+
square = await open().catch(() => undefined);
|
|
105
|
+
const fresh = await square?.recovery(name).catch(() => undefined);
|
|
100
106
|
name = fresh?.participant ?? name;
|
|
101
107
|
const output = { squarePath, name, draftPath, participantCount: fresh?.standingCount, held: fresh?.held };
|
|
102
108
|
const confirmedUnsent = landedId === undefined && detail?.landedId === undefined
|
|
103
109
|
&& detail?.expressEffect !== 'landed' && detail?.expressEffect !== 'unknown'
|
|
104
|
-
&& (detail?.expressEffect === 'unsent' || (isSquareError(error) && error.facts?.activityUnsent === true));
|
|
110
|
+
&& (!attempted || detail?.expressEffect === 'unsent' || (isSquareError(error) && error.facts?.activityUnsent === true));
|
|
105
111
|
const retryCommand = activityRetryCommand(squarePath, name, opts);
|
|
106
112
|
const exitCode = (code) => { process.exitCode = controller.signal.aborted ? 130 : code; };
|
|
107
113
|
if (!confirmedUnsent) {
|
|
@@ -154,19 +160,17 @@ export async function executeExpression(application, squarePath, requestedName,
|
|
|
154
160
|
: 'Invalid --reply: expected an activity id like act/12'
|
|
155
161
|
: refusalText(error);
|
|
156
162
|
const lines = [message, `· draft kept: ${draftPath}`];
|
|
157
|
-
const
|
|
158
|
-
const repair = reason === 'bell_mention_conflict' ? { bell: true, fromBody: true }
|
|
159
|
-
: reason === 'not_standing' && recipientFailure ? { bell: false, fromBody: false } : undefined;
|
|
163
|
+
const repair = reason === 'bell_mention_conflict' || (reason === 'not_standing' && detail?.subject === 'recipient');
|
|
160
164
|
if (isSquareError(error)) {
|
|
161
165
|
if ((reason === 'never_joined' && detail?.subject === 'caller') || error.code === 'unknown_participant' || error.code === 'not_joined') {
|
|
162
166
|
lines.push(joinRecoveryCommand(squarePath, name));
|
|
163
167
|
}
|
|
164
168
|
if (error.code === 'already_joined')
|
|
165
169
|
lines.push(...takeoverRecoveryLines(squarePath, name));
|
|
166
|
-
if (repair
|
|
167
|
-
lines.push(participantsRecoveryCommand(squarePath),
|
|
168
|
-
?
|
|
169
|
-
: ' · pick someone standing here, or land it bare:', `${
|
|
170
|
+
if (repair) {
|
|
171
|
+
lines.push(participantsRecoveryCommand(squarePath), reason === 'bell_mention_conflict'
|
|
172
|
+
? ' · ring the bell without explicit mentions:'
|
|
173
|
+
: ' · pick someone standing here, or land it bare:', `${activityRetryCommand(squarePath, name, { ...opts, mentions: [], noMention: opts.reach === 'bell' ? opts.noMention : true })} < ${quoteShell(draftPath)}`);
|
|
170
174
|
}
|
|
171
175
|
else if (error.code === 'invalid_args' || error.code === 'invalid_name') {
|
|
172
176
|
if (opts.mentions?.length)
|
|
@@ -179,11 +183,11 @@ export async function executeExpression(application, squarePath, requestedName,
|
|
|
179
183
|
lines.push(' · choose someone with --mention <name>, or send without addressing anyone:', `${activityRetryCommand(squarePath, name, { ...opts, noMention: true })} < ${quoteShell(draftPath)}`);
|
|
180
184
|
}
|
|
181
185
|
else if (reason === 'invalid_reply') {
|
|
182
|
-
const
|
|
183
|
-
const withoutReply = { ...opts, reply: undefined, ...(
|
|
184
|
-
lines.push(`${commandPrefix(squarePath)} history --limit 10`, ' · choose a valid --reply from history, or send without a reply using this repair:', ...(
|
|
186
|
+
const needsBareReach = facts?.hasReachWithoutReply === false;
|
|
187
|
+
const withoutReply = { ...opts, reply: undefined, ...(needsBareReach ? { noMention: true } : {}) };
|
|
188
|
+
lines.push(`${commandPrefix(squarePath)} history --limit 10`, ' · choose a valid --reply from history, or send without a reply using this repair:', ...(needsBareReach ? [' · this repair is bare; replace --no-mention with --mention <name> to address someone'] : []), `${activityRetryCommand(squarePath, name, withoutReply)} < ${quoteShell(draftPath)}`);
|
|
185
189
|
}
|
|
186
|
-
else if (repair
|
|
190
|
+
else if (!repair) {
|
|
187
191
|
lines.push(' · correct the problem above before retrying; keep your intended recipients and reply:', `${retryCommand} < ${quoteShell(draftPath)}`);
|
|
188
192
|
}
|
|
189
193
|
process.stderr.write(formatRefusal(squarePath, lines, output));
|
|
@@ -191,5 +195,6 @@ export async function executeExpression(application, squarePath, requestedName,
|
|
|
191
195
|
}
|
|
192
196
|
finally {
|
|
193
197
|
process.off('SIGINT', interrupt);
|
|
198
|
+
await square?.close();
|
|
194
199
|
}
|
|
195
200
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { renderDoctorClean, renderDoctorUnfixable, withPathOutput } from '../presentation.js';
|
|
3
|
-
import { requireSquarePath, usage } from './context.js';
|
|
1
|
+
import { diagnoseSquare, migrateSquare } from '../square-api.js';
|
|
2
|
+
import { commandPrefix, renderDoctorClean, renderDoctorUnfixable, withPathOutput } from '../presentation.js';
|
|
3
|
+
import { requireSquarePath, squareInput, usage } from './context.js';
|
|
4
4
|
export const migrateCommand = {
|
|
5
5
|
parse(argv, context) {
|
|
6
6
|
if (argv.length > 0)
|
|
@@ -9,14 +9,14 @@ export const migrateCommand = {
|
|
|
9
9
|
},
|
|
10
10
|
async execute(_intent, context) {
|
|
11
11
|
const squarePath = requireSquarePath(context);
|
|
12
|
-
const
|
|
12
|
+
const outcome = await migrateSquare(squareInput(context));
|
|
13
13
|
const body = outcome.status === 'migrated' && outcome.counts !== undefined
|
|
14
14
|
? [
|
|
15
15
|
'✓ migrated to row storage',
|
|
16
16
|
` · ${outcome.counts.activities} activities · ${outcome.counts.receipts} receipts · ${outcome.counts.leases} leases · ${outcome.counts.routes} routes`,
|
|
17
17
|
].join('\n')
|
|
18
18
|
: '· already format 2 — nothing changed';
|
|
19
|
-
return { output: withPathOutput(squarePath, body, { participantCount:
|
|
19
|
+
return { output: withPathOutput(squarePath, body, { participantCount: outcome.standing }) };
|
|
20
20
|
},
|
|
21
21
|
present(result) {
|
|
22
22
|
process.stdout.write(result.output);
|
|
@@ -30,9 +30,9 @@ export const doctorCommand = {
|
|
|
30
30
|
},
|
|
31
31
|
async execute(_intent, context) {
|
|
32
32
|
const squarePath = requireSquarePath(context);
|
|
33
|
-
const
|
|
33
|
+
const diagnosis = await diagnoseSquare(squareInput(context));
|
|
34
34
|
if (diagnosis.migrationRequired !== undefined) {
|
|
35
|
-
return { output: withPathOutput(squarePath, `${diagnosis.migrationRequired}\n`), exitCode: 2 };
|
|
35
|
+
return { output: withPathOutput(squarePath, `${diagnosis.migrationRequired}\n${commandPrefix(squarePath)} migrate\n`), exitCode: 2 };
|
|
36
36
|
}
|
|
37
37
|
if (diagnosis.unfixable !== undefined || diagnosis.standingCount === undefined) {
|
|
38
38
|
return {
|
|
@@ -42,7 +42,7 @@ export const doctorCommand = {
|
|
|
42
42
|
}
|
|
43
43
|
return {
|
|
44
44
|
output: withPathOutput(squarePath, renderDoctorClean(), {
|
|
45
|
-
participantCount:
|
|
45
|
+
participantCount: diagnosis.standingCount,
|
|
46
46
|
}),
|
|
47
47
|
};
|
|
48
48
|
},
|
|
@@ -7,7 +7,7 @@ export const mcpServerCommand = {
|
|
|
7
7
|
},
|
|
8
8
|
async execute(_intent, context) {
|
|
9
9
|
const { runSquareMcpStdio } = await import('../mcp.js');
|
|
10
|
-
await runSquareMcpStdio({ cwd: context.cwd, env: context.env,
|
|
10
|
+
await runSquareMcpStdio({ cwd: context.cwd, env: context.env, path: context.squarePath, participant: context.name });
|
|
11
11
|
},
|
|
12
12
|
present() { },
|
|
13
13
|
};
|
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { CatchOptions, DiscoveryOptions, HistoryQuery, StreamStart } from '../square-facade.js';
|
|
2
2
|
import { type CommandSpec } from './context.js';
|
|
3
3
|
interface HistoryCommandOptions {
|
|
4
|
-
query:
|
|
4
|
+
query: HistoryQuery;
|
|
5
5
|
noTruncate: boolean;
|
|
6
6
|
format?: string[];
|
|
7
7
|
json: boolean;
|
|
8
8
|
continuationArgs: string[];
|
|
9
9
|
}
|
|
10
|
-
export declare const listCommand: CommandSpec<
|
|
10
|
+
export declare const listCommand: CommandSpec<DiscoveryOptions, string>;
|
|
11
11
|
interface StreamIntent {
|
|
12
12
|
ndjson: boolean;
|
|
13
13
|
forName?: string;
|
|
14
14
|
start: StreamStart;
|
|
15
15
|
}
|
|
16
16
|
export declare const streamCommand: CommandSpec<StreamIntent>;
|
|
17
|
-
export declare const catchCommand: CommandSpec<
|
|
17
|
+
export declare const catchCommand: CommandSpec<CatchOptions>;
|
|
18
18
|
export declare const historyCommand: CommandSpec<HistoryCommandOptions, string>;
|
|
19
19
|
interface ParticipantsCommandOptions {
|
|
20
20
|
limit: number;
|
|
@@ -6,9 +6,9 @@ import { isSquareError, sameName } from '../model.js';
|
|
|
6
6
|
import { commandPrefix, participantIdentity, renderGrepActivitiesView, renderEventCli, renderAmbientEventFacts, renderPresenceAnchor, truncateChars, withPathOutput, quoteShell, } from '../presentation.js';
|
|
7
7
|
import { style } from '../tty-style.js';
|
|
8
8
|
import { formatRelativeTime, formatTimestamp, parseTimeOrRelative } from '../time.js';
|
|
9
|
-
import { 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-
|
|
9
|
+
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
10
|
import { renderCatchOutcome, renderCatchProgress } from './catch-presentation.js';
|
|
11
|
-
import {
|
|
11
|
+
import { withSquare, squareInput, now, fail, parseBoundedLimit, parseDurationMs, parseNameList, parseNonNegativeInteger, readStdin, requireSquarePath, requireValue, usage, } from './context.js';
|
|
12
12
|
const STATUS_PARTICIPANT_PREVIEW_LIMIT = 10;
|
|
13
13
|
const PARTICIPANTS_DEFAULT_LIMIT = 20;
|
|
14
14
|
const PARTICIPANTS_MAX_LIMIT = 100;
|
|
@@ -80,8 +80,8 @@ export const listCommand = {
|
|
|
80
80
|
return { depth, limit, after };
|
|
81
81
|
},
|
|
82
82
|
async execute(intent, context) {
|
|
83
|
-
const
|
|
84
|
-
return renderSquareList(
|
|
83
|
+
const result = await discover(squareInput(context), intent);
|
|
84
|
+
return renderSquareList(result, { now: now(context), depth: intent.depth ?? DEFAULT_LIST_DEPTH, limit: intent.limit ?? DEFAULT_LIST_LIMIT });
|
|
85
85
|
},
|
|
86
86
|
present: (result) => process.stdout.write(result),
|
|
87
87
|
};
|
|
@@ -132,10 +132,12 @@ export const streamCommand = {
|
|
|
132
132
|
const interrupt = () => controller.abort();
|
|
133
133
|
process.once('SIGINT', interrupt);
|
|
134
134
|
try {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
135
|
+
await withSquare(context, async (square) => {
|
|
136
|
+
for await (const record of square.stream({ recipient: intent.forName, start: intent.start }, { signal: controller.signal })) {
|
|
137
|
+
if (!process.stdout.write(`${JSON.stringify(record)}\n`))
|
|
138
|
+
await once(process.stdout, 'drain', { signal: controller.signal });
|
|
139
|
+
}
|
|
140
|
+
}, { signal: controller.signal });
|
|
139
141
|
}
|
|
140
142
|
catch (error) {
|
|
141
143
|
if (controller.signal.aborted)
|
|
@@ -218,14 +220,14 @@ export const catchCommand = {
|
|
|
218
220
|
const interrupt = () => controller.abort();
|
|
219
221
|
process.once('SIGINT', interrupt);
|
|
220
222
|
try {
|
|
221
|
-
const outcome = await
|
|
223
|
+
const outcome = await withSquare(context, async (square) => (await square.participant(context.name)).catch({ ...intent, observe: true }, {
|
|
222
224
|
signal: controller.signal,
|
|
223
225
|
onProgress(progress) {
|
|
224
226
|
const line = renderCatchProgress(squarePath, progress);
|
|
225
227
|
if (line !== undefined)
|
|
226
228
|
process.stderr.write(line);
|
|
227
229
|
},
|
|
228
|
-
});
|
|
230
|
+
}), { signal: controller.signal });
|
|
229
231
|
const rendered = renderCatchOutcome(squarePath, outcome, intent);
|
|
230
232
|
process.stdout.write(rendered.stdout);
|
|
231
233
|
process.exitCode = rendered.exitCode;
|
|
@@ -301,7 +303,7 @@ function parseHistory(argv, context) {
|
|
|
301
303
|
index += 1;
|
|
302
304
|
}
|
|
303
305
|
else if (flag === '--since') {
|
|
304
|
-
since = parseTimestamp(requireValue(argv, index, flag), flag,
|
|
306
|
+
since = parseTimestamp(requireValue(argv, index, flag), flag, now(context));
|
|
305
307
|
index += 1;
|
|
306
308
|
}
|
|
307
309
|
else if (flag === '--after') {
|
|
@@ -446,7 +448,7 @@ export const historyCommand = {
|
|
|
446
448
|
const squarePath = requireSquarePath(context);
|
|
447
449
|
let outcome;
|
|
448
450
|
try {
|
|
449
|
-
outcome = await
|
|
451
|
+
outcome = await withSquare(context, (square) => square.history({ ...options.query, observe: true }));
|
|
450
452
|
}
|
|
451
453
|
catch (error) {
|
|
452
454
|
const bounds = error?.operation?.historyBounds;
|
|
@@ -454,7 +456,7 @@ export const historyCommand = {
|
|
|
454
456
|
fail(`✕ history is capped at ${bounds.maxLimit} activities\n${historyContinuationCommand(options, squarePath, ['--limit', String(bounds.maxLimit)])}`);
|
|
455
457
|
throw error;
|
|
456
458
|
}
|
|
457
|
-
const projection = outcome.
|
|
459
|
+
const projection = outcome.observation;
|
|
458
460
|
const events = projection.activities;
|
|
459
461
|
if (options.json)
|
|
460
462
|
return events.map((item) => jsonLine(projection.sayNumbers, item)).join('\n') + (events.length > 0 ? '\n' : '');
|
|
@@ -488,7 +490,8 @@ export const participantsCommand = {
|
|
|
488
490
|
parse(argv, context) { return parseParticipants(argv, context); },
|
|
489
491
|
async execute(intent, context) {
|
|
490
492
|
const squarePath = requireSquarePath(context);
|
|
491
|
-
const
|
|
493
|
+
const data = await withSquare(context, (square) => square.participants({ observe: true }));
|
|
494
|
+
const projection = data.observation;
|
|
492
495
|
const now = projection.now;
|
|
493
496
|
const participants = data.participants;
|
|
494
497
|
const lines = participants.slice(0, intent.limit).map((participant) => {
|
|
@@ -516,7 +519,8 @@ export const statusCommand = {
|
|
|
516
519
|
usage(context.command); return undefined; },
|
|
517
520
|
async execute(_intent, context) {
|
|
518
521
|
const squarePath = requireSquarePath(context);
|
|
519
|
-
const
|
|
522
|
+
const result = await withSquare(context, (square) => square.status({ viewer: context.name, observe: true }));
|
|
523
|
+
const presentation = result.observation;
|
|
520
524
|
const participantsByName = new Map(result.participants.map((participant) => [participant.name, participant]));
|
|
521
525
|
const orderedHere = presentation.orderedHereNames.map((name) => participantsByName.get(name));
|
|
522
526
|
const lingering = presentation.lingeringCount;
|
|
@@ -639,7 +643,7 @@ export const inboxCommand = {
|
|
|
639
643
|
return { sessionId, json, limit };
|
|
640
644
|
},
|
|
641
645
|
async execute(intent, context) {
|
|
642
|
-
const
|
|
646
|
+
const data = await inbox(squareInput(context), intent.sessionId, { limit: intent.limit });
|
|
643
647
|
const rows = data.rows.map((membership) => ({
|
|
644
648
|
namePreview: inboxDisplay(membership.name),
|
|
645
649
|
squarePathPreview: inboxDisplay(membership.squarePath),
|
package/dist/cli/program.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
/** Parse global flags, select an
|
|
1
|
+
/** Parse global flags, select an adapter, and execute through Square/Participant. */
|
|
2
2
|
export declare function runCli(rawArgs?: string[]): Promise<void>;
|