@astrosheep/square 0.3.93 → 0.3.95
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/activity-feed.d.ts +3 -5
- package/dist/activity-feed.js +16 -14
- package/dist/artifact.js +3 -3
- package/dist/attention.d.ts +19 -0
- package/dist/attention.js +30 -0
- package/dist/boundary-presentation.d.ts +2 -2
- package/dist/boundary-presentation.js +33 -40
- package/dist/catch-decisions.d.ts +5 -8
- package/dist/catch-decisions.js +45 -25
- package/dist/claude-delivery-status.js +10 -4
- package/dist/claude-delivery.js +19 -11
- package/dist/claude-mod.js +24 -53
- package/dist/cli/context.d.ts +9 -4
- package/dist/cli/context.js +30 -27
- package/dist/cli/express-presentation.d.ts +3 -1
- package/dist/cli/express-presentation.js +28 -16
- package/dist/cli/json.d.ts +3 -0
- package/dist/cli/json.js +14 -0
- package/dist/cli/mcp-server-command.js +2 -2
- package/dist/cli/observation-commands.d.ts +1 -3
- package/dist/cli/observation-commands.js +43 -56
- package/dist/cli/program.js +3 -3
- package/dist/cli/registry.js +7 -6
- package/dist/cli/square-commands.d.ts +0 -2
- package/dist/cli/square-commands.js +30 -44
- package/dist/codex-hook.d.ts +3 -2
- package/dist/codex-hook.js +13 -4
- package/dist/codex-queue.js +4 -4
- package/dist/decisions.d.ts +5 -16
- package/dist/decisions.js +9 -33
- package/dist/delivery-attempts.d.ts +52 -0
- package/dist/delivery-attempts.js +73 -0
- package/dist/delivery-deferral.js +2 -2
- package/dist/delivery-effects.d.ts +139 -0
- package/dist/delivery-effects.js +163 -0
- package/dist/delivery-health.d.ts +0 -1
- package/dist/delivery-health.js +1 -3
- package/dist/delivery-operations.d.ts +2 -2
- package/dist/delivery-operations.js +76 -101
- package/dist/delivery-primitives.d.ts +5 -0
- package/dist/delivery-primitives.js +3 -0
- package/dist/delivery.d.ts +1 -1
- package/dist/delivery.js +7 -6
- package/dist/help.js +14 -14
- package/dist/http-delivery.d.ts +16 -0
- package/dist/http-delivery.js +101 -0
- package/dist/inbox.d.ts +9 -22
- package/dist/inbox.js +23 -27
- package/dist/index.d.ts +1 -3
- package/dist/index.js +1 -1
- package/dist/mcp.d.ts +3 -0
- package/dist/mcp.js +23 -24
- package/dist/model.d.ts +12 -21
- package/dist/model.js +5 -8
- package/dist/notifications.d.ts +1 -1
- package/dist/notifications.js +8 -5
- package/dist/operation-presentation.d.ts +6 -6
- package/dist/operation-presentation.js +55 -58
- package/dist/owner.d.ts +11 -0
- package/dist/owner.js +32 -0
- package/dist/paseo-delivery.d.ts +4 -1
- package/dist/paseo-delivery.js +7 -12
- package/dist/paseo-state.d.ts +2 -2
- package/dist/paseo-state.js +6 -4
- package/dist/plugins/opencode/delivery.js +27 -15
- package/dist/ports.d.ts +18 -47
- package/dist/presentation-operations.d.ts +14 -19
- package/dist/presentation-operations.js +51 -61
- package/dist/presentation.d.ts +7 -17
- package/dist/presentation.js +46 -91
- package/dist/receive.d.ts +66 -0
- package/dist/receive.js +54 -0
- package/dist/runtime.d.ts +1 -8
- package/dist/runtime.js +2 -17
- package/dist/seats.d.ts +2 -3
- package/dist/seats.js +7 -15
- package/dist/session-lifecycle.d.ts +6 -2
- package/dist/session-lifecycle.js +39 -11
- package/dist/sqlite-square.d.ts +36 -23
- package/dist/sqlite-square.js +162 -211
- package/dist/square-api.d.ts +16 -11
- package/dist/square-api.js +27 -23
- package/dist/square-core.d.ts +0 -14
- package/dist/square-core.js +0 -9
- package/dist/square-domain.d.ts +4 -2
- package/dist/square-domain.js +65 -52
- package/dist/square-facade.d.ts +47 -105
- package/dist/square-index.d.ts +5 -13
- package/dist/square-index.js +13 -38
- package/dist/square-legacy-framing.d.ts +2 -0
- package/dist/square-legacy-framing.js +8 -0
- package/dist/square-location.d.ts +1 -14
- package/dist/square-location.js +4 -70
- package/dist/square-migration-host-ledger.d.ts +2 -2
- package/dist/square-migration-host-ledger.js +6 -5
- package/dist/square-migration.d.ts +4 -1
- package/dist/square-migration.js +93 -38
- package/dist/square-receive.d.ts +6 -0
- package/dist/square-receive.js +18 -0
- package/dist/square-sqlite.d.ts +9 -3
- package/dist/square-sqlite.js +139 -114
- package/dist/square-tools.d.ts +7 -10
- package/dist/square-tools.js +21 -61
- package/dist/stream.js +4 -5
- package/dist/views.d.ts +23 -13
- package/dist/views.js +47 -53
- package/dist/wakes.d.ts +1 -5
- package/dist/wakes.js +4 -6
- package/examples/symmetric-domains.mjs +250 -0
- package/guides/application-facade-delivery-evidence.md +6 -6
- package/guides/attention-primitive.md +32 -0
- package/guides/change-waits.md +2 -2
- package/guides/claude-native.md +18 -9
- package/guides/codex-delivery.md +17 -6
- package/guides/delivery-primitives.md +180 -0
- package/guides/mcp-connection-lifetime.md +1 -1
- package/guides/mcp.md +3 -3
- package/guides/migration.md +148 -151
- package/guides/operation-cancellation.md +1 -1
- package/guides/participant-ownership.md +78 -47
- package/guides/pi-tools.md +34 -5
- package/guides/primitive-catch-consolidation.md +5 -5
- package/guides/primitive-history-consolidation.md +2 -2
- package/guides/primitive-status-consolidation.md +3 -3
- package/guides/primitive-storage-consolidation.md +1 -1
- package/guides/receive-primitive.md +90 -0
- package/guides/row-runtime-delivery-evidence.md +1 -1
- package/guides/row-storage-design.md +22 -28
- package/guides/square-api.md +314 -91
- package/guides/symmetric-domains.md +92 -0
- package/package.json +14 -1
- package/plugins/claude/.claude-plugin/plugin.json +1 -1
- package/plugins/claude/skills/square/SKILL.md +2 -6
- package/plugins/codex/.codex-plugin/plugin.json +1 -1
- package/plugins/opencode/delivery.ts +27 -17
- package/plugins/paseo/client/palette.ts +18 -18
- package/plugins/paseo/client/square-message.tsx +17 -23
- package/plugins/pi/square-pi.js +17 -17
- package/skills/square/SKILL.md +2 -6
- package/dist/square-backend.d.ts +0 -13
- package/dist/square-backend.js +0 -1
- package/dist/square-stdio.d.ts +0 -22
- package/dist/square-stdio.js +0 -235
- package/dist/stdio-server.d.ts +0 -3
- package/dist/stdio-server.js +0 -212
- package/guides/backends.md +0 -193
package/dist/help.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { JSON_COMMANDS } from './cli/json.js';
|
|
1
2
|
const COMMANDS = [
|
|
2
3
|
{ names: ['help'], usage: 'help [command]', summary: 'Show the command index or help for one command.' },
|
|
3
4
|
{ names: ['version'], usage: 'version', summary: 'Print the installed version.', hiddenFromIndex: true },
|
|
@@ -31,7 +32,7 @@ const COMMANDS = [
|
|
|
31
32
|
'',
|
|
32
33
|
'Options:',
|
|
33
34
|
' -f, --force Express without first catching unread activity or satisfying attention etiquette.',
|
|
34
|
-
' --no-wait If
|
|
35
|
+
' --no-wait If throttled, save a draft and return instead of waiting.',
|
|
35
36
|
' --metadata <json> Attach a bounded JSON object (at most 16 KiB UTF-8 and 256 nesting levels); it may be the only content.',
|
|
36
37
|
' Metadata is returned in structured activity results but is not shown in human text or searchable.',
|
|
37
38
|
],
|
|
@@ -52,9 +53,9 @@ const COMMANDS = [
|
|
|
52
53
|
details: ['Options:', ' --ndjson Emit one JSON event per line.', ' --for <name> With --ndjson, emit notifications for one participant.', ' --last <N> Emit the last N eligible activities first (default 10, maximum 100).', ' --after <id> Resume after a canonical activity id (act/12).'],
|
|
53
54
|
},
|
|
54
55
|
{
|
|
55
|
-
names: ['inbox'], usage: 'inbox --for-
|
|
56
|
+
names: ['inbox'], usage: 'inbox --for-owner <owner> [--limit <N>]', hiddenFromIndex: true,
|
|
56
57
|
summary: 'Inspect a bounded machine-local notification snapshot for a native session.',
|
|
57
|
-
details: ['Options:', ' --for-
|
|
58
|
+
details: ['Options:', ' --for-owner <id> Required opaque owner.', ' --limit <N> Snapshot memberships (default 20, maximum 100).'],
|
|
58
59
|
},
|
|
59
60
|
{ names: ['codex-hook'], usage: '{command}', summary: 'Present pending attention at one native agent boundary.', hiddenFromIndex: true },
|
|
60
61
|
{ names: ['claude-mod'], usage: '{command}', summary: 'Receive a structured operation from the loaded Claude mod.', hiddenFromIndex: true },
|
|
@@ -67,10 +68,8 @@ const COMMANDS = [
|
|
|
67
68
|
{
|
|
68
69
|
names: ['participants'], usage: 'participants [--limit <count>]', usesSquare: true, group: 'host',
|
|
69
70
|
summary: 'Show the participant roster and current states.',
|
|
70
|
-
details: ['Options:', ' --limit <count> Show the first count names in
|
|
71
|
+
details: ['Options:', ' --limit <count> Show the first count names in human text (default 20, maximum 100).'],
|
|
71
72
|
},
|
|
72
|
-
{ names: ['hold'], usage: '--as <name> hold [reason | -]', usesSquare: true, group: 'participant', summary: 'Raise a hand and pause participant activity.' },
|
|
73
|
-
{ names: ['resume'], usage: '--as <name> resume', usesSquare: true, group: 'participant', summary: 'Lower the raised hand and resume activity.' },
|
|
74
73
|
{
|
|
75
74
|
names: ['install'], usage: 'install (--all | <target>...) [-f]', group: 'maintenance',
|
|
76
75
|
summary: 'Install Square support for one or more agent hosts.',
|
|
@@ -93,7 +92,7 @@ const COMMANDS = [
|
|
|
93
92
|
{
|
|
94
93
|
names: ['migrate'], usage: 'migrate', usesSquare: true, group: 'maintenance',
|
|
95
94
|
summary: 'Convert a supported older square to the current format in place.',
|
|
96
|
-
details: ['For the selected .square artifact only. Stop sessions using this artifact before conversion. Back up the stopped artifact, migrate it, then run square --location <path> doctor before starting updated clients.', 'Versions 2,
|
|
95
|
+
details: ['For the selected .square artifact only. Stop sessions using this artifact before conversion. Back up the stopped artifact, migrate it, then run square --location <path> doctor before starting updated clients.', 'Versions 2–7 migrate explicitly to format 8. Format 7 migration deletes hold/resume activities and their keyed rows, clears replies to those activities, and preserves surviving activity ids with gaps. Format 6 attachment and opaque-owner conversion are preserved; versions 4/5 first gain attached seats, and 4 also gains empty deferrals. Version 1, unrelated or unsupported artifacts refuse without a write. Names whose legacy owner and routes agree may share an owner; ambiguous names stay standing without custody. Rejoin with the same owner after migration to republish discovery. There is no --check, --backup or --force.'],
|
|
97
96
|
},
|
|
98
97
|
];
|
|
99
98
|
function definitionFor(command) {
|
|
@@ -104,7 +103,7 @@ function isHelpFlag(value) {
|
|
|
104
103
|
}
|
|
105
104
|
export function renderGlobalHelp() {
|
|
106
105
|
const groups = [
|
|
107
|
-
{ key: 'participant', title: 'In the square:', order: ['join', 'express', 'listen', 'unlisten', 'ignore', 'listening', 'catch', 'history', 'status', '
|
|
106
|
+
{ key: 'participant', title: 'In the square:', order: ['join', 'express', 'listen', 'unlisten', 'ignore', 'listening', 'catch', 'history', 'status', 'done'] },
|
|
108
107
|
{ key: 'host', title: 'Prepare and manage:', order: ['build', 'list', 'participants'] },
|
|
109
108
|
{ key: 'maintenance', title: 'Setup:', order: ['install', 'uninstall', 'doctor', 'migrate'] },
|
|
110
109
|
];
|
|
@@ -117,10 +116,11 @@ export function renderGlobalHelp() {
|
|
|
117
116
|
'',
|
|
118
117
|
]);
|
|
119
118
|
return [
|
|
120
|
-
'Usage: square [--location <square>] [--as <name>] <command> [args...]',
|
|
121
|
-
'Environment: SQUARE_LOCATION sets the CLI
|
|
122
|
-
'
|
|
123
|
-
'
|
|
119
|
+
'Usage: square [--location <square>] [--as <name>] [--owner <id>] <command> [args...]',
|
|
120
|
+
'Environment: SQUARE_LOCATION sets the CLI local artifact path; square-accessing commands require it or --location. Use --as to select a participant.',
|
|
121
|
+
'Identity: --owner overrides SQUARE_OWNER, then a complete harness identity, then user:<OS user>@<host>. Incomplete or ambiguous harness identities refuse. Owners without wake use catch --idle.',
|
|
122
|
+
'Output: --json on join, express, catch, history, listen, ignore, unlisten, listening, done, status, participants and inbox prints the SDK result without observation; a participant handle becomes {name}.',
|
|
123
|
+
'History emits one JSON document; stream --ndjson emits one SDK record per line.',
|
|
124
124
|
'',
|
|
125
125
|
...commandLines,
|
|
126
126
|
"Run 'square <command> --help' for command options.",
|
|
@@ -132,7 +132,7 @@ export function renderSubcommandHelp(command) {
|
|
|
132
132
|
if (definition === undefined)
|
|
133
133
|
return undefined;
|
|
134
134
|
const aliases = definition.names.filter((name) => name !== command);
|
|
135
|
-
const usage = definition.usage.replace('{command}', command);
|
|
135
|
+
const usage = definition.usage.replace('{command}', command) + (JSON_COMMANDS.has(command) ? ' [--json]' : '');
|
|
136
136
|
return [
|
|
137
137
|
`Usage: square ${definition.usesSquare ? '[--location <square>] ' : ''}${usage}`,
|
|
138
138
|
...(aliases.length > 0 ? [`Aliases: ${aliases.join(', ')}`] : []),
|
|
@@ -151,7 +151,7 @@ export function helpRequest(rawArgs) {
|
|
|
151
151
|
const args = [];
|
|
152
152
|
for (let index = 0; index < rawArgs.length; index++) {
|
|
153
153
|
const arg = rawArgs[index];
|
|
154
|
-
if (arg === '--location' || arg === '--as') {
|
|
154
|
+
if (arg === '--location' || arg === '--as' || arg === '--owner') {
|
|
155
155
|
const value = rawArgs[index + 1];
|
|
156
156
|
if (value === undefined || value.startsWith('--'))
|
|
157
157
|
return undefined;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { WakeRoute } from './model.js';
|
|
2
|
+
import type { WakeOutcome, WakeRequest, WakeTransportPort } from './ports.js';
|
|
3
|
+
export interface HttpWakeTransportOptions {
|
|
4
|
+
fetch?: typeof fetch;
|
|
5
|
+
env?: NodeJS.ProcessEnv;
|
|
6
|
+
}
|
|
7
|
+
/** HTTP accepts wake custody only; it never consumes or presents Square activity. */
|
|
8
|
+
export declare class HttpWakeTransport implements WakeTransportPort {
|
|
9
|
+
private readonly opts;
|
|
10
|
+
constructor(opts?: HttpWakeTransportOptions);
|
|
11
|
+
probe(route: WakeRoute): Promise<boolean | {
|
|
12
|
+
outcome: 'not-capable';
|
|
13
|
+
diagnostic: string;
|
|
14
|
+
}>;
|
|
15
|
+
attempt(request: WakeRequest, timeoutMs: number, beforeSend: () => Promise<boolean>): Promise<WakeOutcome>;
|
|
16
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { wakePreview } from './delivery.js';
|
|
2
|
+
/** Configuration only: probing never contacts the receiver. */
|
|
3
|
+
function configuration(route, env) {
|
|
4
|
+
if (route.kind !== 'http')
|
|
5
|
+
return undefined;
|
|
6
|
+
try {
|
|
7
|
+
const url = new URL(route.address.url);
|
|
8
|
+
if (!['http:', 'https:'].includes(url.protocol) || !url.hostname || url.username || url.password
|
|
9
|
+
|| route.address.url.includes('#'))
|
|
10
|
+
return undefined;
|
|
11
|
+
const headers = new Headers({ 'Content-Type': 'application/json' });
|
|
12
|
+
const tokenEnv = route.address.tokenEnv;
|
|
13
|
+
if (tokenEnv !== undefined) {
|
|
14
|
+
const token = tokenEnv.trim() ? env[tokenEnv] : undefined;
|
|
15
|
+
// RFC 6750 bearer credentials; whitespace/control characters cannot become headers.
|
|
16
|
+
if (!token || token !== token.trim() || !/^[A-Za-z0-9._~+\/-]+=*$/.test(token))
|
|
17
|
+
return undefined;
|
|
18
|
+
headers.set('Authorization', `Bearer ${token}`);
|
|
19
|
+
}
|
|
20
|
+
return { url: route.address.url, headers };
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/** HTTP accepts wake custody only; it never consumes or presents Square activity. */
|
|
27
|
+
export class HttpWakeTransport {
|
|
28
|
+
opts;
|
|
29
|
+
constructor(opts = {}) {
|
|
30
|
+
this.opts = opts;
|
|
31
|
+
}
|
|
32
|
+
async probe(route) {
|
|
33
|
+
return configuration(route, this.opts.env ?? process.env) !== undefined
|
|
34
|
+
? true : { outcome: 'not-capable', diagnostic: 'HTTP wake configuration unavailable.' };
|
|
35
|
+
}
|
|
36
|
+
async attempt(request, timeoutMs, beforeSend) {
|
|
37
|
+
const deadline = Date.now() + timeoutMs;
|
|
38
|
+
if (request.route.kind !== 'http')
|
|
39
|
+
return { outcome: 'not-capable' };
|
|
40
|
+
const config = configuration(request.route, this.opts.env ?? process.env);
|
|
41
|
+
if (config === undefined)
|
|
42
|
+
return { outcome: 'failed', signature: 'http_config_rejected', message: 'Invalid HTTP wake configuration.' };
|
|
43
|
+
const controller = new AbortController();
|
|
44
|
+
let sent = false;
|
|
45
|
+
const budgetUnavailable = () => sent
|
|
46
|
+
? { outcome: 'unknown', signature: 'http_send_timeout', message: 'HTTP wake acceptance is unknown after timeout.' }
|
|
47
|
+
: { outcome: 'failed', signature: 'http_pre_send_timeout', message: 'HTTP wake budget elapsed before sending.' };
|
|
48
|
+
if (!Number.isFinite(timeoutMs) || Date.now() >= deadline)
|
|
49
|
+
return budgetUnavailable();
|
|
50
|
+
let timer;
|
|
51
|
+
const timeout = new Promise(resolve => {
|
|
52
|
+
timer = setTimeout(() => { controller.abort(); resolve(budgetUnavailable()); }, Math.max(0, deadline - Date.now()));
|
|
53
|
+
});
|
|
54
|
+
const send = async () => {
|
|
55
|
+
try {
|
|
56
|
+
const preview = request.artifact === undefined ? undefined
|
|
57
|
+
: (await request.artifact.read(facts => wakePreview(facts, request), controller.signal)).value;
|
|
58
|
+
if (preview === undefined)
|
|
59
|
+
return { outcome: 'not-capable', diagnostic: 'No pending Square activity to preview.' };
|
|
60
|
+
const body = JSON.stringify({
|
|
61
|
+
location: request.location, participant: request.participant, activity: request.activity, actor: request.actor,
|
|
62
|
+
...(request.attemptN === undefined ? {} : { attemptN: request.attemptN }), preview,
|
|
63
|
+
});
|
|
64
|
+
if (controller.signal.aborted || Date.now() >= deadline)
|
|
65
|
+
return budgetUnavailable();
|
|
66
|
+
if (!(await beforeSend()))
|
|
67
|
+
return { outcome: 'not-capable' };
|
|
68
|
+
// Preview and the final gate spend the same absolute budget as the request.
|
|
69
|
+
if (controller.signal.aborted || Date.now() >= deadline)
|
|
70
|
+
return budgetUnavailable();
|
|
71
|
+
sent = true;
|
|
72
|
+
const response = await (this.opts.fetch ?? fetch)(config.url, {
|
|
73
|
+
method: 'POST', headers: config.headers, body, redirect: 'manual', signal: controller.signal,
|
|
74
|
+
});
|
|
75
|
+
// Status is the whole acknowledgement; never wait for or buffer a receiver body.
|
|
76
|
+
void response.body?.cancel().catch(() => undefined);
|
|
77
|
+
if (response.status >= 200 && response.status < 300)
|
|
78
|
+
return { outcome: 'accepted', signature: 'http_accepted' };
|
|
79
|
+
return {
|
|
80
|
+
outcome: 'failed', signature: response.status >= 500 && response.status < 600 ? 'http_status_transient' : 'http_status_rejected',
|
|
81
|
+
message: `HTTP wake returned status ${response.status}.`,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
// URLs, query credentials and raw fetch exceptions must never reach evidence.
|
|
86
|
+
if (controller.signal.aborted)
|
|
87
|
+
return budgetUnavailable();
|
|
88
|
+
return sent
|
|
89
|
+
? { outcome: 'unknown', signature: 'http_send_unknown', message: 'HTTP wake acceptance is unknown after a network error.' }
|
|
90
|
+
: { outcome: 'failed', signature: 'http_pre_send_failed', message: 'HTTP wake could not be prepared.' };
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
try {
|
|
94
|
+
return await Promise.race([send(), timeout]);
|
|
95
|
+
}
|
|
96
|
+
finally {
|
|
97
|
+
if (timer !== undefined)
|
|
98
|
+
clearTimeout(timer);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
package/dist/inbox.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type Owner, type LocatedSeat, type PendingMembership } from './model.js';
|
|
2
2
|
import type { SquareRead } from './ports.js';
|
|
3
3
|
export interface PendingWaitOptions {
|
|
4
4
|
signal?: AbortSignal;
|
|
@@ -14,15 +14,12 @@ export declare function pendingAtBoundary(inbox: readonly PendingMembership[]):
|
|
|
14
14
|
export declare function projectBoundaryEligibility(inbox: readonly PendingMembership[]): Promise<PendingMembership[]>;
|
|
15
15
|
export interface SessionBindingCandidate {
|
|
16
16
|
readonly location: string;
|
|
17
|
-
readonly
|
|
17
|
+
readonly owner: Owner;
|
|
18
18
|
}
|
|
19
19
|
/** HOME is a candidate path index; current seats and delivery evidence live in the artifact. */
|
|
20
20
|
export declare function projectSessionCandidates(input: SessionSeatQuery): Promise<readonly SessionBindingCandidate[]>;
|
|
21
21
|
export interface SessionSeatQuery {
|
|
22
|
-
readonly
|
|
23
|
-
readonly sessionId?: string;
|
|
24
|
-
readonly channel?: string;
|
|
25
|
-
readonly agent?: string;
|
|
22
|
+
readonly owner?: Owner;
|
|
26
23
|
readonly location?: string;
|
|
27
24
|
readonly env?: NodeJS.ProcessEnv;
|
|
28
25
|
}
|
|
@@ -36,31 +33,21 @@ export interface NativePendingPreview {
|
|
|
36
33
|
}
|
|
37
34
|
export type NativePendingPreviewInput = {
|
|
38
35
|
readonly location: string;
|
|
39
|
-
readonly
|
|
36
|
+
readonly generation: import('./model.js').ActivityId;
|
|
40
37
|
readonly participant: string;
|
|
41
38
|
readonly actIndex: number;
|
|
42
39
|
readonly cancelledThrough?: number;
|
|
43
40
|
readonly now: number;
|
|
44
41
|
} & ({
|
|
45
42
|
readonly routeKind: 'claude-native';
|
|
46
|
-
readonly address:
|
|
47
|
-
readonly endpoint: string;
|
|
48
|
-
};
|
|
43
|
+
readonly address: Readonly<Record<string, string>>;
|
|
49
44
|
} | {
|
|
50
45
|
readonly routeKind: 'opencode-server';
|
|
51
|
-
readonly address:
|
|
52
|
-
readonly sessionId: string;
|
|
53
|
-
};
|
|
46
|
+
readonly address: Readonly<Record<string, string>>;
|
|
54
47
|
});
|
|
55
|
-
/**
|
|
48
|
+
/** Current-generation native attention, owned by its exact wake address and catch state. */
|
|
56
49
|
export declare function nativePendingPreview(facts: SquareRead, input: NativePendingPreviewInput): NativePendingPreview | undefined;
|
|
57
|
-
export
|
|
58
|
-
readonly channel: string;
|
|
59
|
-
readonly session: string;
|
|
60
|
-
readonly allAgents?: true;
|
|
61
|
-
}
|
|
62
|
-
export type SessionIdentity = Body | SessionIdentityQuery;
|
|
63
|
-
export declare function sessionInbox(identity: SessionIdentity, env?: NodeJS.ProcessEnv, signal?: AbortSignal): Promise<PendingMembership[]>;
|
|
50
|
+
export declare function sessionInbox(owner: Owner, env?: NodeJS.ProcessEnv, signal?: AbortSignal): Promise<PendingMembership[]>;
|
|
64
51
|
export interface SessionPendingObserver {
|
|
65
52
|
/** Read committed revisions before reusing content; filesystem hints are only for waiting. */
|
|
66
53
|
read(options?: Pick<PendingWaitOptions, 'signal' | 'excludeKeys'>): Promise<PendingMembership[]>;
|
|
@@ -68,4 +55,4 @@ export interface SessionPendingObserver {
|
|
|
68
55
|
close(): void;
|
|
69
56
|
}
|
|
70
57
|
/** Session-scoped projection over process-shared storage change detectors. */
|
|
71
|
-
export declare function observeSessionPending(
|
|
58
|
+
export declare function observeSessionPending(owner: Owner, suppliedEnv?: NodeJS.ProcessEnv): Promise<SessionPendingObserver>;
|
package/dist/inbox.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { sameBody } from './model.js';
|
|
2
1
|
import { createArtifactPort, observeSquareDeliveryRevision, observeSquareRevision } from './artifact.js';
|
|
3
2
|
import { indexedSquareEntries, observeSquareIndex } from './square-index.js';
|
|
4
3
|
import { canonicalPath } from './canonical-path.js';
|
|
@@ -20,8 +19,8 @@ export function pendingAtBoundary(inbox) {
|
|
|
20
19
|
}
|
|
21
20
|
function eligibleNotifications(facts, membership, now = Date.now()) {
|
|
22
21
|
const seat = facts.seat(membership.seat.participant);
|
|
23
|
-
if (seat === undefined || seat.generation !== membership.seat.generation
|
|
24
|
-
||
|
|
22
|
+
if (seat === undefined || seat.attachment !== 'attached' || seat.generation !== membership.seat.generation
|
|
23
|
+
|| seat.owner !== membership.seat.owner)
|
|
25
24
|
return { notifications: [] };
|
|
26
25
|
const cancelledThrough = facts.cancelledThrough(seat.participant, seat.generation);
|
|
27
26
|
let expiry = Infinity;
|
|
@@ -68,22 +67,22 @@ export async function projectBoundaryEligibility(inbox) {
|
|
|
68
67
|
/** HOME is a candidate path index; current seats and delivery evidence live in the artifact. */
|
|
69
68
|
export async function projectSessionCandidates(input) {
|
|
70
69
|
const location = input.location === undefined ? undefined : await canonicalPath(input.location);
|
|
71
|
-
const entries = await indexedSquareEntries({
|
|
70
|
+
const entries = await indexedSquareEntries({ owner: input.owner }, input.env ?? process.env);
|
|
72
71
|
const candidates = new Map();
|
|
73
72
|
for (const entry of entries) {
|
|
74
73
|
if (location !== undefined && location !== entry.location)
|
|
75
74
|
continue;
|
|
76
|
-
const key = JSON.stringify([entry.location, entry.
|
|
77
|
-
candidates.set(key, { location: entry.location,
|
|
75
|
+
const key = JSON.stringify([entry.location, entry.owner]);
|
|
76
|
+
candidates.set(key, { location: entry.location, owner: entry.owner });
|
|
78
77
|
}
|
|
79
78
|
return [...candidates.values()];
|
|
80
79
|
}
|
|
81
80
|
function groupCandidates(candidates) {
|
|
82
81
|
const grouped = new Map();
|
|
83
|
-
for (const { location,
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
grouped.set(location,
|
|
82
|
+
for (const { location, owner } of candidates) {
|
|
83
|
+
const owners = grouped.get(location) ?? [];
|
|
84
|
+
owners.push(owner);
|
|
85
|
+
grouped.set(location, owners);
|
|
87
86
|
}
|
|
88
87
|
return grouped;
|
|
89
88
|
}
|
|
@@ -97,11 +96,11 @@ function locatedSeats(facts, location, seats) {
|
|
|
97
96
|
/** Lifecycle reads resolve seats and join times, never pending activity bodies. */
|
|
98
97
|
export async function projectSessionSeats(input, signal) {
|
|
99
98
|
const seats = [];
|
|
100
|
-
for (const [location,
|
|
99
|
+
for (const [location, owners] of groupCandidates(await projectSessionCandidates(input))) {
|
|
101
100
|
signal?.throwIfAborted();
|
|
102
101
|
const artifact = createArtifactPort(location, undefined, signal);
|
|
103
102
|
try {
|
|
104
|
-
seats.push(...(await artifact.read(facts => locatedSeats(facts, location,
|
|
103
|
+
seats.push(...(await artifact.read(facts => locatedSeats(facts, location, owners.flatMap(owner => facts.seatsForOwner(owner))), signal)).value);
|
|
105
104
|
}
|
|
106
105
|
catch (error) {
|
|
107
106
|
if (signal?.aborted)
|
|
@@ -116,11 +115,11 @@ export async function projectSessionSeats(input, signal) {
|
|
|
116
115
|
/** Public count boundary: one coherent read per artifact, without pending body hydration. */
|
|
117
116
|
export async function sessionInboxCounts(input, signal) {
|
|
118
117
|
const rows = [];
|
|
119
|
-
for (const [location,
|
|
118
|
+
for (const [location, owners] of groupCandidates(await projectSessionCandidates(input))) {
|
|
120
119
|
signal?.throwIfAborted();
|
|
121
120
|
const artifact = createArtifactPort(location, undefined, signal);
|
|
122
121
|
try {
|
|
123
|
-
rows.push(...(await artifact.read(facts => locatedSeats(facts, location,
|
|
122
|
+
rows.push(...(await artifact.read(facts => locatedSeats(facts, location, owners.flatMap(owner => facts.seatsForOwner(owner).filter(seat => seat.attachment === 'attached'))).map(({ seat }) => ({
|
|
124
123
|
name: seat.participant, squarePath: location, pending: facts.directedCount(seat.participant, { unseenOnly: true }),
|
|
125
124
|
})), signal)).value);
|
|
126
125
|
}
|
|
@@ -137,13 +136,13 @@ export async function sessionInboxCounts(input, signal) {
|
|
|
137
136
|
/** One authoritative read per canonical artifact, even when discovery names several bodies. */
|
|
138
137
|
async function projectPending(candidates, cache, signal) {
|
|
139
138
|
const pending = [];
|
|
140
|
-
for (const [location,
|
|
139
|
+
for (const [location, owners] of groupCandidates(candidates)) {
|
|
141
140
|
signal?.throwIfAborted();
|
|
142
141
|
const artifact = createArtifactPort(location, undefined, signal);
|
|
143
142
|
try {
|
|
144
143
|
const { value: current } = await artifact.read(facts => {
|
|
145
|
-
const seats =
|
|
146
|
-
const coordinate = JSON.stringify([
|
|
144
|
+
const seats = owners.flatMap(owner => facts.seatsForOwner(owner).filter(seat => seat.attachment === 'attached'));
|
|
145
|
+
const coordinate = JSON.stringify([owners, seats.map(seat => [seat.participant, seat.owner, seat.generation])]);
|
|
147
146
|
const header = facts.header();
|
|
148
147
|
let cached = cache?.get(location);
|
|
149
148
|
if (cached?.coordinate !== coordinate || cached.version !== header.revision) {
|
|
@@ -177,14 +176,14 @@ async function projectPending(candidates, cache, signal) {
|
|
|
177
176
|
return pending;
|
|
178
177
|
}
|
|
179
178
|
function sameWakeAddress(address, kind, requested) {
|
|
180
|
-
if (address?.kind !== kind)
|
|
179
|
+
if (address?.kind !== kind || Object.keys(address.address).length !== Object.keys(requested).length)
|
|
181
180
|
return false;
|
|
182
181
|
return Object.entries(requested).every(([key, value]) => address.address[key] === value);
|
|
183
182
|
}
|
|
184
|
-
/**
|
|
183
|
+
/** Current-generation native attention, owned by its exact wake address and catch state. */
|
|
185
184
|
export function nativePendingPreview(facts, input) {
|
|
186
185
|
const seat = facts.seat(input.participant);
|
|
187
|
-
if (seat === undefined || seat.
|
|
186
|
+
if (seat === undefined || seat.attachment !== 'attached' || seat.generation !== input.generation
|
|
188
187
|
|| !sameWakeAddress(seat.wakeAddress, input.routeKind, input.address))
|
|
189
188
|
return undefined;
|
|
190
189
|
const cancelledThrough = facts.cancelledThrough(seat.participant, seat.generation);
|
|
@@ -200,10 +199,8 @@ export function nativePendingPreview(facts, input) {
|
|
|
200
199
|
return { payload: renderSquareReminder([renderAttentionPreview({ squarePath: input.location, recipient: input.participant, actIndex: item.index,
|
|
201
200
|
actor: item.actor, route: head.route, body: item.body ?? '(structured activity)' })]), clipped: attentionBodyIsClipped(item.body ?? '(structured activity)') };
|
|
202
201
|
}
|
|
203
|
-
export async function sessionInbox(
|
|
204
|
-
|
|
205
|
-
: { body: identity, env };
|
|
206
|
-
return projectPending(await projectSessionCandidates(query), undefined, signal);
|
|
202
|
+
export async function sessionInbox(owner, env = process.env, signal) {
|
|
203
|
+
return projectPending(await projectSessionCandidates({ owner, env }), undefined, signal);
|
|
207
204
|
}
|
|
208
205
|
async function capture(observer, kind, signal) {
|
|
209
206
|
const generation = observer.generation;
|
|
@@ -234,10 +231,9 @@ async function capture(observer, kind, signal) {
|
|
|
234
231
|
}
|
|
235
232
|
}
|
|
236
233
|
/** Session-scoped projection over process-shared storage change detectors. */
|
|
237
|
-
export async function observeSessionPending(
|
|
234
|
+
export async function observeSessionPending(owner, suppliedEnv = process.env) {
|
|
238
235
|
const env = { ...suppliedEnv };
|
|
239
|
-
const query =
|
|
240
|
-
: { body: identity, env };
|
|
236
|
+
const query = { owner, env };
|
|
241
237
|
const index = await observeSquareIndex(env);
|
|
242
238
|
const artifacts = new Map();
|
|
243
239
|
const cache = new Map();
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
export { Square, squareLocation, squareClock, createSquareResourceOwner, discover, inbox, diagnoseSquare, migrateSquare } from './square-api.js';
|
|
2
2
|
export { SquareError, ACTIVITY_METADATA_MAX_BYTES } from './model.js';
|
|
3
|
+
export { selectOwnSeat, requireOwner, localUserOwner, harnessOwner, decodeHarnessOwner } from './square-api.js';
|
|
3
4
|
export type { WakeTransportPort, WakeRequest, WakeOutcome } from './ports.js';
|
|
4
5
|
export type { WakeTransports } from './notifications.js';
|
|
5
|
-
export { createDefaultWakeTransport } from './notifications.js';
|
|
6
|
-
export type { PresentationSinkPort } from './ports.js';
|
|
7
|
-
export type * from './square-backend.js';
|
|
8
6
|
export type * from './square-facade.js';
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export { Square, squareLocation, squareClock, createSquareResourceOwner, discover, inbox, diagnoseSquare, migrateSquare } from './square-api.js';
|
|
2
2
|
export { SquareError, ACTIVITY_METADATA_MAX_BYTES } from './model.js';
|
|
3
|
-
export {
|
|
3
|
+
export { selectOwnSeat, requireOwner, localUserOwner, harnessOwner, decodeHarnessOwner } from './square-api.js';
|
package/dist/mcp.d.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import { type Owner } from './square-api.js';
|
|
2
3
|
import type { SquareAtInput } from './square-facade.js';
|
|
3
4
|
/** The server owns its artifact connection lifetime, so callers cannot lend one. */
|
|
4
5
|
export interface SquareMcpOptions extends Omit<SquareAtInput, 'resources'> {
|
|
6
|
+
readonly owner?: Owner;
|
|
7
|
+
readonly wakeAddress?: import('./model.js').WakeAddress;
|
|
5
8
|
}
|
|
6
9
|
export type SquareMcpServer = McpServer;
|
|
7
10
|
export declare function createSquareMcpServer(options: SquareMcpOptions): SquareMcpServer;
|
package/dist/mcp.js
CHANGED
|
@@ -6,8 +6,10 @@ import { codexWakeAddress } from './codex-address.js';
|
|
|
6
6
|
import { readClaudeMcpCall } from './claude-mcp-context.js';
|
|
7
7
|
import { SQUARE_IDENTITY } from './identity.js';
|
|
8
8
|
import { Square, createSquareResourceOwner } from './square-api.js';
|
|
9
|
+
import { harnessOwner } from './square-api.js';
|
|
9
10
|
export function createSquareMcpServer(options) {
|
|
10
|
-
const
|
|
11
|
+
const { owner: configuredOwner, wakeAddress, ...resourceOptions } = options;
|
|
12
|
+
const baseEnv = { ...(resourceOptions.env ?? process.env) };
|
|
11
13
|
const resources = createSquareResourceOwner();
|
|
12
14
|
// Calls to the configured square borrow one server-owned connection.
|
|
13
15
|
const inFlight = new Set();
|
|
@@ -19,21 +21,20 @@ export function createSquareMcpServer(options) {
|
|
|
19
21
|
const call = (async () => {
|
|
20
22
|
let square;
|
|
21
23
|
try {
|
|
22
|
-
const {
|
|
24
|
+
const { location } = args;
|
|
23
25
|
const threadId = extra._meta?.threadId;
|
|
24
26
|
const opencodeSessionId = extra._meta?.['ai.opencode/sessionID'];
|
|
25
27
|
// Claude's plugin endpoint requires the mod's call-local coordinate, never startup identity.
|
|
26
28
|
const claude = baseEnv.SQUARE_CLAUDE_MCP_CONTEXT === '1'
|
|
27
29
|
? await readClaudeMcpCall(extra._meta?.['claudecode/toolUseId'], baseEnv)
|
|
28
30
|
: undefined;
|
|
29
|
-
const
|
|
30
|
-
? { channel: 'claude-code', session: claude.sessionId,
|
|
31
|
-
...(claude.agentId === undefined ? {} : { agent: claude.agentId }) }
|
|
31
|
+
const owner = claude !== undefined
|
|
32
|
+
? harnessOwner({ channel: 'claude-code', session: claude.sessionId, ...(claude.agentId === undefined ? {} : { agent: claude.agentId }) })
|
|
32
33
|
: typeof threadId === 'string' && threadId.trim()
|
|
33
|
-
? { channel: 'codex', session: threadId }
|
|
34
|
+
? harnessOwner({ channel: 'codex', session: threadId })
|
|
34
35
|
: typeof opencodeSessionId === 'string' && opencodeSessionId.trim()
|
|
35
|
-
? { channel: 'opencode', session: opencodeSessionId }
|
|
36
|
-
:
|
|
36
|
+
? harnessOwner({ channel: 'opencode', session: opencodeSessionId })
|
|
37
|
+
: configuredOwner;
|
|
37
38
|
const env = claude !== undefined
|
|
38
39
|
? { ...operationEnv('claude', claude.sessionId, baseEnv),
|
|
39
40
|
// Preserve Claude's session + child flag semantics; an agent loop ID is not a session ID.
|
|
@@ -44,37 +45,35 @@ export function createSquareMcpServer(options) {
|
|
|
44
45
|
? operationEnv('opencode', opencodeSessionId, baseEnv)
|
|
45
46
|
: baseEnv;
|
|
46
47
|
square = await Square.at({
|
|
47
|
-
...
|
|
48
|
-
// A call-local Codex thread uses its native queue even when managed by Paseo.
|
|
49
|
-
wakeAddress: claude === undefined && typeof threadId === 'string' && threadId.trim()
|
|
50
|
-
? codexWakeAddress(threadId, env) : options.wakeAddress,
|
|
48
|
+
...resourceOptions, env, cwd: claude?.cwd ?? resourceOptions.cwd,
|
|
51
49
|
path: location ?? options.path,
|
|
52
|
-
participant: participant ?? options.participant,
|
|
53
50
|
// The server owner is bound to its configured square; overrides close after each call.
|
|
54
51
|
resources: location === undefined && claude === undefined ? resources : undefined,
|
|
55
52
|
}, { signal: extra.signal });
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
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;
|
|
59
59
|
try {
|
|
60
|
-
|
|
60
|
+
text = await tool.run(square, args, { signal: extra.signal }, {
|
|
61
|
+
owner, wakeAddress: claude === undefined && typeof threadId === 'string' && threadId.trim()
|
|
62
|
+
? codexWakeAddress(threadId, env) : callWake,
|
|
63
|
+
});
|
|
61
64
|
}
|
|
62
65
|
finally {
|
|
63
66
|
await square.close();
|
|
64
67
|
}
|
|
65
|
-
|
|
66
|
-
const text = tool.render(receipt, args) ?? '';
|
|
67
|
-
// Observation facts are a rendering aid, not part of the receipt machines receive.
|
|
68
|
-
const { observation: _observation, ...structuredContent } = receipt;
|
|
69
|
-
return { content: [{ type: 'text', text }], structuredContent };
|
|
68
|
+
return { content: [{ type: 'text', text }] };
|
|
70
69
|
}
|
|
71
70
|
catch (error) {
|
|
72
71
|
const failure = squareToolFailure(error, extra.signal);
|
|
73
72
|
const participant = args.as;
|
|
74
73
|
return { isError: true, content: [{ type: 'text', text: squareToolFailureText(failure, {
|
|
75
74
|
location: square?.location ?? options.path,
|
|
76
|
-
participant: typeof participant === 'string' ? participant :
|
|
77
|
-
}) }]
|
|
75
|
+
participant: typeof participant === 'string' ? participant : undefined,
|
|
76
|
+
}) }] };
|
|
78
77
|
}
|
|
79
78
|
})();
|
|
80
79
|
inFlight.add(call);
|