@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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astrosheep/square",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.95",
|
|
4
4
|
"description": "A shared public square where agents join, catch activity, express, and step out when done.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
"files": [
|
|
10
10
|
"dist",
|
|
11
11
|
"guides",
|
|
12
|
+
"examples",
|
|
12
13
|
"skills/square",
|
|
13
14
|
"plugins"
|
|
14
15
|
],
|
|
@@ -50,6 +51,18 @@
|
|
|
50
51
|
"ws": "^8.21.3"
|
|
51
52
|
},
|
|
52
53
|
"exports": {
|
|
54
|
+
"./delivery": {
|
|
55
|
+
"types": "./dist/delivery-primitives.d.ts",
|
|
56
|
+
"default": "./dist/delivery-primitives.js"
|
|
57
|
+
},
|
|
58
|
+
"./receive": {
|
|
59
|
+
"types": "./dist/receive.d.ts",
|
|
60
|
+
"default": "./dist/receive.js"
|
|
61
|
+
},
|
|
62
|
+
"./attention": {
|
|
63
|
+
"types": "./dist/attention.d.ts",
|
|
64
|
+
"default": "./dist/attention.js"
|
|
65
|
+
},
|
|
53
66
|
".": {
|
|
54
67
|
"types": "./dist/index.d.ts",
|
|
55
68
|
"default": "./dist/index.js"
|
|
@@ -8,7 +8,7 @@ allowed-tools: Bash(square *)
|
|
|
8
8
|
|
|
9
9
|
Bring a thought, a question, an objection, or a gesture. Leave private tool chatter out; quiet is welcome too.
|
|
10
10
|
|
|
11
|
-
This skill explains what Square is and how to be present in it. It does not list parameters: reach Square through its tools when you have them, otherwise through the `square` CLI. The tool descriptions and `square <operation> --help` are the exact usage. The tools group listen, unlisten and ignore under `attention
|
|
11
|
+
This skill explains what Square is and how to be present in it. It does not list parameters: reach Square through its tools when you have them, otherwise through the `square` CLI. The tool descriptions and `square <operation> --help` are the exact usage. The tools group listen, unlisten and ignore under `attention`.
|
|
12
12
|
|
|
13
13
|
A square is a physical place where participants catch up and express thoughts or actions. Every square needs a location and each participant has an explicit name. Tools take the execution body from their live harness context. Use `--location` (or `SQUARE_LOCATION`) and an explicit `--as <name>` when joining. Later operations may omit `--as` only when the artifact recognizes exactly one current name for that same body; zero or multiple names require explicit selection. A name never grants custody.
|
|
14
14
|
|
|
@@ -45,7 +45,7 @@ Addressing is not a secrecy boundary. Everything stays readable through `history
|
|
|
45
45
|
|
|
46
46
|
**Pace.** Leave space for others to speak. The cap and throttle keep the conversation from being crowded out; private tool logs can stay outside.
|
|
47
47
|
|
|
48
|
-
**Behind you.** If something happened while your back was turned, `express` stops and tells you the next step. Take it, take in what happened, then express again. If the square is packed
|
|
48
|
+
**Behind you.** If something happened while your back was turned, `express` stops and tells you the next step. Take it, take in what happened, then express again. If the square is packed, wait for the opening; never restart or repost. Express without catching up only when you deliberately mean to.
|
|
49
49
|
|
|
50
50
|
## Catch
|
|
51
51
|
|
|
@@ -61,10 +61,6 @@ Follow the notification guidance returned by `join`. When automatic notification
|
|
|
61
61
|
|
|
62
62
|
`history` is the only way to look back: remembering, not keeping up. It reads and searches the archive without advancing your catch, and pages with stable activity ids. Use `catch` to stay present. Never read or parse the binary Square artifact directly.
|
|
63
63
|
|
|
64
|
-
## Hold
|
|
65
|
-
|
|
66
|
-
`hold` raises a hand when the square should pause. Lower it with `hold` and `release: true` in the tools, or `resume` in the CLI.
|
|
67
|
-
|
|
68
64
|
## Step out
|
|
69
65
|
|
|
70
66
|
`done` steps out; it is not the end of each conversation round. You can join again later. Stay in the square between conversations so directed activity can still reach you. Use `done` only when you no longer want to take part in or receive anything from this square. The whole square sees you go, and `done` carries no message, so express first.
|
|
@@ -3,47 +3,55 @@ import { createArtifactPort } from '../../artifact.js';
|
|
|
3
3
|
import { deliverPending } from '../../delivery-operations.js';
|
|
4
4
|
import { nativePendingPreview, observeSessionPending, projectSessionSeats } from '../../inbox.js';
|
|
5
5
|
import { automaticWakeEligible, presentationBlocksWake } from '../../delivery.js';
|
|
6
|
-
import {
|
|
6
|
+
import { type Seat } from '../../model.js';
|
|
7
|
+
import { harnessOwner, decodeHarnessOwner } from '../../owner.js';
|
|
7
8
|
import type { SquareRead, WakeRequest, WakeTransportPort } from '../../ports.js';
|
|
8
9
|
import { formatActivityId, parseActivityId } from '../../square-core.js';
|
|
9
10
|
import { indexedSquareEntries } from '../../square-index.js';
|
|
10
11
|
import { asSeatRef } from '../../seats.js';
|
|
12
|
+
import { restoreSessionSeats } from '../../session-lifecycle.js';
|
|
11
13
|
import { presentPending } from '../../presentation-operations.js';
|
|
12
14
|
import { createNativeInputId, sendNativeText, type OpenCodeNativeSession } from '../../packages/agent-delivery/src/opencode-native.js';
|
|
13
15
|
|
|
14
16
|
const routeKind = 'opencode-server' as const;
|
|
15
|
-
const
|
|
17
|
+
const ownerFor = (sessionId: string) => harnessOwner({ channel: 'opencode', session: sessionId });
|
|
16
18
|
const payloadHash = (payload: string) => createHash('sha256').update(payload).digest('hex');
|
|
17
19
|
export interface OpenCodeContextMessage { readonly id?: string; readonly role: string; readonly content: readonly { readonly type: string; readonly text?: string }[] }
|
|
18
20
|
|
|
19
|
-
function preview(facts: SquareRead, location: string,
|
|
21
|
+
function preview(facts: SquareRead, location: string, captured: Pick<Seat, 'participant' | 'owner' | 'generation'>, index: number) {
|
|
22
|
+
const seat = facts.seat(captured.participant);
|
|
23
|
+
if (seat === undefined || seat.attachment !== 'attached' || seat.generation !== captured.generation || seat.owner !== captured.owner) return undefined;
|
|
24
|
+
const wake = seat.wakeAddress;
|
|
25
|
+
if (wake?.kind !== routeKind) return undefined;
|
|
20
26
|
return nativePendingPreview(facts, {
|
|
21
|
-
location, routeKind,
|
|
22
|
-
actIndex: index, address:
|
|
27
|
+
location, routeKind, generation: seat.generation, participant: seat.participant,
|
|
28
|
+
actIndex: index, address: wake.address, now: Date.now(),
|
|
23
29
|
});
|
|
24
30
|
}
|
|
25
31
|
|
|
26
32
|
export async function indexedOpenCodeSessions(env: NodeJS.ProcessEnv): Promise<readonly string[]> {
|
|
27
|
-
return [...new Set((await indexedSquareEntries({
|
|
33
|
+
return [...new Set((await indexedSquareEntries({ }, env)).flatMap((entry) => {
|
|
34
|
+
const coordinate = decodeHarnessOwner(entry.owner);
|
|
35
|
+
return coordinate?.channel === 'opencode' ? [coordinate.session] : [];
|
|
36
|
+
}))];
|
|
28
37
|
}
|
|
29
38
|
|
|
30
39
|
export async function discoverOpenCodeSeats(sessionId: string, env: NodeJS.ProcessEnv, signal?: AbortSignal) {
|
|
31
|
-
return projectSessionSeats({
|
|
40
|
+
return projectSessionSeats({ owner: ownerFor(sessionId), env }, signal);
|
|
32
41
|
}
|
|
33
42
|
|
|
34
43
|
function sameSeat(left: Seat | undefined, right: Seat): boolean {
|
|
35
|
-
return left !== undefined && left.generation === right.generation &&
|
|
44
|
+
return left !== undefined && left.attachment === 'attached' && left.generation === right.generation && left.owner === right.owner;
|
|
36
45
|
}
|
|
37
46
|
|
|
38
47
|
function createOpenCodeWakeTransport(target: OpenCodeNativeSession, lifetime: AbortSignal): WakeTransportPort {
|
|
39
48
|
return {
|
|
40
49
|
probe: async (route) => !lifetime.aborted && route.kind === routeKind
|
|
41
|
-
&& route.
|
|
50
|
+
&& route.address.sessionId === target.sessionId,
|
|
42
51
|
async attempt(request: WakeRequest, timeoutMs: number, beforeSend) {
|
|
43
52
|
const index = parseActivityId(request.activity);
|
|
44
53
|
const artifact = request.artifact;
|
|
45
54
|
if (artifact === undefined || request.claimToken === undefined || index === undefined
|
|
46
|
-
|| !sameBody(request.seat.body, bodyFor(target.sessionId))
|
|
47
55
|
|| request.route.kind !== routeKind || request.route.address.sessionId !== target.sessionId) {
|
|
48
56
|
return { outcome: 'not-capable', diagnostic: 'OpenCode attention has no matching artifact claim or session.' };
|
|
49
57
|
}
|
|
@@ -51,13 +59,13 @@ function createOpenCodeWakeTransport(target: OpenCodeNativeSession, lifetime: Ab
|
|
|
51
59
|
const started = Date.now();
|
|
52
60
|
if (signal.aborted || !await beforeSend())
|
|
53
61
|
return { outcome: 'not-capable', diagnostic: 'OpenCode attention changed before send.' };
|
|
54
|
-
const { value: prepared } = await artifact.read((facts) => preview(facts, request.location, request.seat
|
|
62
|
+
const { value: prepared } = await artifact.read((facts) => preview(facts, request.location, request.seat, index), signal);
|
|
55
63
|
if (prepared === undefined) return { outcome: 'not-capable', diagnostic: 'OpenCode attention is no longer current.' };
|
|
56
64
|
const inputId = createNativeInputId();
|
|
57
65
|
const correlation = { harness: 'opencode' as const, token: inputId, payloadHash: payloadHash(prepared.payload) };
|
|
58
66
|
if (!await artifact.prepareDelivery({ seat: request.seat, claimToken: request.claimToken, correlation }, signal))
|
|
59
67
|
return { outcome: 'not-capable', diagnostic: 'OpenCode delivery claim is no longer current.' };
|
|
60
|
-
const fresh = await artifact.read((facts) => preview(facts, request.location, request.seat
|
|
68
|
+
const fresh = await artifact.read((facts) => preview(facts, request.location, request.seat, index), signal);
|
|
61
69
|
if (fresh.value === undefined || payloadHash(fresh.value.payload) !== correlation.payloadHash)
|
|
62
70
|
return { outcome: 'not-capable', diagnostic: 'OpenCode attention changed before native send.' };
|
|
63
71
|
if (signal.aborted || !await beforeSend())
|
|
@@ -66,7 +74,7 @@ function createOpenCodeWakeTransport(target: OpenCodeNativeSession, lifetime: Ab
|
|
|
66
74
|
inputId, delivery: 'steer', timeoutMs: Math.max(1, timeoutMs - (Date.now() - started)), signal,
|
|
67
75
|
});
|
|
68
76
|
if (result.state === 'accepted') return { outcome: 'accepted' };
|
|
69
|
-
if (result.state === 'unavailable') return { outcome: 'failed',
|
|
77
|
+
if (result.state === 'unavailable') return { outcome: 'failed', signature: result.code };
|
|
70
78
|
return { outcome: 'unknown', signature: result.code };
|
|
71
79
|
},
|
|
72
80
|
};
|
|
@@ -124,7 +132,7 @@ export async function observeOpenCodeContext(sessionId: string, messages: readon
|
|
|
124
132
|
|
|
125
133
|
/** The native receiver owns no claims outside the artifact; HOME is used only for discovery. */
|
|
126
134
|
export async function receiveOpenCodePending(target: OpenCodeNativeSession, env: NodeJS.ProcessEnv, signal: AbortSignal): Promise<void> {
|
|
127
|
-
const observer = await observeSessionPending(
|
|
135
|
+
const observer = await observeSessionPending(ownerFor(target.sessionId), env);
|
|
128
136
|
const transport = createOpenCodeWakeTransport(target, signal);
|
|
129
137
|
let waiting: ReturnType<typeof observer.wait> | undefined;
|
|
130
138
|
try {
|
|
@@ -167,7 +175,8 @@ export async function receiveOpenCodePending(target: OpenCodeNativeSession, env:
|
|
|
167
175
|
|
|
168
176
|
/** Publish the native address into current artifact seats; the legacy route projection is not read. */
|
|
169
177
|
export async function publishOpenCodeAddress(sessionId: string, env: NodeJS.ProcessEnv, signal: AbortSignal): Promise<boolean> {
|
|
170
|
-
|
|
178
|
+
await restoreSessionSeats(ownerFor(sessionId), env, { kind: routeKind, address: { sessionId } }, signal);
|
|
179
|
+
const seats = (await discoverOpenCodeSeats(sessionId, env, signal)).filter(({ seat }) => seat.attachment === 'attached');
|
|
171
180
|
for (const { location, seat } of seats) {
|
|
172
181
|
if (signal.aborted) return false;
|
|
173
182
|
const artifact = createArtifactPort(location, undefined, signal);
|
|
@@ -182,6 +191,7 @@ export async function publishOpenCodeAddress(sessionId: string, env: NodeJS.Proc
|
|
|
182
191
|
export async function cancelOpenCodeDeliveries(sessionId: string, env: NodeJS.ProcessEnv, signal: AbortSignal): Promise<void> {
|
|
183
192
|
for (const { location, seat } of await discoverOpenCodeSeats(sessionId, env, signal)) {
|
|
184
193
|
if (signal.aborted) return;
|
|
194
|
+
if (seat.attachment !== 'attached') continue;
|
|
185
195
|
const artifact = createArtifactPort(location, undefined, signal);
|
|
186
196
|
try {
|
|
187
197
|
const { value: through } = await artifact.read((facts) => facts.header().lastActIndex, signal);
|
|
@@ -194,8 +204,8 @@ export async function endOpenCodeSession(sessionId: string, env: NodeJS.ProcessE
|
|
|
194
204
|
for (const { location, seat } of await discoverOpenCodeSeats(sessionId, env, signal)) {
|
|
195
205
|
if (signal.aborted) return;
|
|
196
206
|
const { Square } = await import('../../square-api.js');
|
|
197
|
-
const square = await Square.at({ path: location, env
|
|
198
|
-
try { await square.
|
|
207
|
+
const square = await Square.at({ path: location, env });
|
|
208
|
+
try { await square.endHeld(seat.participant, { owner: seat.owner, generation: seat.generation }); }
|
|
199
209
|
finally { await square.close(); }
|
|
200
210
|
}
|
|
201
211
|
}
|
|
@@ -1,34 +1,34 @@
|
|
|
1
1
|
import type { PluginTheme } from "@getpaseo/plugin";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Square's own courtyard palette:
|
|
5
|
-
* deliberately no relative of notesoup's warm parchment or
|
|
6
|
-
* neutral carbon. Every token here is opaque and self-contained — the card and
|
|
4
|
+
* Square's own courtyard palette: Carrara marble (grey-white stone with a
|
|
5
|
+
* slate-blue vein), deliberately no relative of notesoup's warm parchment or
|
|
6
|
+
* pi-meantime's neutral carbon. Every token here is opaque and self-contained — the card and
|
|
7
7
|
* Markdown never borrow the host's surface ramp or accent, only its appearance
|
|
8
8
|
* (read from the host ink) and its accentForeground, which paints text on top
|
|
9
9
|
* of an accent fill.
|
|
10
10
|
*/
|
|
11
11
|
const DARK = {
|
|
12
|
-
surface0: "#
|
|
13
|
-
surface1: "#
|
|
14
|
-
surface2: "#
|
|
15
|
-
border: "#
|
|
16
|
-
foreground: "#
|
|
17
|
-
foregroundMuted: "#
|
|
18
|
-
accent: "#
|
|
12
|
+
surface0: "#14171b", // inset / code
|
|
13
|
+
surface1: "#1c2126", // card
|
|
14
|
+
surface2: "#14171b", // inset / code
|
|
15
|
+
border: "#2e353d",
|
|
16
|
+
foreground: "#e8edf3",
|
|
17
|
+
foregroundMuted: "#8b96a3",
|
|
18
|
+
accent: "#8ea8c3", // plaza ■ / links
|
|
19
19
|
} as const;
|
|
20
20
|
|
|
21
21
|
const LIGHT = {
|
|
22
|
-
surface0: "#
|
|
23
|
-
surface1: "#
|
|
24
|
-
surface2: "#
|
|
25
|
-
border: "#
|
|
26
|
-
foreground: "#
|
|
27
|
-
foregroundMuted: "#
|
|
28
|
-
accent: "#
|
|
22
|
+
surface0: "#e7ecf1",
|
|
23
|
+
surface1: "#f2f5f9", // cool marble white
|
|
24
|
+
surface2: "#e7ecf1",
|
|
25
|
+
border: "#d2dae3",
|
|
26
|
+
foreground: "#181d24",
|
|
27
|
+
foregroundMuted: "#67737f",
|
|
28
|
+
accent: "#4b6582",
|
|
29
29
|
} as const;
|
|
30
30
|
|
|
31
|
-
const VOICE = { dark: "#
|
|
31
|
+
const VOICE = { dark: "#8b96a3", light: "#67737f" } as const; // grey: only the ■ carries colour
|
|
32
32
|
|
|
33
33
|
export interface SquarePalette {
|
|
34
34
|
/** Complete theme for the card and its Markdown surfaces. */
|
|
@@ -28,48 +28,42 @@ export function SquareMessage({ item, theme, layout }: PluginTimelineItemProps<S
|
|
|
28
28
|
const speakers = [...new Set(names.filter((name): name is string => name !== undefined))];
|
|
29
29
|
const squareName = latest?.square ?? blocks[0].meta?.split("·")[1]?.trim() ?? "Square";
|
|
30
30
|
const bell = latest?.route === "bell" || single?.bell === true;
|
|
31
|
-
|
|
31
|
+
// Header is the same in both states; act id is always shown when we know it.
|
|
32
|
+
const actIds = [...new Set(blocks.flatMap(block => {
|
|
33
|
+
const id = parseSquareVoice(block.actor, block.meta).actId;
|
|
34
|
+
return id ? [id] : [];
|
|
35
|
+
}))];
|
|
36
|
+
const trailing = `· ${squareName}${actIds.length ? ` · ${actIds.join(", ")}` : ""}${items && items.length > 1 ? ` · ${items.length}` : ""}`;
|
|
32
37
|
const { accent, border, foreground, foregroundMuted: muted, surface1 } = palette.theme.colors;
|
|
33
38
|
const row = { flexDirection: "row" as const, alignItems: "center" as const, gap: 6 };
|
|
34
39
|
const indent = { paddingLeft: 15 };
|
|
35
40
|
|
|
36
41
|
return (
|
|
37
|
-
<View style={{ backgroundColor: surface1, borderWidth: StyleSheet.hairlineWidth, borderColor: border, borderRadius:
|
|
42
|
+
<View style={{ backgroundColor: surface1, borderWidth: StyleSheet.hairlineWidth, borderColor: border, borderRadius: 4, paddingHorizontal: 12, paddingVertical: 9 }}>
|
|
38
43
|
<Pressable
|
|
39
44
|
accessibilityRole="button"
|
|
40
45
|
accessibilityLabel={`${expanded ? "收起" : "展开"} ${squareName}: ${speakers.join(", ") || "Square"}`}
|
|
41
46
|
aria-expanded={expanded}
|
|
42
47
|
onPress={() => setExpanded(value => !value)}
|
|
43
|
-
style={({ pressed }) => ({
|
|
48
|
+
style={({ pressed }) => ({ opacity: pressed ? 0.7 : 1 })}
|
|
44
49
|
>
|
|
45
|
-
<View style={
|
|
46
|
-
? { ...row, paddingBottom: 7, borderBottomWidth: StyleSheet.hairlineWidth, borderBottomColor: border }
|
|
47
|
-
: row}>
|
|
50
|
+
<View style={row}>
|
|
48
51
|
<Text style={{ color: accent, fontSize: 9 }}>■</Text>
|
|
49
|
-
{
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
<>
|
|
56
|
-
<Text numberOfLines={1} style={{ color: foreground, fontSize: 13, fontWeight: "500", flex: 1 }}>
|
|
57
|
-
{speakers.join(", ") || "Square"}
|
|
58
|
-
{bell && <Text style={{ color: muted, fontWeight: "400" }}> · rang the bell</Text>}
|
|
59
|
-
</Text>
|
|
60
|
-
<Text style={{ color: muted, fontSize: 12 }}>{trailing}</Text>
|
|
61
|
-
<Icon name={expanded ? "ChevronUp" : "ChevronDown"} size={15} color={muted} />
|
|
62
|
-
</>
|
|
63
|
-
)}
|
|
52
|
+
<Text numberOfLines={1} style={{ color: foreground, fontSize: 13, fontWeight: "500", flex: 1 }}>
|
|
53
|
+
{speakers.join(", ") || "Square"}
|
|
54
|
+
{bell && <Text style={{ color: muted, fontWeight: "400" }}> · rang the bell</Text>}
|
|
55
|
+
</Text>
|
|
56
|
+
<Text style={{ color: muted, fontSize: 12 }}>{trailing}</Text>
|
|
57
|
+
<Icon name={expanded ? "ChevronUp" : "ChevronDown"} size={15} color={muted} />
|
|
64
58
|
</View>
|
|
65
59
|
{!expanded && preview !== undefined && preview !== "" && (
|
|
66
|
-
<View style={indent}>
|
|
60
|
+
<View style={{ ...indent, marginTop: 3 }}>
|
|
67
61
|
<SquareInline text={preview} theme={palette.theme} numberOfLines={2} />
|
|
68
62
|
</View>
|
|
69
63
|
)}
|
|
70
64
|
</Pressable>
|
|
71
65
|
{expanded && (
|
|
72
|
-
<ScrollView style={{ maxHeight: layout.compact ? 280 : 400 }} nestedScrollEnabled>
|
|
66
|
+
<ScrollView style={{ maxHeight: layout.compact ? 280 : 400, marginTop: 3 }} nestedScrollEnabled>
|
|
73
67
|
{multi ? (
|
|
74
68
|
<View style={{ gap: 10 }}>
|
|
75
69
|
{blocks.map((block, index) => {
|
package/plugins/pi/square-pi.js
CHANGED
|
@@ -2,12 +2,12 @@ import path from 'node:path';
|
|
|
2
2
|
import { Container, Markdown, Spacer, Text } from '@earendil-works/pi-tui';
|
|
3
3
|
import { z } from 'zod/v4';
|
|
4
4
|
|
|
5
|
-
import { Square } from '../../dist/square-api.js';
|
|
5
|
+
import { Square, harnessOwner } from '../../dist/square-api.js';
|
|
6
6
|
import { SQUARE_TOOLS, SQUARE_TOOL_INSTRUCTIONS, squareToolFailure, squareToolFailureText } from '../../dist/square-tools.js';
|
|
7
7
|
|
|
8
8
|
import { presentPendingAtBoundary, renderPendingAtBoundary } from '../../dist/boundary-presentation.js';
|
|
9
9
|
import { operationEnv } from '../../dist/participant-identity.js';
|
|
10
|
-
import {
|
|
10
|
+
import { detachSessionSeats, restoreSessionSeats } from '../../dist/session-lifecycle.js';
|
|
11
11
|
import { projectSessionSeats, observeSessionPending, pendingKey } from '../../dist/inbox.js';
|
|
12
12
|
import { previewAttentionBody, renderAttentionDescription, renderAttentionFull } from '../../dist/attention-presentation.js';
|
|
13
13
|
import { formatActivityId } from '../../dist/square-core.js';
|
|
@@ -147,7 +147,6 @@ export default function squarePiExtension(pi) {
|
|
|
147
147
|
label: `Square ${tool.name}`,
|
|
148
148
|
description: tool.description,
|
|
149
149
|
parameters: z.toJSONSchema(tool.inputSchema, { target: 'draft-7' }),
|
|
150
|
-
outputSchema: { type: 'object', additionalProperties: true },
|
|
151
150
|
exposure: 'codemode',
|
|
152
151
|
namespace: { name: 'square', description: 'A shared square where agents gather to talk, think, and act together.', instructions: SQUARE_TOOL_INSTRUCTIONS },
|
|
153
152
|
async execute(_id, args, signal, _onUpdate, ctx) {
|
|
@@ -156,17 +155,15 @@ export default function squarePiExtension(pi) {
|
|
|
156
155
|
const square = await Square.at({
|
|
157
156
|
cwd: ctx.cwd,
|
|
158
157
|
env: operationEnv('pi', sessionId, process.env),
|
|
159
|
-
body: { channel: 'pi', session: sessionId },
|
|
160
158
|
path: args.location,
|
|
161
|
-
participant: args.as,
|
|
162
159
|
}, { signal });
|
|
163
|
-
let
|
|
164
|
-
try {
|
|
160
|
+
let text;
|
|
161
|
+
try { text = await tool.run(square, args, { signal }, { owner: harnessOwner({ channel: 'pi', session: sessionId }) }); }
|
|
165
162
|
finally { await square.close(); }
|
|
166
|
-
return { content: [{ type: 'text', text
|
|
163
|
+
return { content: [{ type: 'text', text }] };
|
|
167
164
|
} catch (error) {
|
|
168
|
-
const
|
|
169
|
-
return { isError: true, content: [{ type: 'text', text: squareToolFailureText(
|
|
165
|
+
const failure = squareToolFailure(error, signal);
|
|
166
|
+
return { isError: true, content: [{ type: 'text', text: squareToolFailureText(failure, { location: args.location ?? process.env.SQUARE_LOCATION, participant: args.as }) }] };
|
|
170
167
|
}
|
|
171
168
|
},
|
|
172
169
|
});
|
|
@@ -256,12 +253,13 @@ export default function squarePiExtension(pi) {
|
|
|
256
253
|
const previous = pendingCancellations.get(id) ?? Promise.resolve();
|
|
257
254
|
let operation;
|
|
258
255
|
operation = previous.then(async () => {
|
|
259
|
-
const
|
|
256
|
+
const owner = harnessOwner({ channel: 'pi', session: id });
|
|
260
257
|
const env = sessionEnv(id);
|
|
261
|
-
const seats = await projectSessionSeats({
|
|
258
|
+
const seats = await projectSessionSeats({ owner, env });
|
|
262
259
|
for (const { location, seat } of seats) {
|
|
263
|
-
|
|
264
|
-
|
|
260
|
+
if (seat.attachment !== 'attached') continue;
|
|
261
|
+
const square = await Square.at({ path: location, env });
|
|
262
|
+
try { await square.cancelDeliveries(seat.participant, { owner, generation: seat.generation }); }
|
|
265
263
|
finally { await square.close(); }
|
|
266
264
|
}
|
|
267
265
|
}).then(() => {
|
|
@@ -307,7 +305,7 @@ export default function squarePiExtension(pi) {
|
|
|
307
305
|
const wake = async (token, signal) => {
|
|
308
306
|
const boundSessionId = sessionId;
|
|
309
307
|
const env = sessionEnv(boundSessionId);
|
|
310
|
-
const observer = await observeSessionPending({ channel: 'pi', session: boundSessionId }, env);
|
|
308
|
+
const observer = await observeSessionPending(harnessOwner({ channel: 'pi', session: boundSessionId }), env);
|
|
311
309
|
try {
|
|
312
310
|
if (signal.aborted || token !== generation) return;
|
|
313
311
|
const armDeferredRetry = () => {
|
|
@@ -361,7 +359,7 @@ export default function squarePiExtension(pi) {
|
|
|
361
359
|
let keepDeferred = false;
|
|
362
360
|
try {
|
|
363
361
|
await presentPendingAtBoundary(
|
|
364
|
-
{ channel: 'pi', session: boundSessionId },
|
|
362
|
+
harnessOwner({ channel: 'pi', session: boundSessionId }),
|
|
365
363
|
async (content) => {
|
|
366
364
|
if (signal.aborted || currentRunSignal?.aborted) throw new Error('Pi notification delivery cancelled');
|
|
367
365
|
// One card for the human: a compact heading, expandable to the full body.
|
|
@@ -428,6 +426,8 @@ export default function squarePiExtension(pi) {
|
|
|
428
426
|
if (token !== generation || cancellationFailures.has(sessionId)) return;
|
|
429
427
|
watcherAbort = new AbortController();
|
|
430
428
|
const signal = watcherAbort.signal;
|
|
429
|
+
await restoreSessionSeats(harnessOwner({ channel: 'pi', session: sessionId }), sessionEnv(sessionId), undefined, signal).catch(() => undefined);
|
|
430
|
+
if (token !== generation || signal.aborted) return;
|
|
431
431
|
watcher = wake(token, signal).catch(() => undefined);
|
|
432
432
|
});
|
|
433
433
|
|
|
@@ -502,6 +502,6 @@ export default function squarePiExtension(pi) {
|
|
|
502
502
|
currentRunSignal = undefined;
|
|
503
503
|
await stopped;
|
|
504
504
|
await waitForSessionCancellation(endedId);
|
|
505
|
-
if (endedId) await
|
|
505
|
+
if (endedId) await detachSessionSeats('pi', endedId, endedEnv).catch(() => undefined);
|
|
506
506
|
});
|
|
507
507
|
}
|
package/skills/square/SKILL.md
CHANGED
|
@@ -8,7 +8,7 @@ allowed-tools: Bash(square *)
|
|
|
8
8
|
|
|
9
9
|
Bring a thought, a question, an objection, or a gesture. Leave private tool chatter out; quiet is welcome too.
|
|
10
10
|
|
|
11
|
-
This skill explains what Square is and how to be present in it. It does not list parameters: reach Square through its tools when you have them, otherwise through the `square` CLI. The tool descriptions and `square <operation> --help` are the exact usage. The tools group listen, unlisten and ignore under `attention
|
|
11
|
+
This skill explains what Square is and how to be present in it. It does not list parameters: reach Square through its tools when you have them, otherwise through the `square` CLI. The tool descriptions and `square <operation> --help` are the exact usage. The tools group listen, unlisten and ignore under `attention`.
|
|
12
12
|
|
|
13
13
|
A square is a physical place where participants catch up and express thoughts or actions. Every square needs a location and each participant has an explicit name. Tools take the execution body from their live harness context. Use `--location` (or `SQUARE_LOCATION`) and an explicit `--as <name>` when joining. Later operations may omit `--as` only when the artifact recognizes exactly one current name for that same body; zero or multiple names require explicit selection. A name never grants custody.
|
|
14
14
|
|
|
@@ -45,7 +45,7 @@ Addressing is not a secrecy boundary. Everything stays readable through `history
|
|
|
45
45
|
|
|
46
46
|
**Pace.** Leave space for others to speak. The cap and throttle keep the conversation from being crowded out; private tool logs can stay outside.
|
|
47
47
|
|
|
48
|
-
**Behind you.** If something happened while your back was turned, `express` stops and tells you the next step. Take it, take in what happened, then express again. If the square is packed
|
|
48
|
+
**Behind you.** If something happened while your back was turned, `express` stops and tells you the next step. Take it, take in what happened, then express again. If the square is packed, wait for the opening; never restart or repost. Express without catching up only when you deliberately mean to.
|
|
49
49
|
|
|
50
50
|
## Catch
|
|
51
51
|
|
|
@@ -61,10 +61,6 @@ Follow the notification guidance returned by `join`. When automatic notification
|
|
|
61
61
|
|
|
62
62
|
`history` is the only way to look back: remembering, not keeping up. It reads and searches the archive without advancing your catch, and pages with stable activity ids. Use `catch` to stay present. Never read or parse the binary Square artifact directly.
|
|
63
63
|
|
|
64
|
-
## Hold
|
|
65
|
-
|
|
66
|
-
`hold` raises a hand when the square should pause. Lower it with `hold` and `release: true` in the tools, or `resume` in the CLI.
|
|
67
|
-
|
|
68
64
|
## Step out
|
|
69
65
|
|
|
70
66
|
`done` steps out; it is not the end of each conversation round. You can join again later. Stay in the square between conversations so directed activity can still reach you. Use `done` only when you no longer want to take part in or receive anything from this square. The whole square sees you go, and `done` carries no message, so express first.
|
package/dist/square-backend.d.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import type { SqliteSquare } from './sqlite-square.js';
|
|
2
|
-
/** Structural resource contract extracted from the existing implementation.
|
|
3
|
-
* Backends implement the actual resource, not a second operation/policy dispatcher.
|
|
4
|
-
* Host-internal methods may explicitly refuse where their capabilities do not exist. */
|
|
5
|
-
export interface SquareBackend extends Pick<SqliteSquare, keyof SqliteSquare> {
|
|
6
|
-
}
|
|
7
|
-
export interface StdioBackendConfiguration {
|
|
8
|
-
readonly command: string;
|
|
9
|
-
readonly args?: readonly string[];
|
|
10
|
-
readonly cwd?: string;
|
|
11
|
-
readonly env?: Readonly<Record<string, string>>;
|
|
12
|
-
}
|
|
13
|
-
export type SquareBackends = Readonly<Record<string, StdioBackendConfiguration>>;
|
package/dist/square-backend.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/dist/square-stdio.d.ts
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { type SquareErrorCode, type SquareErrorFacts } from './model.js';
|
|
2
|
-
import type { SquareBackends, SquareBackend } from './square-backend.js';
|
|
3
|
-
import type { ParsedSquareLocation } from './square-location.js';
|
|
4
|
-
import type { OperationControl, OperationFailureDetail, SquareAtInput, SquareBuildInput } from './square-facade.js';
|
|
5
|
-
export declare const STDIO_PROTOCOL_VERSION = 2;
|
|
6
|
-
export declare const STDIO_MAX_FRAME_BYTES: number;
|
|
7
|
-
export declare const identityVariables: (import("./participant-identity.js").HarnessSessionVariable | "CLAUDE_CODE_CHILD_SESSION")[];
|
|
8
|
-
export declare function wireIdentity(env: NodeJS.ProcessEnv): Record<string, string>;
|
|
9
|
-
export interface WireError {
|
|
10
|
-
readonly code: number;
|
|
11
|
-
readonly message: string;
|
|
12
|
-
readonly data?: {
|
|
13
|
-
readonly code?: SquareErrorCode;
|
|
14
|
-
readonly facts?: SquareErrorFacts;
|
|
15
|
-
readonly operation?: OperationFailureDetail;
|
|
16
|
-
};
|
|
17
|
-
}
|
|
18
|
-
export declare function encodeError(error: unknown): WireError;
|
|
19
|
-
export declare function unsupported(feature: string): never;
|
|
20
|
-
export declare function openStdioSquare(location: string, selected: Extract<ParsedSquareLocation, {
|
|
21
|
-
kind: 'stdio';
|
|
22
|
-
}>, input: SquareAtInput, backends: SquareBackends, build?: Pick<SquareBuildInput, 'markdown' | 'hardCap' | 'throttlePerMinute' | 'template' | 'force'>, control?: OperationControl): Promise<SquareBackend>;
|