@astrosheep/square 0.3.95 → 0.3.96
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 +5 -4
- package/dist/attention-presentation.js +18 -8
- package/dist/boundary-presentation.js +17 -8
- package/dist/channel.d.ts +72 -0
- package/dist/channel.js +86 -0
- package/dist/claude-delivery.js +2 -1
- package/dist/delivery.js +2 -2
- package/dist/inbox.js +3 -1
- package/dist/mcp.js +65 -63
- package/dist/model.d.ts +6 -0
- package/dist/model.js +19 -0
- package/dist/ports.d.ts +3 -0
- package/dist/presentation-operations.d.ts +1 -0
- package/dist/sqlite-square.d.ts +3 -1
- package/dist/sqlite-square.js +54 -2
- package/dist/square-core.d.ts +1 -0
- package/dist/square-domain.js +22 -7
- package/dist/square-facade.d.ts +20 -2
- package/dist/square-sqlite.js +12 -3
- package/dist/square-tools.d.ts +1 -0
- package/dist/square-tools.js +9 -1
- package/dist/views.js +1 -0
- package/package.json +5 -1
- package/plugins/claude/.claude-plugin/plugin.json +1 -1
- package/plugins/codex/.codex-plugin/plugin.json +1 -1
- package/plugins/paseo/client/marble.ts +7 -0
- package/plugins/paseo/client/markdown.tsx +65 -9
- package/plugins/paseo/client/palette.ts +43 -20
- package/plugins/paseo/client/square-message.tsx +57 -48
- package/plugins/paseo/shared/message.ts +1 -2
- package/plugins/pi/square-pi.js +6 -4
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { DirectedNotificationRoute } from './model.js';
|
|
1
|
+
import type { ActivityDelivery, DirectedNotificationRoute } from './model.js';
|
|
2
2
|
export declare const ATTENTION_BODY_MAX = 200;
|
|
3
3
|
export interface AttentionPreview {
|
|
4
4
|
squarePath: string;
|
|
@@ -7,13 +7,14 @@ export interface AttentionPreview {
|
|
|
7
7
|
actor: string;
|
|
8
8
|
route: DirectedNotificationRoute;
|
|
9
9
|
body: string;
|
|
10
|
+
delivery?: ActivityDelivery;
|
|
10
11
|
}
|
|
11
|
-
export declare function previewAttentionBody(body: string): string;
|
|
12
|
-
export declare function attentionBodyIsClipped(body: string): boolean;
|
|
12
|
+
export declare function previewAttentionBody(body: string, delivery?: ActivityDelivery): string;
|
|
13
|
+
export declare function attentionBodyIsClipped(body: string, delivery?: ActivityDelivery): boolean;
|
|
13
14
|
export declare function displayAttentionPath(squarePath: string): string;
|
|
14
15
|
export declare function renderAttentionDescription({ actor, route }: Pick<AttentionPreview, 'actor' | 'route'>): string;
|
|
15
16
|
/** Full notification text for human-facing expansion, never the bounded model preview. */
|
|
16
17
|
export declare function renderAttentionFull(attention: AttentionPreview): string;
|
|
17
18
|
/** Shared model-facing envelope; transport correlation and human cards stay outside it. */
|
|
18
|
-
export declare function renderSquareReminder(previews: readonly string[]): string;
|
|
19
|
+
export declare function renderSquareReminder(previews: readonly string[], deliveries?: readonly (ActivityDelivery | undefined)[]): string;
|
|
19
20
|
export declare function renderAttentionPreview(attention: AttentionPreview): string;
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import { homedir } from 'node:os';
|
|
2
2
|
import { formatActivityId } from './square-core.js';
|
|
3
3
|
export const ATTENTION_BODY_MAX = 200;
|
|
4
|
-
export function previewAttentionBody(body) {
|
|
5
|
-
const compact = body.replace(/\r\n/g, '\n');
|
|
6
|
-
if (compact.length <= ATTENTION_BODY_MAX)
|
|
4
|
+
export function previewAttentionBody(body, delivery) {
|
|
5
|
+
const compact = (delivery?.mode === 'direct' ? delivery.preview ?? body : body).replace(/\r\n/g, '\n');
|
|
6
|
+
if (delivery?.mode === 'direct' || compact.length <= ATTENTION_BODY_MAX)
|
|
7
7
|
return compact;
|
|
8
8
|
return `${compact.slice(0, ATTENTION_BODY_MAX).trimEnd()}…`;
|
|
9
9
|
}
|
|
10
|
-
export function attentionBodyIsClipped(body) {
|
|
11
|
-
return
|
|
10
|
+
export function attentionBodyIsClipped(body, delivery) {
|
|
11
|
+
return delivery?.mode === 'direct'
|
|
12
|
+
? delivery.preview !== undefined
|
|
13
|
+
: body.replace(/\r\n/g, '\n').length > ATTENTION_BODY_MAX;
|
|
12
14
|
}
|
|
13
15
|
export function displayAttentionPath(squarePath) {
|
|
14
16
|
return squarePath.startsWith(homedir())
|
|
@@ -25,7 +27,7 @@ export function renderAttentionDescription({ actor, route }) {
|
|
|
25
27
|
}
|
|
26
28
|
/** Full notification text for human-facing expansion, never the bounded model preview. */
|
|
27
29
|
export function renderAttentionFull(attention) {
|
|
28
|
-
return renderAttentionBlock(attention, attention.body);
|
|
30
|
+
return attention.delivery?.mode === 'direct' ? renderDirectBlock(attention) : renderAttentionBlock(attention, attention.body);
|
|
29
31
|
}
|
|
30
32
|
/** Attribute values keep their quotes; the stored body and the human card stay unescaped. */
|
|
31
33
|
function escapeAttribute(value) {
|
|
@@ -49,14 +51,20 @@ function renderAttentionBlock(attention, body) {
|
|
|
49
51
|
'</square-activity>',
|
|
50
52
|
].join('\n');
|
|
51
53
|
}
|
|
54
|
+
function renderDirectBlock(attention) {
|
|
55
|
+
return escapeSquareTags(previewAttentionBody(attention.body, attention.delivery));
|
|
56
|
+
}
|
|
52
57
|
/** Shared model-facing envelope; transport correlation and human cards stay outside it. */
|
|
53
|
-
export function renderSquareReminder(previews) {
|
|
58
|
+
export function renderSquareReminder(previews, deliveries = []) {
|
|
54
59
|
if (previews.length === 0)
|
|
55
60
|
return '';
|
|
61
|
+
const header = deliveries.some(item => item?.mode === 'direct')
|
|
62
|
+
? 'This is an external notification, not a direct message from the user.'
|
|
63
|
+
: 'This is an external reminder from Square, not a direct message from the user.';
|
|
56
64
|
return [
|
|
57
65
|
'',
|
|
58
66
|
'<system-reminder>',
|
|
59
|
-
|
|
67
|
+
header,
|
|
60
68
|
'',
|
|
61
69
|
previews.join('\n\n'),
|
|
62
70
|
'</system-reminder>',
|
|
@@ -64,6 +72,8 @@ export function renderSquareReminder(previews) {
|
|
|
64
72
|
].join('\n');
|
|
65
73
|
}
|
|
66
74
|
export function renderAttentionPreview(attention) {
|
|
75
|
+
if (attention.delivery?.mode === 'direct')
|
|
76
|
+
return renderDirectBlock(attention);
|
|
67
77
|
const remaining = attention.body.replace(/\r\n/g, '\n').length - ATTENTION_BODY_MAX;
|
|
68
78
|
const attributes = [
|
|
69
79
|
`square="${escapeAttribute(displayAttentionPath(attention.squarePath))}"`,
|
|
@@ -14,10 +14,13 @@ export function renderPendingAtBoundary(inbox) {
|
|
|
14
14
|
function renderBoundary(inbox) {
|
|
15
15
|
const queued = inbox.flatMap((membership) => membership.notifications.map((notification) => ({ membership, notification })));
|
|
16
16
|
const blocks = [];
|
|
17
|
+
const agoraBlocks = [];
|
|
18
|
+
const deliveries = [];
|
|
19
|
+
let remainingAgora = queued.filter(({ notification }) => notification.delivery?.mode !== 'direct').length;
|
|
17
20
|
const complete = [];
|
|
18
21
|
let omitted = 0;
|
|
19
22
|
const omission = (count) => `${count} more ${count === 1 ? 'activity' : 'activities'} not shown.`;
|
|
20
|
-
for (const
|
|
23
|
+
for (const entry of queued) {
|
|
21
24
|
const { membership, notification } = entry;
|
|
22
25
|
const block = [
|
|
23
26
|
renderAttentionPreview({
|
|
@@ -27,23 +30,29 @@ function renderBoundary(inbox) {
|
|
|
27
30
|
actor: notification.actor,
|
|
28
31
|
route: notification.route,
|
|
29
32
|
body: notification.body,
|
|
33
|
+
delivery: notification.delivery,
|
|
30
34
|
}),
|
|
31
35
|
].join('\n');
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
36
|
+
if (notification.delivery?.mode !== 'direct') {
|
|
37
|
+
remainingAgora -= 1;
|
|
38
|
+
const omittedAfter = omitted + remainingAgora;
|
|
39
|
+
const prospective = renderSquareReminder([...agoraBlocks, block, ...(omittedAfter > 0 ? [omission(omittedAfter)] : [])]);
|
|
40
|
+
if (prospective.length > CONTEXT_MAX) {
|
|
41
|
+
omitted += 1;
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
agoraBlocks.push(block);
|
|
37
45
|
}
|
|
38
46
|
blocks.push(block);
|
|
47
|
+
deliveries.push(notification.delivery);
|
|
39
48
|
complete.push({
|
|
40
49
|
membership,
|
|
41
50
|
actIndexes: [notification.actIndex],
|
|
42
|
-
markSeen: !attentionBodyIsClipped(notification.body),
|
|
51
|
+
markSeen: !attentionBodyIsClipped(notification.body, notification.delivery),
|
|
43
52
|
});
|
|
44
53
|
}
|
|
45
54
|
return {
|
|
46
|
-
context: renderSquareReminder([...blocks, ...(omitted > 0 ? [omission(omitted)] : [])]),
|
|
55
|
+
context: renderSquareReminder([...blocks, ...(omitted > 0 ? [omission(omitted)] : [])], deliveries),
|
|
47
56
|
complete,
|
|
48
57
|
};
|
|
49
58
|
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { type HarnessSessionChannel } from './participant-identity.js';
|
|
2
|
+
import type { SquareResourceOwner, WakeTransportPort } from './ports.js';
|
|
3
|
+
import type { ActivityId, ChannelSendInput, ChannelSendResult, DeliveryDeferral, HeldSeat, MetadataMatch, OperationControl, Owner, Participant, WakeAddress } from './square-facade.js';
|
|
4
|
+
export { harnessOwner, decodeHarnessOwner, localUserOwner } from './owner.js';
|
|
5
|
+
export type { ActivityDelivery, ActivityMetadata, ChannelTruncate } from './square-facade.js';
|
|
6
|
+
export type { ActivityId, ChannelSendInput, ChannelSendResult, DeliveryDeferral, HeldSeat, MetadataMatch, OperationControl, Owner, WakeAddress, SquareResourceOwner, WakeTransportPort, HarnessSessionChannel };
|
|
7
|
+
export interface ResolvedHarnessSession {
|
|
8
|
+
readonly channel: HarnessSessionChannel;
|
|
9
|
+
readonly sessionId: string;
|
|
10
|
+
readonly agentId?: string;
|
|
11
|
+
readonly owner: Owner;
|
|
12
|
+
readonly wakeAddress?: WakeAddress;
|
|
13
|
+
}
|
|
14
|
+
export declare function resolveHarnessSession(env?: NodeJS.ProcessEnv): ResolvedHarnessSession | undefined;
|
|
15
|
+
export interface ChannelOpenInput {
|
|
16
|
+
readonly path: string;
|
|
17
|
+
readonly cwd?: string;
|
|
18
|
+
readonly env?: NodeJS.ProcessEnv;
|
|
19
|
+
readonly clock?: () => number;
|
|
20
|
+
readonly wakeTransport?: WakeTransportPort | false;
|
|
21
|
+
readonly resources?: SquareResourceOwner;
|
|
22
|
+
}
|
|
23
|
+
export interface ChannelCreateInput extends ChannelOpenInput {
|
|
24
|
+
readonly force?: boolean;
|
|
25
|
+
readonly description?: string;
|
|
26
|
+
}
|
|
27
|
+
type EndpointOptions = {
|
|
28
|
+
readonly owner: Owner;
|
|
29
|
+
readonly wakeAddress?: WakeAddress;
|
|
30
|
+
};
|
|
31
|
+
type EndpointIdentity = {
|
|
32
|
+
readonly owner: Owner;
|
|
33
|
+
readonly generation: ActivityId;
|
|
34
|
+
};
|
|
35
|
+
/** A scoped direct-messaging vocabulary over the shared Square resource. */
|
|
36
|
+
export declare class Channel {
|
|
37
|
+
private readonly square;
|
|
38
|
+
private constructor();
|
|
39
|
+
get location(): string;
|
|
40
|
+
static open(input: ChannelOpenInput, control?: OperationControl): Promise<Channel>;
|
|
41
|
+
static create(input: ChannelCreateInput, control?: OperationControl): Promise<Channel>;
|
|
42
|
+
static inMemory(input?: Omit<ChannelCreateInput, 'path' | 'resources' | 'force'>): Channel;
|
|
43
|
+
attach(name: string, options: EndpointOptions & {
|
|
44
|
+
readonly takeover?: boolean;
|
|
45
|
+
}, control?: OperationControl): Promise<ChannelEndpoint>;
|
|
46
|
+
reattach(name: string, options: EndpointOptions, control?: OperationControl): Promise<ChannelEndpoint | null>;
|
|
47
|
+
endpoint(name: string, options: {
|
|
48
|
+
readonly owner: Owner;
|
|
49
|
+
}): Promise<ChannelEndpoint>;
|
|
50
|
+
endpointsOf(owner: Owner): Promise<readonly HeldSeat[]>;
|
|
51
|
+
detach(name: string, identity: EndpointIdentity): Promise<true | null>;
|
|
52
|
+
remove(name: string, identity: EndpointIdentity): Promise<boolean>;
|
|
53
|
+
cancelDeliveries(name: string, identity: EndpointIdentity): Promise<boolean>;
|
|
54
|
+
send(input: ChannelSendInput, control?: OperationControl): Promise<ChannelSendResult>;
|
|
55
|
+
close(): Promise<void>;
|
|
56
|
+
}
|
|
57
|
+
/** Captures one recipient generation through its existing Participant handle. */
|
|
58
|
+
export declare class ChannelEndpoint {
|
|
59
|
+
private readonly channel;
|
|
60
|
+
private readonly participant;
|
|
61
|
+
constructor(channel: Channel, participant: Participant);
|
|
62
|
+
get name(): string;
|
|
63
|
+
get generation(): ActivityId;
|
|
64
|
+
leave(control?: OperationControl): Promise<void>;
|
|
65
|
+
deferDelivery(input: Readonly<{
|
|
66
|
+
match: MetadataMatch;
|
|
67
|
+
durationMs: number;
|
|
68
|
+
}>, control?: OperationControl): Promise<DeliveryDeferral>;
|
|
69
|
+
renewDeliveryDeferral(id: string, durationMs: number, control?: OperationControl): Promise<DeliveryDeferral | null>;
|
|
70
|
+
releaseDeliveryDeferral(id: string, control?: OperationControl): Promise<boolean>;
|
|
71
|
+
send(input: Omit<ChannelSendInput, 'from'>, control?: OperationControl): Promise<ChannelSendResult>;
|
|
72
|
+
}
|
package/dist/channel.js
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { codexWakeAddress } from './codex-address.js';
|
|
2
|
+
import { SquareError } from './model.js';
|
|
3
|
+
import { harnessOwner } from './owner.js';
|
|
4
|
+
import { harnessSessionSources } from './participant-identity.js';
|
|
5
|
+
import { Square } from './square-api.js';
|
|
6
|
+
import { squareLocation } from './square-location.js';
|
|
7
|
+
export { harnessOwner, decodeHarnessOwner, localUserOwner } from './owner.js';
|
|
8
|
+
export function resolveHarnessSession(env = process.env) {
|
|
9
|
+
for (const { variable, channel } of harnessSessionSources) {
|
|
10
|
+
const sessionId = env[variable]?.trim();
|
|
11
|
+
if (!sessionId)
|
|
12
|
+
continue;
|
|
13
|
+
const agentId = channel === 'claude-code' && env.CLAUDE_CODE_CHILD_SESSION?.trim() === '1'
|
|
14
|
+
? env.CLAUDE_CODE_AGENT_ID?.trim() || undefined : undefined;
|
|
15
|
+
const wakeAddress = channel === 'codex' ? codexWakeAddress(sessionId, env)
|
|
16
|
+
: channel === 'paseo' ? { kind: 'paseo', address: { agentId: sessionId } } : undefined;
|
|
17
|
+
return { channel, sessionId, ...(agentId === undefined ? {} : { agentId }),
|
|
18
|
+
owner: harnessOwner({ channel, session: sessionId, ...(agentId === undefined ? {} : { agent: agentId }) }),
|
|
19
|
+
...(wakeAddress === undefined ? {} : { wakeAddress }) };
|
|
20
|
+
}
|
|
21
|
+
return undefined;
|
|
22
|
+
}
|
|
23
|
+
function explicitLocation(input) {
|
|
24
|
+
if (typeof input?.path !== 'string' || input.path.trim() === '')
|
|
25
|
+
throw new SquareError('invalid_args', 'Channel path is required.');
|
|
26
|
+
return squareLocation(input);
|
|
27
|
+
}
|
|
28
|
+
/** A scoped direct-messaging vocabulary over the shared Square resource. */
|
|
29
|
+
export class Channel {
|
|
30
|
+
square;
|
|
31
|
+
constructor(square) {
|
|
32
|
+
this.square = square;
|
|
33
|
+
}
|
|
34
|
+
get location() { return this.square.location; }
|
|
35
|
+
static async open(input, control) {
|
|
36
|
+
const path = explicitLocation(input);
|
|
37
|
+
return new Channel(await Square.at({ ...input, path }, control));
|
|
38
|
+
}
|
|
39
|
+
static async create(input, control) {
|
|
40
|
+
const path = explicitLocation(input);
|
|
41
|
+
return new Channel(await Square.build({ ...input, path, hardCap: null, markdown: input.description ?? '# Channel\n' }, control));
|
|
42
|
+
}
|
|
43
|
+
static inMemory(input = {}) {
|
|
44
|
+
return new Channel(Square.inMemory({ ...input, hardCap: null, markdown: input.description ?? '# Channel\n' }));
|
|
45
|
+
}
|
|
46
|
+
async attach(name, options, control) {
|
|
47
|
+
return new ChannelEndpoint(this, (await this.square.join(name, options, control)).participant);
|
|
48
|
+
}
|
|
49
|
+
async reattach(name, options, control) {
|
|
50
|
+
const participant = await this.square.reattach(name, options, control);
|
|
51
|
+
return participant === null ? null : new ChannelEndpoint(this, participant);
|
|
52
|
+
}
|
|
53
|
+
async endpoint(name, options) {
|
|
54
|
+
return new ChannelEndpoint(this, await this.square.participant(name, options));
|
|
55
|
+
}
|
|
56
|
+
endpointsOf(owner) { return this.square.seatsOf(owner); }
|
|
57
|
+
detach(name, identity) { return this.square.detach(name, identity); }
|
|
58
|
+
async remove(name, identity) { return await this.square.endHeld(name, identity) !== null; }
|
|
59
|
+
cancelDeliveries(name, identity) { return this.square.cancelDeliveries(name, identity); }
|
|
60
|
+
send(input, control) { return this.square.send(input, control); }
|
|
61
|
+
close() { return this.square.close(); }
|
|
62
|
+
}
|
|
63
|
+
/** Captures one recipient generation through its existing Participant handle. */
|
|
64
|
+
export class ChannelEndpoint {
|
|
65
|
+
channel;
|
|
66
|
+
participant;
|
|
67
|
+
constructor(channel, participant) {
|
|
68
|
+
this.channel = channel;
|
|
69
|
+
this.participant = participant;
|
|
70
|
+
}
|
|
71
|
+
get name() { return this.participant.name; }
|
|
72
|
+
get generation() { return this.participant.generation; }
|
|
73
|
+
async leave(control) { await this.participant.done(undefined, {}, control); }
|
|
74
|
+
deferDelivery(input, control) {
|
|
75
|
+
return this.participant.deferDelivery(input, control);
|
|
76
|
+
}
|
|
77
|
+
renewDeliveryDeferral(id, durationMs, control) {
|
|
78
|
+
return this.participant.renewDeliveryDeferral(id, durationMs, control);
|
|
79
|
+
}
|
|
80
|
+
releaseDeliveryDeferral(id, control) {
|
|
81
|
+
return this.participant.releaseDeliveryDeferral(id, control);
|
|
82
|
+
}
|
|
83
|
+
send(input, control) {
|
|
84
|
+
return this.channel.send({ ...input, from: this.name }, control);
|
|
85
|
+
}
|
|
86
|
+
}
|
package/dist/claude-delivery.js
CHANGED
|
@@ -150,7 +150,8 @@ export async function observeClaudeDelivery(sessionId, text, operation, env = pr
|
|
|
150
150
|
return { recognized, current: false };
|
|
151
151
|
if (operation === 'stored')
|
|
152
152
|
await presentPending({ artifact: row.artifact, location: request.location,
|
|
153
|
-
|
|
153
|
+
// Claude's stored event consumes even Agora previews; retain that contract for both modes.
|
|
154
|
+
participant: request.participant, activity: request.activity, seat: request.seat, markSeen: true, sink: { present() { } },
|
|
154
155
|
current: facts => currentPayload(facts, request) === payload });
|
|
155
156
|
}
|
|
156
157
|
return { recognized, current: true };
|
package/dist/delivery.js
CHANGED
|
@@ -14,8 +14,8 @@ export function wakePreview(facts, request) {
|
|
|
14
14
|
return undefined;
|
|
15
15
|
return renderSquareReminder([renderAttentionPreview({
|
|
16
16
|
squarePath: request.location, recipient: request.participant, actIndex: item.index,
|
|
17
|
-
actor: item.actor, route: head.route, body: item.body ?? '(structured activity)',
|
|
18
|
-
})]);
|
|
17
|
+
actor: item.actor, route: head.route, body: item.body ?? '(structured activity)', delivery: item.delivery,
|
|
18
|
+
})], [item.delivery]);
|
|
19
19
|
}
|
|
20
20
|
function custody(evidence) {
|
|
21
21
|
return evidence.map(row => ({ purpose: row.kind === 'wake' ? 'dispatch' : 'presentation', outcome: row.outcome, expiresAt: row.expiresAt }));
|
package/dist/inbox.js
CHANGED
|
@@ -149,6 +149,7 @@ async function projectPending(candidates, cache, signal) {
|
|
|
149
149
|
cached = { coordinate, version: header.revision, value: locatedSeats(facts, location, seats).map(membership => ({
|
|
150
150
|
...membership, notifications: pendingNotifications(facts, membership.seat.participant).map(({ item, route }) => ({
|
|
151
151
|
actIndex: item.index, actor: item.actor, at: item.at, body: item.body ?? '(structured activity)', route,
|
|
152
|
+
...(item.delivery === undefined ? {} : { delivery: item.delivery }),
|
|
152
153
|
})),
|
|
153
154
|
})) };
|
|
154
155
|
}
|
|
@@ -197,7 +198,8 @@ export function nativePendingPreview(facts, input) {
|
|
|
197
198
|
if (item?.kind !== 'say' || deliveryDeferralExpiry(facts, seat, input.actIndex, input.now) !== undefined)
|
|
198
199
|
return undefined;
|
|
199
200
|
return { payload: renderSquareReminder([renderAttentionPreview({ squarePath: input.location, recipient: input.participant, actIndex: item.index,
|
|
200
|
-
actor: item.actor, route: head.route, body: item.body ?? '(structured activity)' })]
|
|
201
|
+
actor: item.actor, route: head.route, body: item.body ?? '(structured activity)', delivery: item.delivery })], [item.delivery]),
|
|
202
|
+
clipped: attentionBodyIsClipped(item.body ?? '(structured activity)', item.delivery) };
|
|
201
203
|
}
|
|
202
204
|
export async function sessionInbox(owner, env = process.env, signal) {
|
|
203
205
|
return projectPending(await projectSessionCandidates({ owner, env }), undefined, signal);
|
package/dist/mcp.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
2
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
3
|
-
import { SQUARE_TOOLS, SQUARE_TOOL_INSTRUCTIONS, squareToolFailure, squareToolFailureText } from './square-tools.js';
|
|
3
|
+
import { SQUARE_TOOLS, SQUARE_TOOL_INSTRUCTIONS, squareToolsEnabled, squareToolFailure, squareToolFailureText } from './square-tools.js';
|
|
4
4
|
import { operationEnv } from './participant-identity.js';
|
|
5
5
|
import { codexWakeAddress } from './codex-address.js';
|
|
6
6
|
import { readClaudeMcpCall } from './claude-mcp-context.js';
|
|
@@ -10,76 +10,78 @@ import { harnessOwner } from './square-api.js';
|
|
|
10
10
|
export function createSquareMcpServer(options) {
|
|
11
11
|
const { owner: configuredOwner, wakeAddress, ...resourceOptions } = options;
|
|
12
12
|
const baseEnv = { ...(resourceOptions.env ?? process.env) };
|
|
13
|
+
const toolsEnabled = squareToolsEnabled(baseEnv);
|
|
13
14
|
const resources = createSquareResourceOwner();
|
|
14
15
|
// Calls to the configured square borrow one server-owned connection.
|
|
15
16
|
const inFlight = new Set();
|
|
16
17
|
const server = new McpServer({ name: 'square', version: SQUARE_IDENTITY.packageVersion }, {
|
|
17
|
-
instructions: SQUARE_TOOL_INSTRUCTIONS,
|
|
18
|
+
...(toolsEnabled ? { instructions: SQUARE_TOOL_INSTRUCTIONS } : {}),
|
|
18
19
|
});
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
const { location } = args;
|
|
25
|
-
const threadId = extra._meta?.threadId;
|
|
26
|
-
const opencodeSessionId = extra._meta?.['ai.opencode/sessionID'];
|
|
27
|
-
// Claude's plugin endpoint requires the mod's call-local coordinate, never startup identity.
|
|
28
|
-
const claude = baseEnv.SQUARE_CLAUDE_MCP_CONTEXT === '1'
|
|
29
|
-
? await readClaudeMcpCall(extra._meta?.['claudecode/toolUseId'], baseEnv)
|
|
30
|
-
: undefined;
|
|
31
|
-
const owner = claude !== undefined
|
|
32
|
-
? harnessOwner({ channel: 'claude-code', session: claude.sessionId, ...(claude.agentId === undefined ? {} : { agent: claude.agentId }) })
|
|
33
|
-
: typeof threadId === 'string' && threadId.trim()
|
|
34
|
-
? harnessOwner({ channel: 'codex', session: threadId })
|
|
35
|
-
: typeof opencodeSessionId === 'string' && opencodeSessionId.trim()
|
|
36
|
-
? harnessOwner({ channel: 'opencode', session: opencodeSessionId })
|
|
37
|
-
: configuredOwner;
|
|
38
|
-
const env = claude !== undefined
|
|
39
|
-
? { ...operationEnv('claude', claude.sessionId, baseEnv),
|
|
40
|
-
// Preserve Claude's session + child flag semantics; an agent loop ID is not a session ID.
|
|
41
|
-
CLAUDE_CODE_CHILD_SESSION: claude.agentId === undefined ? '' : '1' }
|
|
42
|
-
: typeof threadId === 'string' && threadId.trim()
|
|
43
|
-
? operationEnv('codex', threadId, baseEnv)
|
|
44
|
-
: typeof opencodeSessionId === 'string' && opencodeSessionId.trim()
|
|
45
|
-
? operationEnv('opencode', opencodeSessionId, baseEnv)
|
|
46
|
-
: baseEnv;
|
|
47
|
-
square = await Square.at({
|
|
48
|
-
...resourceOptions, env, cwd: claude?.cwd ?? resourceOptions.cwd,
|
|
49
|
-
path: location ?? options.path,
|
|
50
|
-
// The server owner is bound to its configured square; overrides close after each call.
|
|
51
|
-
resources: location === undefined && claude === undefined ? resources : undefined,
|
|
52
|
-
}, { signal: extra.signal });
|
|
53
|
-
const callWake = wakeAddress !== undefined && (owner === configuredOwner
|
|
54
|
-
|| wakeAddress.kind === 'paseo' && wakeAddress.address.agentId === baseEnv.PASEO_AGENT_ID
|
|
55
|
-
|| wakeAddress.kind === 'claude-native' && wakeAddress.address.sessionId === claude?.sessionId
|
|
56
|
-
|| wakeAddress.kind === 'opencode-server' && wakeAddress.address.sessionId === opencodeSessionId)
|
|
57
|
-
? wakeAddress : undefined;
|
|
58
|
-
let text;
|
|
20
|
+
if (toolsEnabled)
|
|
21
|
+
for (const tool of SQUARE_TOOLS) {
|
|
22
|
+
server.registerTool(tool.name, { description: tool.description, inputSchema: tool.inputSchema }, (args, extra) => {
|
|
23
|
+
const call = (async () => {
|
|
24
|
+
let square;
|
|
59
25
|
try {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
26
|
+
const { location } = args;
|
|
27
|
+
const threadId = extra._meta?.threadId;
|
|
28
|
+
const opencodeSessionId = extra._meta?.['ai.opencode/sessionID'];
|
|
29
|
+
// Claude's plugin endpoint requires the mod's call-local coordinate, never startup identity.
|
|
30
|
+
const claude = baseEnv.SQUARE_CLAUDE_MCP_CONTEXT === '1'
|
|
31
|
+
? await readClaudeMcpCall(extra._meta?.['claudecode/toolUseId'], baseEnv)
|
|
32
|
+
: undefined;
|
|
33
|
+
const owner = claude !== undefined
|
|
34
|
+
? harnessOwner({ channel: 'claude-code', session: claude.sessionId, ...(claude.agentId === undefined ? {} : { agent: claude.agentId }) })
|
|
35
|
+
: typeof threadId === 'string' && threadId.trim()
|
|
36
|
+
? harnessOwner({ channel: 'codex', session: threadId })
|
|
37
|
+
: typeof opencodeSessionId === 'string' && opencodeSessionId.trim()
|
|
38
|
+
? harnessOwner({ channel: 'opencode', session: opencodeSessionId })
|
|
39
|
+
: configuredOwner;
|
|
40
|
+
const env = claude !== undefined
|
|
41
|
+
? { ...operationEnv('claude', claude.sessionId, baseEnv),
|
|
42
|
+
// Preserve Claude's session + child flag semantics; an agent loop ID is not a session ID.
|
|
43
|
+
CLAUDE_CODE_CHILD_SESSION: claude.agentId === undefined ? '' : '1' }
|
|
44
|
+
: typeof threadId === 'string' && threadId.trim()
|
|
45
|
+
? operationEnv('codex', threadId, baseEnv)
|
|
46
|
+
: typeof opencodeSessionId === 'string' && opencodeSessionId.trim()
|
|
47
|
+
? operationEnv('opencode', opencodeSessionId, baseEnv)
|
|
48
|
+
: baseEnv;
|
|
49
|
+
square = await Square.at({
|
|
50
|
+
...resourceOptions, env, cwd: claude?.cwd ?? resourceOptions.cwd,
|
|
51
|
+
path: location ?? options.path,
|
|
52
|
+
// The server owner is bound to its configured square; overrides close after each call.
|
|
53
|
+
resources: location === undefined && claude === undefined ? resources : undefined,
|
|
54
|
+
}, { signal: extra.signal });
|
|
55
|
+
const callWake = wakeAddress !== undefined && (owner === configuredOwner
|
|
56
|
+
|| wakeAddress.kind === 'paseo' && wakeAddress.address.agentId === baseEnv.PASEO_AGENT_ID
|
|
57
|
+
|| wakeAddress.kind === 'claude-native' && wakeAddress.address.sessionId === claude?.sessionId
|
|
58
|
+
|| wakeAddress.kind === 'opencode-server' && wakeAddress.address.sessionId === opencodeSessionId)
|
|
59
|
+
? wakeAddress : undefined;
|
|
60
|
+
let text;
|
|
61
|
+
try {
|
|
62
|
+
text = await tool.run(square, args, { signal: extra.signal }, {
|
|
63
|
+
owner, wakeAddress: claude === undefined && typeof threadId === 'string' && threadId.trim()
|
|
64
|
+
? codexWakeAddress(threadId, env) : callWake,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
finally {
|
|
68
|
+
await square.close();
|
|
69
|
+
}
|
|
70
|
+
return { content: [{ type: 'text', text }] };
|
|
64
71
|
}
|
|
65
|
-
|
|
66
|
-
|
|
72
|
+
catch (error) {
|
|
73
|
+
const failure = squareToolFailure(error, extra.signal);
|
|
74
|
+
const participant = args.as;
|
|
75
|
+
return { isError: true, content: [{ type: 'text', text: squareToolFailureText(failure, {
|
|
76
|
+
location: square?.location ?? options.path,
|
|
77
|
+
participant: typeof participant === 'string' ? participant : undefined,
|
|
78
|
+
}) }] };
|
|
67
79
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
return { isError: true, content: [{ type: 'text', text: squareToolFailureText(failure, {
|
|
74
|
-
location: square?.location ?? options.path,
|
|
75
|
-
participant: typeof participant === 'string' ? participant : undefined,
|
|
76
|
-
}) }] };
|
|
77
|
-
}
|
|
78
|
-
})();
|
|
79
|
-
inFlight.add(call);
|
|
80
|
-
return call.finally(() => { inFlight.delete(call); });
|
|
81
|
-
});
|
|
82
|
-
}
|
|
80
|
+
})();
|
|
81
|
+
inFlight.add(call);
|
|
82
|
+
return call.finally(() => { inFlight.delete(call); });
|
|
83
|
+
});
|
|
84
|
+
}
|
|
83
85
|
const close = server.close.bind(server);
|
|
84
86
|
// One idempotent shutdown for both close paths: an explicit server.close() and a
|
|
85
87
|
// transport-initiated disconnect, where the SDK protocol fires onclose by itself.
|
package/dist/model.d.ts
CHANGED
|
@@ -7,6 +7,11 @@ export type JsonValue = null | boolean | number | string | readonly JsonValue[]
|
|
|
7
7
|
readonly [key: string]: JsonValue;
|
|
8
8
|
};
|
|
9
9
|
export type ActivityMetadata = Readonly<Record<string, JsonValue>>;
|
|
10
|
+
export interface ActivityDelivery {
|
|
11
|
+
readonly mode: 'direct';
|
|
12
|
+
readonly preview?: string;
|
|
13
|
+
}
|
|
14
|
+
export declare function validateActivityDelivery(value: unknown): ActivityDelivery | undefined;
|
|
10
15
|
export declare const ACTIVITY_METADATA_MAX_BYTES: number;
|
|
11
16
|
export declare const ACTIVITY_METADATA_MAX_DEPTH = 256;
|
|
12
17
|
/** Validate the bounded, lossless JSON object carried by a say. */
|
|
@@ -105,6 +110,7 @@ export interface InboxNotification {
|
|
|
105
110
|
at: number;
|
|
106
111
|
route: DirectedNotificationRoute;
|
|
107
112
|
body: string;
|
|
113
|
+
readonly delivery?: ActivityDelivery;
|
|
108
114
|
}
|
|
109
115
|
export interface LocatedSeat {
|
|
110
116
|
readonly location: string;
|
package/dist/model.js
CHANGED
|
@@ -1,6 +1,25 @@
|
|
|
1
1
|
// Shared model and constants for Square.
|
|
2
2
|
export { formatActivityId, parseActivityId } from './square-core.js';
|
|
3
3
|
export const WAKE_ROUTE_KINDS = ['opencode-server', 'codex-queue', 'claude-native', 'paseo', 'http'];
|
|
4
|
+
export function validateActivityDelivery(value) {
|
|
5
|
+
if (value === undefined)
|
|
6
|
+
return undefined;
|
|
7
|
+
if (value !== null && typeof value === 'object'
|
|
8
|
+
&& [Object.prototype, null].includes(Object.getPrototypeOf(value))
|
|
9
|
+
&& Object.getOwnPropertySymbols(value).length === 0) {
|
|
10
|
+
const keys = Object.getOwnPropertyNames(value);
|
|
11
|
+
const mode = Object.getOwnPropertyDescriptor(value, 'mode');
|
|
12
|
+
const preview = Object.getOwnPropertyDescriptor(value, 'preview');
|
|
13
|
+
if (mode?.enumerable && 'value' in mode && mode.value === 'direct') {
|
|
14
|
+
if (keys.length === 1)
|
|
15
|
+
return { mode: 'direct' };
|
|
16
|
+
if (keys.length === 2 && preview?.enumerable && 'value' in preview
|
|
17
|
+
&& typeof preview.value === 'string' && preview.value.trim() !== '')
|
|
18
|
+
return { mode: 'direct', preview: preview.value };
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
throw new SquareError('invalid_args', "Activity delivery must be { mode: 'direct', preview?: string }.");
|
|
22
|
+
}
|
|
4
23
|
export const ACTIVITY_METADATA_MAX_BYTES = 16 * 1024;
|
|
5
24
|
export const ACTIVITY_METADATA_MAX_DEPTH = 256;
|
|
6
25
|
/** Validate the bounded, lossless JSON object carried by a say. */
|
package/dist/ports.d.ts
CHANGED
|
@@ -84,6 +84,9 @@ export interface ReceiptAssignment {
|
|
|
84
84
|
}
|
|
85
85
|
export type SeatRef = Pick<Seat, 'participant' | 'owner' | 'generation'>;
|
|
86
86
|
export type ArtifactWriteAuthority = {
|
|
87
|
+
readonly kind: 'send';
|
|
88
|
+
readonly actor: string;
|
|
89
|
+
} | {
|
|
87
90
|
readonly kind: 'participant';
|
|
88
91
|
readonly seat: SeatRef;
|
|
89
92
|
} | {
|
|
@@ -6,6 +6,7 @@ export declare function preparePendingPresentation(input: Omit<PresentPendingInp
|
|
|
6
6
|
at?: number;
|
|
7
7
|
body?: string;
|
|
8
8
|
metadata?: import("./model.js").ActivityMetadata;
|
|
9
|
+
delivery?: import("./model.js").ActivityDelivery;
|
|
9
10
|
mentions?: readonly import("./square-core.js").Participant[];
|
|
10
11
|
reach?: import("./square-core.js").Reach;
|
|
11
12
|
reply?: number;
|
package/dist/sqlite-square.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type Owner } from './model.js';
|
|
2
|
-
import type { HistoryQuery, HistoryResult, JoinOptions, JoinResult, LifecycleResult, ObservationOptions, OperationControl, Participant, SquareAtInput, SquareBuildInput, SquareLocation, StatusOptions, StatusResult, ParticipantsResult, RecoveryResult, DiscoveryOptions, InboxOptions, InboxResult, StreamOptions, StreamRecord, Activity, PerceivedActivity } from './square-facade.js';
|
|
2
|
+
import type { HistoryQuery, HistoryResult, JoinOptions, JoinResult, LifecycleResult, ObservationOptions, OperationControl, Participant, SquareAtInput, SquareBuildInput, SquareLocation, StatusOptions, StatusResult, ParticipantsResult, RecoveryResult, DiscoveryOptions, InboxOptions, InboxResult, StreamOptions, StreamRecord, Activity, PerceivedActivity, ChannelSendInput, ChannelSendResult } from './square-facade.js';
|
|
3
3
|
export type * from './square-facade.js';
|
|
4
4
|
export { createSquareResourceOwner } from './artifact.js';
|
|
5
5
|
export { formatActivityId, parseActivityId, MAX_IDENTITY_SET_SIZE } from './square-core.js';
|
|
@@ -26,6 +26,8 @@ export declare class SqliteSquare {
|
|
|
26
26
|
private contextObservation;
|
|
27
27
|
private handle;
|
|
28
28
|
private static readonly ParticipantHandle;
|
|
29
|
+
/** Direct messages use explicit recipients, not participant expression admission or body attention. */
|
|
30
|
+
send(input: ChannelSendInput, control?: OperationControl): Promise<ChannelSendResult>;
|
|
29
31
|
participant(name: string, { owner }: {
|
|
30
32
|
readonly owner: Owner;
|
|
31
33
|
}): Promise<Participant>;
|