@astrosheep/square 0.3.63 → 0.3.65
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/claude-plugin/.claude-plugin/plugin.json +3 -2
- package/claude-plugin/hooks/hooks.json +1 -22
- package/claude-plugin/hooks/register.js +119 -0
- package/claude-plugin/types.d.ts +7 -0
- package/codex-plugin/.codex-plugin/plugin.json +1 -1
- package/dist/activity-feed.d.ts +1 -10
- package/dist/activity-feed.js +1 -27
- package/dist/activity.js +57 -25
- package/dist/artifact.d.ts +1 -1
- package/dist/artifact.js +24 -25
- package/dist/attention-presentation.js +1 -0
- package/dist/automatic-session.d.ts +3 -1
- package/dist/automatic-session.js +21 -34
- package/dist/boundary-presentation.js +4 -13
- package/dist/canonical-path.d.ts +11 -0
- package/dist/canonical-path.js +47 -0
- package/dist/catch-decisions.js +14 -10
- package/dist/catch-selection.d.ts +6 -0
- package/dist/catch-selection.js +14 -0
- package/dist/claude-delivery.d.ts +11 -0
- package/dist/claude-delivery.js +145 -0
- package/dist/claude-mod.d.ts +8 -0
- package/dist/claude-mod.js +164 -0
- package/dist/cli/context.d.ts +0 -1
- package/dist/cli/context.js +9 -21
- package/dist/cli/harness-command.d.ts +0 -1
- package/dist/cli/harness-command.js +0 -6
- package/dist/cli/observation-commands.d.ts +1 -1
- package/dist/cli/observation-commands.js +31 -58
- package/dist/cli/program.js +20 -18
- package/dist/cli/registry.js +2 -2
- package/dist/cli/square-commands.js +10 -6
- package/dist/codex-boundary-state.d.ts +2 -2
- package/dist/codex-boundary-state.js +4 -4
- package/dist/codex-hook.js +12 -15
- package/dist/codex-queue.d.ts +2 -2
- package/dist/codex-queue.js +7 -5
- package/dist/decisions.d.ts +2 -6
- package/dist/decisions.js +16 -17
- package/dist/delivery-health.d.ts +1 -2
- package/dist/delivery-health.js +4 -5
- package/dist/delivery-operations.d.ts +2 -5
- package/dist/delivery-operations.js +77 -214
- package/dist/delivery.d.ts +25 -47
- package/dist/delivery.js +14 -46
- package/dist/diagnostic-redaction.js +7 -9
- package/dist/file-changes.d.ts +0 -1
- package/dist/file-changes.js +2 -19
- package/dist/harness-claude.js +8 -6
- package/dist/harness-codex.d.ts +0 -2
- package/dist/harness-codex.js +0 -2
- package/dist/harness-links.js +13 -17
- package/dist/harness.js +3 -7
- package/dist/help.js +4 -3
- package/dist/host-ledger-file-adapter.d.ts +17 -8
- package/dist/host-ledger-file-adapter.js +164 -80
- package/dist/host-ledger.d.ts +55 -50
- package/dist/inbox.d.ts +0 -3
- package/dist/inbox.js +88 -50
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/list.js +1 -4
- package/dist/mcp.js +24 -41
- package/dist/mention-parse.js +3 -9
- package/dist/model.d.ts +11 -2
- package/dist/model.js +1 -1
- package/dist/notifications.d.ts +3 -16
- package/dist/notifications.js +41 -122
- package/dist/opencode-delivery.d.ts +14 -0
- package/dist/opencode-delivery.js +171 -0
- package/dist/opencode.d.ts +39 -18
- package/dist/opencode.js +145 -40
- package/dist/packages/agent-delivery/src/claude-auth.d.ts +13 -0
- package/dist/packages/agent-delivery/src/claude-auth.js +75 -0
- package/dist/packages/agent-delivery/src/claude-native.d.ts +28 -0
- package/dist/packages/agent-delivery/src/claude-native.js +68 -0
- package/dist/packages/agent-delivery/src/claude.d.ts +14 -0
- package/dist/packages/agent-delivery/src/claude.js +66 -0
- package/dist/packages/agent-delivery/src/deadline.d.ts +11 -0
- package/dist/packages/agent-delivery/src/deadline.js +41 -0
- package/dist/packages/agent-delivery/src/errors.d.ts +16 -0
- package/dist/packages/agent-delivery/src/errors.js +41 -0
- package/dist/packages/agent-delivery/src/guards.d.ts +6 -0
- package/dist/packages/agent-delivery/src/guards.js +6 -0
- package/dist/packages/agent-delivery/src/index.d.ts +83 -0
- package/dist/packages/agent-delivery/src/index.js +110 -0
- package/dist/packages/agent-delivery/src/local-endpoint.d.ts +26 -0
- package/dist/packages/agent-delivery/src/local-endpoint.js +114 -0
- package/dist/packages/agent-delivery/src/opencode-native.d.ts +33 -0
- package/dist/packages/agent-delivery/src/opencode-native.js +75 -0
- package/dist/packages/agent-delivery/src/opencode.d.ts +14 -0
- package/dist/packages/agent-delivery/src/opencode.js +127 -0
- package/dist/packages/agent-delivery/src/paseo-native.d.ts +58 -0
- package/dist/packages/agent-delivery/src/paseo-native.js +122 -0
- package/dist/packages/agent-delivery/src/paseo.d.ts +19 -0
- package/dist/packages/agent-delivery/src/paseo.js +106 -0
- package/dist/packages/agent-delivery/src/pi-client.d.ts +10 -0
- package/dist/packages/agent-delivery/src/pi-client.js +106 -0
- package/dist/packages/agent-delivery/src/pi-protocol.d.ts +15 -0
- package/dist/packages/agent-delivery/src/pi-protocol.js +50 -0
- package/dist/packages/agent-delivery/src/pi-send.d.ts +23 -0
- package/dist/packages/agent-delivery/src/pi-send.js +4 -0
- package/dist/packages/agent-delivery/src/pi.d.ts +25 -0
- package/dist/packages/agent-delivery/src/pi.js +209 -0
- package/dist/packages/agent-delivery/src/types.d.ts +120 -0
- package/dist/participant-host.js +12 -13
- package/dist/participant-identity.d.ts +21 -0
- package/dist/participant-identity.js +32 -11
- package/dist/paseo-delivery.d.ts +2 -2
- package/dist/paseo-delivery.js +35 -27
- package/dist/paseo-timeline.js +25 -21
- package/dist/paseo.d.ts +2 -2
- package/dist/paseo.js +1 -2
- package/dist/ports.d.ts +7 -20
- package/dist/presentation-operations.js +16 -4
- package/dist/presentation.d.ts +19 -10
- package/dist/presentation.js +99 -177
- package/dist/registry.d.ts +15 -66
- package/dist/registry.js +45 -123
- package/dist/routes.d.ts +1 -28
- package/dist/routes.js +22 -104
- package/dist/runtime.d.ts +3 -9
- package/dist/runtime.js +14 -67
- package/dist/search.d.ts +0 -2
- package/dist/search.js +3 -10
- package/dist/square-actions.js +48 -72
- package/dist/square-application.js +32 -30
- package/dist/square-core.d.ts +3 -0
- package/dist/square-core.js +22 -5
- package/dist/square-facade.d.ts +2 -0
- package/dist/square-file-adapter.d.ts +2 -1
- package/dist/square-file-adapter.js +6 -9
- package/dist/square-projections.d.ts +40 -45
- package/dist/square-projections.js +60 -74
- package/dist/square-state.js +1 -4
- package/dist/square-storage.d.ts +5 -8
- package/dist/square-storage.js +13 -36
- package/dist/square-wiring.d.ts +2 -7
- package/dist/square-wiring.js +6 -24
- package/dist/stream.js +4 -6
- package/dist/time.js +2 -7
- package/dist/views.d.ts +6 -18
- package/dist/views.js +14 -21
- package/dist/wake-attempts.d.ts +2 -56
- package/dist/wake-attempts.js +15 -110
- package/dist/wake-eligibility.d.ts +43 -0
- package/dist/wake-eligibility.js +106 -0
- package/dist/wake-evidence.d.ts +32 -9
- package/dist/wake-evidence.js +29 -24
- package/dist/wake-sink.d.ts +13 -9
- package/dist/wake-sink.js +35 -54
- package/dist/watch.js +13 -21
- package/extensions/square-pi.js +27 -13
- package/guides/change-waits.md +1 -1
- package/guides/claude-native.md +101 -0
- package/guides/host-ledger.md +3 -1
- package/guides/participant.md +14 -7
- package/guides/pi-native-delivery.md +49 -0
- package/package.json +4 -3
- package/dist/claude-hook.d.ts +0 -10
- package/dist/claude-hook.js +0 -60
- package/dist/paseo-connection.d.ts +0 -15
- package/dist/paseo-connection.js +0 -141
- package/dist/presence.d.ts +0 -2
- package/dist/presence.js +0 -24
- package/dist/presented.d.ts +0 -2
- package/dist/presented.js +0 -10
- package/dist/state-cell.d.ts +0 -14
- package/dist/wake-port.d.ts +0 -23
- package/dist/wake-port.js +0 -27
- /package/dist/{state-cell.js → packages/agent-delivery/src/types.js} +0 -0
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "square",
|
|
3
|
-
"version": "0.3.
|
|
4
|
-
"description": "Native Claude Code
|
|
3
|
+
"version": "0.3.65",
|
|
4
|
+
"description": "Native Claude Code inbox delivery for Square participants",
|
|
5
|
+
"types": "./types.d.ts",
|
|
5
6
|
"author": {
|
|
6
7
|
"name": "Square"
|
|
7
8
|
}
|
|
@@ -1,22 +1 @@
|
|
|
1
|
-
{
|
|
2
|
-
"description": "Bounded Square inbox admission between Claude Code agent steps",
|
|
3
|
-
"hooks": {
|
|
4
|
-
"SessionStart": [
|
|
5
|
-
{ "hooks": [{ "type": "command", "command": "square claude-hook", "timeout": 5 }] }
|
|
6
|
-
],
|
|
7
|
-
"SessionEnd": [
|
|
8
|
-
{ "hooks": [{ "type": "command", "command": "square claude-hook", "timeout": 5 }] }
|
|
9
|
-
],
|
|
10
|
-
"PostToolBatch": [
|
|
11
|
-
{
|
|
12
|
-
"hooks": [
|
|
13
|
-
{
|
|
14
|
-
"type": "command",
|
|
15
|
-
"command": "square claude-hook",
|
|
16
|
-
"timeout": 5
|
|
17
|
-
}
|
|
18
|
-
]
|
|
19
|
-
}
|
|
20
|
-
]
|
|
21
|
-
}
|
|
22
|
-
}
|
|
1
|
+
{"modules":["./register.js"]}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
// Claude Code 2.1.295 mod. No Node imports, shell interpolation, or child credentials.
|
|
2
|
+
const hasToken = (text) => typeof text === 'string' && /(?:^|\n)\[square-inbox:[a-zA-Z0-9-]+\](?:\n|$)/.test(text);
|
|
3
|
+
|
|
4
|
+
async function coordinate($) {
|
|
5
|
+
return { sessionId: await $.session.id(), cwd: await $.session.cwd(), version: (await $.session.version()).version, endpoint: await $.env.get('CLAUDE_CODE_MESSAGING_SOCKET') };
|
|
6
|
+
}
|
|
7
|
+
async function bridge($, value, budget = 2800) {
|
|
8
|
+
const result = await $.process.run(['square', 'claude-mod'], { cwd: value.cwd, stdin: JSON.stringify(value), timeoutMs: Math.max(1, Math.min(2800, budget)) });
|
|
9
|
+
if (result.exitCode !== 0 || result.isStdoutTruncated) throw new Error('Square native inbox bridge unavailable');
|
|
10
|
+
return JSON.parse(result.stdout);
|
|
11
|
+
}
|
|
12
|
+
async function snapshot($, id) { return (await $.state.get({ plugin: 'square', key: 'inbox', id })).value; }
|
|
13
|
+
async function cancellation($, id) { return (await $.state.get({ plugin: 'square', key: 'cancelAt', id })).value; }
|
|
14
|
+
function confirmLater($, c, operation, text) {
|
|
15
|
+
// State reads are dispatch snapshots. This ONE fresh timer dispatch is not polling.
|
|
16
|
+
// Reload cancels it; lost evidence stays unknown and is never blindly replayed.
|
|
17
|
+
try { $.clock.after(0, () => {
|
|
18
|
+
(async () => {
|
|
19
|
+
if (await $.session.id() !== c.sessionId) return;
|
|
20
|
+
const old = await snapshot($, c.sessionId);
|
|
21
|
+
const cancelled = await cancellation($, c.sessionId);
|
|
22
|
+
await bridge($, { ...c, cancelAt: cancelled?.at, cancelledBindings: cancelled?.bindings, bindings: old?.bindings, operation, text });
|
|
23
|
+
})().catch(() => undefined);
|
|
24
|
+
}); } catch { /* denied scheduling leaves evidence unknown, never a second next */ }
|
|
25
|
+
}
|
|
26
|
+
async function save($, id, update, version) {
|
|
27
|
+
return $.state.set({ plugin: 'square', key: 'inbox', id }, update, version === undefined ? undefined : { ifVersion: version });
|
|
28
|
+
}
|
|
29
|
+
async function reconcile($, sessionId, operation = 'start', resume = false) {
|
|
30
|
+
const read = await coordinate($);
|
|
31
|
+
const c = sessionId ? { ...read, sessionId } : read;
|
|
32
|
+
const held = await $.state.get({ plugin: 'square', key: 'inbox', id: c.sessionId });
|
|
33
|
+
const old = held.value;
|
|
34
|
+
const cancelled = await cancellation($, c.sessionId);
|
|
35
|
+
const result = await bridge($, { ...c, operation, cancelAt: cancelled?.at, cancelledBindings: cancelled?.bindings, bindings: old?.bindings, resume });
|
|
36
|
+
// A concurrent abort must win over a stale reconciliation write.
|
|
37
|
+
await save($, c.sessionId, { coordinate: c, bindings: result.bindings }, held.version);
|
|
38
|
+
if (!result.available) await $.ui.log(result.diagnostic);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async function cancel($) {
|
|
42
|
+
const c = await coordinate($);
|
|
43
|
+
const old = await snapshot($, c.sessionId);
|
|
44
|
+
const cancelAt = await $.clock.now();
|
|
45
|
+
const captured = old?.bindings ?? [];
|
|
46
|
+
await $.state.set({ plugin: 'square', key: 'cancelAt', id: c.sessionId }, { at: cancelAt, bindings: captured });
|
|
47
|
+
const result = await bridge($, { ...c, bindings: captured, cancelAt, cancelledBindings: captured, operation: 'cancel' });
|
|
48
|
+
try { $.clock.after(0, () => {
|
|
49
|
+
(async () => {
|
|
50
|
+
const held = await $.state.get({ plugin: 'square', key: 'cancelAt', id: c.sessionId });
|
|
51
|
+
if (held.value?.at === cancelAt) await $.state.set({ plugin: 'square', key: 'cancelAt', id: c.sessionId }, { at: cancelAt, bindings: result.cancelledBindings }, { ifVersion: held.version });
|
|
52
|
+
})().catch(() => undefined);
|
|
53
|
+
}); } catch { /* captured cancellation remains engine-owned */ }
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function register(on) {
|
|
57
|
+
on('session.start', async ($, e, next) => {
|
|
58
|
+
await reconcile($).catch(() => undefined);
|
|
59
|
+
return next(e);
|
|
60
|
+
});
|
|
61
|
+
on('classic.SessionStart', async ($, e, next) => {
|
|
62
|
+
await reconcile($, e.session_id, 'start', e.source === 'resume').catch(() => undefined);
|
|
63
|
+
return next(e);
|
|
64
|
+
});
|
|
65
|
+
on('tool.call', async ($, e, next) => {
|
|
66
|
+
try { return await next(e); }
|
|
67
|
+
finally { if (!e.agentId) await reconcile($, undefined, 'reconcile').catch(() => undefined); }
|
|
68
|
+
});
|
|
69
|
+
on('turn.start', async ($, e, next) => {
|
|
70
|
+
if (!e.agentId) await reconcile($, undefined, 'reconcile').catch(() => undefined);
|
|
71
|
+
return next(e);
|
|
72
|
+
});
|
|
73
|
+
on('session.end', async ($, e, next) => {
|
|
74
|
+
// Pinned old ID and captured ownership epochs, never a later current coordinate.
|
|
75
|
+
const endedAt = await $.clock.now().catch(() => undefined);
|
|
76
|
+
const held = await $.state.get({ plugin: 'square', key: 'inbox', id: e.sessionId }).catch(() => undefined);
|
|
77
|
+
const old = held?.value;
|
|
78
|
+
const c = old?.coordinate ?? await coordinate($).catch(() => undefined);
|
|
79
|
+
if (c) {
|
|
80
|
+
const result = await bridge($, { ...c, sessionId: e.sessionId, bindings: old?.bindings, endedAt, operation: 'end' }, next.budget.remainingMs).catch(() => undefined);
|
|
81
|
+
// Retired membership lives in the host ledger; conversation state may be cleared.
|
|
82
|
+
if (result) await save($, e.sessionId, { coordinate: { ...c, sessionId: e.sessionId }, bindings: [] }, held?.version).catch(() => undefined);
|
|
83
|
+
}
|
|
84
|
+
return next(e);
|
|
85
|
+
});
|
|
86
|
+
on('turn.abort', async ($, e, next) => {
|
|
87
|
+
await cancel($).catch(() => undefined);
|
|
88
|
+
return next(e);
|
|
89
|
+
});
|
|
90
|
+
on('turn.complete', async ($, e, next) => {
|
|
91
|
+
// Terminal Esc aborts are reported here, not through the plugin's turn.abort op.
|
|
92
|
+
if (!e.agentId && e.reason === 'aborted') await cancel($).catch(() => undefined);
|
|
93
|
+
return next(e);
|
|
94
|
+
});
|
|
95
|
+
on('session.receive', async ($, e, next) => {
|
|
96
|
+
if (e.agentId || e.origin?.kind !== 'peer' || !hasToken(e.text)) return next(e);
|
|
97
|
+
const c = await coordinate($).catch(() => undefined);
|
|
98
|
+
if (!c) return next(e);
|
|
99
|
+
const old = await snapshot($, c.sessionId).catch(() => undefined);
|
|
100
|
+
const cancelled = await cancellation($, c.sessionId).catch(() => undefined);
|
|
101
|
+
const guard = await bridge($, { ...c, cancelAt: cancelled?.at, cancelledBindings: cancelled?.bindings, bindings: old?.bindings, operation: 'guard', text: e.text }).catch(() => undefined);
|
|
102
|
+
if (guard?.recognized && !guard.current) return { consumed: 'Square delivery is stale or cancelled' };
|
|
103
|
+
// Preserve native policy: hold/refuse reject this gate; never call next twice.
|
|
104
|
+
const result = await next(e);
|
|
105
|
+
if (guard?.current && result.text === e.text) confirmLater($, c, 'admitted', result.text);
|
|
106
|
+
return result;
|
|
107
|
+
});
|
|
108
|
+
on('session.append', async ($, e, next) => {
|
|
109
|
+
if (e.agentId || e.origin?.kind !== 'peer') return next(e);
|
|
110
|
+
const c = await coordinate($).catch(() => undefined);
|
|
111
|
+
const result = await next(e);
|
|
112
|
+
if (!c || result.message?.role !== 'user') return result;
|
|
113
|
+
// Match a complete payload inside one returned stored text block, not entry text.
|
|
114
|
+
for (const block of result.message.content ?? []) {
|
|
115
|
+
if (block.type === 'text' && hasToken(block.text)) confirmLater($, c, 'stored', block.text);
|
|
116
|
+
}
|
|
117
|
+
return result;
|
|
118
|
+
});
|
|
119
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export type SquareInboxBinding = { location: string; participant: string; session: string; epoch?: number };
|
|
2
|
+
export type SquareInboxCoordinate = { sessionId: string; cwd: string; version: string; endpoint?: string };
|
|
3
|
+
export type SquareInboxCancellation = { at: number; bindings?: SquareInboxBinding[] };
|
|
4
|
+
export type SquareInboxState = { coordinate: SquareInboxCoordinate; bindings?: SquareInboxBinding[] };
|
|
5
|
+
declare module 'claude-code' {
|
|
6
|
+
interface PluginState { square: { inbox: StateFamily<SquareInboxState>; cancelAt: StateFamily<SquareInboxCancellation> } }
|
|
7
|
+
}
|
package/dist/activity-feed.d.ts
CHANGED
|
@@ -1,16 +1,7 @@
|
|
|
1
|
-
import { type StoredAct, type SquareState
|
|
2
|
-
export interface ActivityFeedFilter {
|
|
3
|
-
participants?: string[];
|
|
4
|
-
mention?: string;
|
|
5
|
-
}
|
|
1
|
+
import { type StoredAct, type SquareState } from './model.js';
|
|
6
2
|
export declare function actDelta(acts: StoredAct[], cursor: number): StoredAct[];
|
|
7
3
|
/** Visible activities after the participant's derived continuous-seen prefix. */
|
|
8
4
|
export declare function deliveryDelta(squareState: SquareState, name: string, delivery?: import("./delivery.js").DeliveryModel): StoredAct[];
|
|
9
|
-
export declare function peerRoomChanges(delta: StoredAct[], name: string): RoomChangeAct[];
|
|
10
|
-
export declare function peerPublicActs(delta: StoredAct[], name: string): PublicAct[];
|
|
11
5
|
export declare function directedPeerSays(squareState: SquareState, delta: StoredAct[], name: string, delivery?: import("./delivery.js").DeliveryModel): Extract<StoredAct, {
|
|
12
6
|
kind: 'say';
|
|
13
7
|
}>[];
|
|
14
|
-
export declare function matchesFeedFilter(act: StoredAct, filter: ActivityFeedFilter, recipients?: readonly string[]): boolean;
|
|
15
|
-
export declare function filteredPeerActivities(delta: StoredAct[], name: string, filter: ActivityFeedFilter): PublicAct[];
|
|
16
|
-
export declare function filteredRoomChanges(delta: StoredAct[], name: string, filter: ActivityFeedFilter): RoomChangeAct[];
|
package/dist/activity-feed.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { deriveDeliveryModel, matchesCatchFilter } from './delivery.js';
|
|
1
|
+
import { deriveDeliveryModel } from './delivery.js';
|
|
3
2
|
export function actDelta(acts, cursor) {
|
|
4
3
|
return acts.filter((act) => act.index > cursor);
|
|
5
4
|
}
|
|
@@ -7,31 +6,6 @@ export function actDelta(acts, cursor) {
|
|
|
7
6
|
export function deliveryDelta(squareState, name, delivery = deriveDeliveryModel(squareState)) {
|
|
8
7
|
return actDelta(squareState.acts, delivery.cursorFor(name));
|
|
9
8
|
}
|
|
10
|
-
export function peerRoomChanges(delta, name) {
|
|
11
|
-
return delta.filter((act) => act.actor !== undefined && !sameName(act.actor, name) && act.kind !== 'say' && act.kind !== 'read');
|
|
12
|
-
}
|
|
13
|
-
export function peerPublicActs(delta, name) {
|
|
14
|
-
return delta.filter((act) => act.actor !== undefined && !sameName(act.actor, name) && (act.kind === 'say' || act.kind === 'done'));
|
|
15
|
-
}
|
|
16
9
|
export function directedPeerSays(squareState, delta, name, delivery = deriveDeliveryModel(squareState)) {
|
|
17
10
|
return delta.filter((act) => delivery.directedTo(act, name));
|
|
18
11
|
}
|
|
19
|
-
function matchesParticipants(act, participants) {
|
|
20
|
-
return participants === undefined || (act.actor !== undefined && participants.some((participant) => sameName(participant, act.actor)));
|
|
21
|
-
}
|
|
22
|
-
export function matchesFeedFilter(act, filter, recipients) {
|
|
23
|
-
if (act.kind === 'say') {
|
|
24
|
-
return matchesCatchFilter({ actor: act.actor, body: act.body, mentions: act.mentions, reach: act.reach, ...(recipients === undefined ? {} : { recipients }) }, filter);
|
|
25
|
-
}
|
|
26
|
-
return filter.mention === undefined && matchesParticipants(act, filter.participants);
|
|
27
|
-
}
|
|
28
|
-
export function filteredPeerActivities(delta, name, filter) {
|
|
29
|
-
return peerPublicActs(delta, name)
|
|
30
|
-
.filter((act) => act.kind === 'say')
|
|
31
|
-
.filter((act) => matchesFeedFilter(act, filter));
|
|
32
|
-
}
|
|
33
|
-
export function filteredRoomChanges(delta, name, filter) {
|
|
34
|
-
if (filter.mention !== undefined)
|
|
35
|
-
return [];
|
|
36
|
-
return peerRoomChanges(delta, name).filter((act) => matchesParticipants(act, filter.participants));
|
|
37
|
-
}
|
package/dist/activity.js
CHANGED
|
@@ -14,20 +14,13 @@ import { formatDuration } from './time.js';
|
|
|
14
14
|
import { style } from './tty-style.js';
|
|
15
15
|
import { hostLedgerForEnv } from './registry.js';
|
|
16
16
|
import { createDefaultWakeTransport } from './notifications.js';
|
|
17
|
-
function draftDirFor(squarePath) {
|
|
18
|
-
return path.join(path.dirname(squarePath), 'drafts');
|
|
19
|
-
}
|
|
20
|
-
function draftTimestamp(at) {
|
|
21
|
-
return new Date(at).toISOString().replace(/\.\d{3}Z$/, 'Z').replace(/[:.]/g, '-');
|
|
22
|
-
}
|
|
23
|
-
function draftNamePart(name) {
|
|
24
|
-
return name.replace(/[^\p{L}\p{N}_-]+/gu, '-').replace(/^-+|-+$/g, '') || 'participant';
|
|
25
|
-
}
|
|
26
17
|
export function saveActivityDraft(squarePath, name, body) {
|
|
27
|
-
const draftDir =
|
|
18
|
+
const draftDir = path.join(path.dirname(squarePath), 'drafts');
|
|
28
19
|
fs.mkdirSync(draftDir, { recursive: true });
|
|
29
20
|
const hash = crypto.createHash('sha256').update(body).digest('hex').slice(0, 8);
|
|
30
|
-
const
|
|
21
|
+
const stamp = new Date(nowMs()).toISOString().replace(/\.\d{3}Z$/, 'Z').replace(/[:.]/g, '-');
|
|
22
|
+
const namePart = name.replace(/[^\p{L}\p{N}_-]+/gu, '-').replace(/^-+|-+$/g, '') || 'participant';
|
|
23
|
+
const base = `${stamp}-${namePart}-${hash}`;
|
|
31
24
|
for (let i = 0;; i++) {
|
|
32
25
|
const filename = `${base}${i === 0 ? '' : `-${i}`}.md`;
|
|
33
26
|
const target = path.join(draftDir, filename);
|
|
@@ -51,6 +44,20 @@ export function activityRetryCommand(squarePath, name, opts, force = opts.force
|
|
|
51
44
|
const reply = opts.reply === undefined ? '' : ` --reply ${replyIndex === undefined ? quoteShell(opts.reply) : formatActivityId(replyIndex)}`;
|
|
52
45
|
return `${participantCommandPrefix(squarePath, name)} express${force ? ' --force' : ''}${opts.noWait ? ' --no-wait' : ''}${reach}${reply} -`;
|
|
53
46
|
}
|
|
47
|
+
/**
|
|
48
|
+
* A recipient conflict is the speaker's to edit: the printed recovery drops every
|
|
49
|
+
* mention flag (or keeps the bell) so the retry never repeats the rejected target.
|
|
50
|
+
*/
|
|
51
|
+
function mentionRepairCommand(squarePath, name, opts, bell) {
|
|
52
|
+
const replyIndex = opts.reply === undefined ? undefined : parseActivityId(opts.reply);
|
|
53
|
+
const reply = opts.reply === undefined ? '' : ` --reply ${replyIndex === undefined ? quoteShell(opts.reply) : formatActivityId(replyIndex)}`;
|
|
54
|
+
const reach = bell ? ' --bell' : ' --no-mention';
|
|
55
|
+
return `${participantCommandPrefix(squarePath, name)} express${opts.force ? ' --force' : ''}${opts.noWait ? ' --no-wait' : ''}${reach}${reply} -`;
|
|
56
|
+
}
|
|
57
|
+
/** A body that is nothing but *gestures* reads as an action, not as speech. */
|
|
58
|
+
function isGestureOnly(body) {
|
|
59
|
+
return /\*[^*]*\*/.test(body) && body.replace(/\*[^*]*\*/g, '').trim() === '';
|
|
60
|
+
}
|
|
54
61
|
export async function cmdActivity(squarePath, name, activity, resolveBody, opts) {
|
|
55
62
|
const rawInput = String(resolveBody(activity));
|
|
56
63
|
const env = { ...(opts.env ?? process.env) };
|
|
@@ -99,7 +106,6 @@ export async function cmdActivity(squarePath, name, activity, resolveBody, opts)
|
|
|
99
106
|
const reentered = entry.kind === 'joined' && entry.activity !== null;
|
|
100
107
|
const before = await presentation();
|
|
101
108
|
const pendingPublic = before.pendingPublic;
|
|
102
|
-
const pendingRoomChanges = before.pendingRoomChanges;
|
|
103
109
|
expressAttempted = true;
|
|
104
110
|
const landed = await application.express(rawInput.replace(/\r\n/g, '\n').trim(), {
|
|
105
111
|
force: opts.force ?? false,
|
|
@@ -128,18 +134,28 @@ export async function cmdActivity(squarePath, name, activity, resolveBody, opts)
|
|
|
128
134
|
const headerCount = fresh.participantCount;
|
|
129
135
|
const held = fresh.held;
|
|
130
136
|
const ownActCount = fresh.ownActivityCount;
|
|
131
|
-
const hasPending = pendingPublic.length > 0
|
|
132
|
-
const
|
|
137
|
+
const hasPending = pendingPublic.length > 0;
|
|
138
|
+
const pendingSpeaker = pendingPublic[0]?.actor;
|
|
139
|
+
const pendingLead = pendingSpeaker === undefined
|
|
140
|
+
? ''
|
|
141
|
+
: `▲ while you spoke, ${participantIdentity(pendingSpeaker)} said something behind you\n\n`;
|
|
142
|
+
const pending = hasPending ? `\n\n${pendingLead}${renderPendingFeed([...fresh.activities], [...pendingPublic], knownName, fresh.state)}` : '';
|
|
133
143
|
const hint = expressHintLine(ownActCount);
|
|
134
|
-
const
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
144
|
+
const receiptId = landed.activity.id;
|
|
145
|
+
const capCount = fresh.hardCap === null ? '' : ` · ${ownActCount}/${fresh.hardCap}`;
|
|
146
|
+
const confirmation = landed.activity.reach === 'bell'
|
|
147
|
+
? `● you ring the bell — everyone turns · ${receiptId}${style('dim', capCount)}`
|
|
148
|
+
: `● ${landed.activity.mentions.length > 0
|
|
149
|
+
? `you walk over to ${landed.activity.mentions.map((target) => participantIdentity(target)).join(', ')}`
|
|
150
|
+
: isGestureOnly(landed.activity.body ?? '')
|
|
151
|
+
? 'your gesture lands'
|
|
152
|
+
: 'your words land'} — ${receiptId}${style('dim', capCount)}`;
|
|
140
153
|
const withHint = hint ? `${confirmation}\n${style('dim', hint)}` : confirmation;
|
|
154
|
+
const replyNotice = landed.replyAuthorNotHere === undefined
|
|
155
|
+
? ''
|
|
156
|
+
: `\n○ ${participantIdentity(landed.replyAuthorNotHere)} isn't in the square right now — the reply landed without reaching them`;
|
|
141
157
|
const reentry = reentered ? '● you stepped back into the square\n' : '';
|
|
142
|
-
process.stdout.write(withPathOutput(squarePath, reentry + withHint + pending, { participantCount: headerCount, held }));
|
|
158
|
+
process.stdout.write(withPathOutput(squarePath, reentry + withHint + replyNotice + pending, { participantCount: headerCount, held }));
|
|
143
159
|
}
|
|
144
160
|
catch (error) {
|
|
145
161
|
// Save before any recovery read: even a broken artifact must not eat the body.
|
|
@@ -159,7 +175,6 @@ export async function cmdActivity(squarePath, name, activity, resolveBody, opts)
|
|
|
159
175
|
retryCommand,
|
|
160
176
|
forceCommand,
|
|
161
177
|
activitySummaries: unreadActivitySummaries(fresh.state, knownName, nowMs()),
|
|
162
|
-
unreadRoomChanges: [],
|
|
163
178
|
}));
|
|
164
179
|
process.exit(1);
|
|
165
180
|
return;
|
|
@@ -178,7 +193,8 @@ export async function cmdActivity(squarePath, name, activity, resolveBody, opts)
|
|
|
178
193
|
...output,
|
|
179
194
|
reason: error.code,
|
|
180
195
|
delayMs: error.facts?.retryAfterMs ?? SLEEP_MS,
|
|
181
|
-
|
|
196
|
+
...(error.facts?.holder === undefined ? {} : { holder: error.facts.holder }),
|
|
197
|
+
...(error.facts?.holdReason === undefined ? {} : { holdReason: error.facts.holdReason }),
|
|
182
198
|
retryCommand,
|
|
183
199
|
}));
|
|
184
200
|
process.exit(1);
|
|
@@ -197,19 +213,35 @@ export async function cmdActivity(squarePath, name, activity, resolveBody, opts)
|
|
|
197
213
|
}
|
|
198
214
|
}
|
|
199
215
|
const lines = [error instanceof Error ? error.message : String(error), `· draft kept: ${draftPath}`];
|
|
216
|
+
const reason = isSquareError(error) ? error.facts?.reason : undefined;
|
|
217
|
+
// `not_standing` is a flag mention; the body-scan and bell conflicts carry an @name in the draft.
|
|
218
|
+
const mentionRepair = reason === 'bell_mention_conflict' ? { bell: true, fromBody: true }
|
|
219
|
+
: reason === 'unmatched_mention' ? { bell: false, fromBody: true }
|
|
220
|
+
: reason === 'not_standing' ? { bell: false, fromBody: false }
|
|
221
|
+
: undefined;
|
|
200
222
|
if (isSquareError(error)) {
|
|
201
223
|
if (callerMissing || error.code === 'unknown_participant' || error.code === 'not_joined')
|
|
202
224
|
lines.push(joinRecoveryCommand(squarePath, name));
|
|
203
225
|
if (error.code === 'already_joined')
|
|
204
226
|
lines.push(...takeoverRecoveryLines(squarePath, name));
|
|
205
|
-
if (
|
|
227
|
+
if (mentionRepair !== undefined) {
|
|
228
|
+
// The draft stays, but the retry no longer carries the target that was refused.
|
|
229
|
+
lines.push(participantsRecoveryCommand(squarePath));
|
|
230
|
+
lines.push(mentionRepair.fromBody
|
|
231
|
+
? " · edit the draft first — the body's @name must be removed or wrapped in backticks:"
|
|
232
|
+
: ' · pick someone standing here, or land it bare:');
|
|
233
|
+
lines.push(`${mentionRepairCommand(squarePath, name, opts, mentionRepair.bell)} < ${quoteShell(draftPath)}`);
|
|
234
|
+
}
|
|
235
|
+
else if (error.code === 'invalid_args' || error.code === 'invalid_name') {
|
|
206
236
|
if (opts.mentions?.length)
|
|
207
237
|
lines.push(participantsRecoveryCommand(squarePath));
|
|
208
238
|
if (opts.reply !== undefined)
|
|
209
239
|
lines.push(`${commandPrefix(squarePath)} history --limit 10`);
|
|
210
240
|
}
|
|
211
241
|
}
|
|
212
|
-
|
|
242
|
+
if (mentionRepair === undefined) {
|
|
243
|
+
lines.push(' · correct the problem above before retrying; keep your intended recipients and reply:', `${retryCommand} < ${quoteShell(draftPath)}`);
|
|
244
|
+
}
|
|
213
245
|
process.stderr.write(formatRefusal(squarePath, lines, output));
|
|
214
246
|
process.exit(2);
|
|
215
247
|
}
|
package/dist/artifact.d.ts
CHANGED
|
@@ -23,7 +23,7 @@ export declare function readSquareSnapshot(squarePath: string, signal?: AbortSig
|
|
|
23
23
|
/** Check the artifact revision without loading or parsing the historical state. */
|
|
24
24
|
export declare function readSquareRevision(squarePath: string, signal?: AbortSignal): Promise<number>;
|
|
25
25
|
/** One reference-counted revision detector per canonical artifact in this process. */
|
|
26
|
-
export declare function observeSquareRevision(squarePath: string): Promise<import('./file-changes.js').VersionObserver<number>>;
|
|
26
|
+
export declare function observeSquareRevision(squarePath: string): Promise<import('./file-changes.js').VersionObserver<number | null>>;
|
|
27
27
|
export type SquareTransition<R> = (state: SquareState, revision: number) => {
|
|
28
28
|
state?: SquareState;
|
|
29
29
|
result: R;
|
package/dist/artifact.js
CHANGED
|
@@ -31,14 +31,11 @@ function isNotFound(error) {
|
|
|
31
31
|
function isNotADatabase(error) {
|
|
32
32
|
return error instanceof Error && /not a database|file is not a database|SQLITE_NOTADB/i.test(error.message);
|
|
33
33
|
}
|
|
34
|
-
function
|
|
34
|
+
function openExistingDatabase(squarePath) {
|
|
35
35
|
const uri = pathToFileURL(path.resolve(squarePath));
|
|
36
36
|
uri.searchParams.set('mode', 'rw');
|
|
37
|
-
return uri.href;
|
|
38
|
-
}
|
|
39
|
-
function openExistingDatabase(squarePath) {
|
|
40
37
|
try {
|
|
41
|
-
return new DatabaseSync(
|
|
38
|
+
return new DatabaseSync(uri.href);
|
|
42
39
|
}
|
|
43
40
|
catch (error) {
|
|
44
41
|
if (isNotFound(error))
|
|
@@ -116,9 +113,6 @@ function validateDatabase(database) {
|
|
|
116
113
|
throw error;
|
|
117
114
|
}
|
|
118
115
|
}
|
|
119
|
-
function configureDatabase(database) {
|
|
120
|
-
database.exec('PRAGMA busy_timeout = 0; PRAGMA journal_mode = DELETE; PRAGMA synchronous = FULL;');
|
|
121
|
-
}
|
|
122
116
|
/** Opens an existing artifact without permitting SQLite to create a missing path. */
|
|
123
117
|
function readExistingArtifact(squarePath, read) {
|
|
124
118
|
requireSquareExtension(squarePath);
|
|
@@ -143,13 +137,6 @@ function readExistingArtifact(squarePath, read) {
|
|
|
143
137
|
function readSquareSnapshotOnce(squarePath) {
|
|
144
138
|
return readExistingArtifact(squarePath, validateDatabase);
|
|
145
139
|
}
|
|
146
|
-
function readSquareRevisionOnce(squarePath) {
|
|
147
|
-
return readExistingArtifact(squarePath, (database) => {
|
|
148
|
-
validateDatabaseHeader(database);
|
|
149
|
-
const rows = database.prepare(`SELECT id, revision FROM ${SNAPSHOT_TABLE}`).all();
|
|
150
|
-
return validateSnapshotRevision(rows);
|
|
151
|
-
});
|
|
152
|
-
}
|
|
153
140
|
async function createTemporaryArtifact(squarePath) {
|
|
154
141
|
const directory = path.dirname(squarePath);
|
|
155
142
|
await fs.promises.mkdir(directory, { recursive: true });
|
|
@@ -177,12 +164,6 @@ async function syncTemporaryArtifact(temporary) {
|
|
|
177
164
|
await handle.close();
|
|
178
165
|
}
|
|
179
166
|
}
|
|
180
|
-
async function removeTemporaryArtifact(temporary) {
|
|
181
|
-
try {
|
|
182
|
-
await fs.promises.unlink(temporary);
|
|
183
|
-
}
|
|
184
|
-
catch { /* cleanup cannot invalidate a published artifact */ }
|
|
185
|
-
}
|
|
186
167
|
function initializeDatabase(squarePath, state) {
|
|
187
168
|
const encoded = JSON.stringify(state);
|
|
188
169
|
let database;
|
|
@@ -222,7 +203,10 @@ export async function createSquareFile(squarePath, state) {
|
|
|
222
203
|
}
|
|
223
204
|
}
|
|
224
205
|
finally {
|
|
225
|
-
|
|
206
|
+
try {
|
|
207
|
+
await fs.promises.unlink(temporary);
|
|
208
|
+
}
|
|
209
|
+
catch { /* cleanup cannot invalidate a published artifact */ }
|
|
226
210
|
}
|
|
227
211
|
}
|
|
228
212
|
function isBusy(error) {
|
|
@@ -259,11 +243,26 @@ export function readSquareSnapshot(squarePath, signal) {
|
|
|
259
243
|
}
|
|
260
244
|
/** Check the artifact revision without loading or parsing the historical state. */
|
|
261
245
|
export function readSquareRevision(squarePath, signal) {
|
|
262
|
-
return readWithBusyRetry(() =>
|
|
246
|
+
return readWithBusyRetry(() => readExistingArtifact(squarePath, (database) => {
|
|
247
|
+
validateDatabaseHeader(database);
|
|
248
|
+
const rows = database.prepare(`SELECT id, revision FROM ${SNAPSHOT_TABLE}`).all();
|
|
249
|
+
return validateSnapshotRevision(rows);
|
|
250
|
+
}), signal);
|
|
263
251
|
}
|
|
264
252
|
/** One reference-counted revision detector per canonical artifact in this process. */
|
|
265
253
|
export function observeSquareRevision(squarePath) {
|
|
266
|
-
return observeFileVersion(squarePath, 'square-revision',
|
|
254
|
+
return observeFileVersion(squarePath, 'square-revision', async (file, signal) => {
|
|
255
|
+
try {
|
|
256
|
+
return await readSquareRevision(file, signal);
|
|
257
|
+
}
|
|
258
|
+
catch (error) {
|
|
259
|
+
if (signal?.aborted)
|
|
260
|
+
throw signal.reason ?? error;
|
|
261
|
+
if (error instanceof InternalSquareError && error.code === 'not_found')
|
|
262
|
+
return null;
|
|
263
|
+
throw error;
|
|
264
|
+
}
|
|
265
|
+
});
|
|
267
266
|
}
|
|
268
267
|
async function readWithBusyRetry(read, signal) {
|
|
269
268
|
while (true) {
|
|
@@ -305,7 +304,7 @@ export async function transactSquareSnapshot(squarePath, fn, signal, forceCommit
|
|
|
305
304
|
if (signal?.aborted)
|
|
306
305
|
throw signal.reason ?? closedError();
|
|
307
306
|
try {
|
|
308
|
-
|
|
307
|
+
database.exec('PRAGMA busy_timeout = 0; PRAGMA journal_mode = DELETE; PRAGMA synchronous = FULL;');
|
|
309
308
|
database.exec('BEGIN IMMEDIATE;');
|
|
310
309
|
begun = true;
|
|
311
310
|
break;
|
|
@@ -19,6 +19,7 @@ export function displayAttentionPath(squarePath) {
|
|
|
19
19
|
export function renderAttentionDescription({ actor, recipient, route }) {
|
|
20
20
|
switch (route) {
|
|
21
21
|
case 'mention': return `${actor} addressed you (${recipient})`;
|
|
22
|
+
case 'reply': return `${actor} replied to you (${recipient})`;
|
|
22
23
|
case 'attention': return `${actor} spoke · you’re listening to ${actor}`;
|
|
23
24
|
case 'bell': return `${actor} rang the bell · everyone’s attention`;
|
|
24
25
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
import { type AutomaticProvider } from './participant-identity.js';
|
|
2
|
+
export type { AutomaticProvider } from './participant-identity.js';
|
|
2
3
|
export { automaticParticipant } from './participant-identity.js';
|
|
4
|
+
export declare function operationEnv(provider: AutomaticProvider, sessionId: string, env: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
|
|
3
5
|
export declare function publicSquarePath(cwd: string): string;
|
|
4
6
|
export declare function automaticSessionStart(provider: AutomaticProvider, sessionId: string, cwd: string, env?: NodeJS.ProcessEnv): Promise<string | undefined>;
|
|
5
7
|
export declare function automaticSessionEnd(provider: AutomaticProvider, sessionId: string, cwd: string, env?: NodeJS.ProcessEnv): Promise<void>;
|
|
@@ -1,39 +1,26 @@
|
|
|
1
1
|
import { promises as fs } from 'node:fs';
|
|
2
|
-
import { hostLedgerRoot } from './host-ledger-root.js';
|
|
3
2
|
import path from 'node:path';
|
|
4
3
|
import { openSquare } from './square-file-adapter.js';
|
|
5
4
|
import { closeOpenSquare } from './open-square.js';
|
|
6
5
|
import { Square } from './square-wiring.js';
|
|
7
6
|
import { entryPresentation } from './views.js';
|
|
8
|
-
import { automaticParticipant } from './participant-identity.js';
|
|
7
|
+
import { automaticParticipant, harnessSessionSources } from './participant-identity.js';
|
|
9
8
|
import { SquareError } from './model.js';
|
|
10
|
-
import { createHostLedgerPort } from './host-ledger-file-adapter.js';
|
|
11
9
|
import { projectSessionBindings } from './square-projections.js';
|
|
12
|
-
import { claimSessionParticipant, readParticipantOwner, releaseSessionParticipant } from './registry.js';
|
|
10
|
+
import { claimSessionParticipant, hostLedgerForEnv, readParticipantOwner, releaseSessionParticipant } from './registry.js';
|
|
13
11
|
import { publishWakeRoute, resolvePrimaryWakeRoute, defaultWakeRouteCapabilities } from './routes.js';
|
|
14
12
|
export { automaticParticipant } from './participant-identity.js';
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
CODEX_THREAD_ID: '',
|
|
27
|
-
OPENCODE_SESSION_ID: '',
|
|
28
|
-
PI_SESSION_ID: '',
|
|
29
|
-
[providerEnv[provider]]: sessionId,
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
function hostLedgerForEnv(env) {
|
|
33
|
-
const root = hostLedgerRoot(env);
|
|
34
|
-
return createHostLedgerPort({
|
|
35
|
-
rootPath: root,
|
|
36
|
-
});
|
|
13
|
+
export function operationEnv(provider, sessionId, env) {
|
|
14
|
+
const scoped = { ...env };
|
|
15
|
+
// Clear every native coordinate (and the Claude child flag); PASEO_AGENT_ID stays as it is.
|
|
16
|
+
for (const source of harnessSessionSources) {
|
|
17
|
+
if (source.provider === undefined)
|
|
18
|
+
continue;
|
|
19
|
+
scoped[source.variable] = source.provider === provider ? sessionId : '';
|
|
20
|
+
if (source.childVariable !== undefined)
|
|
21
|
+
scoped[source.childVariable] = '';
|
|
22
|
+
}
|
|
23
|
+
return scoped;
|
|
37
24
|
}
|
|
38
25
|
export function publicSquarePath(cwd) {
|
|
39
26
|
return path.join(cwd, '.square', 'PUBLIC.square');
|
|
@@ -77,18 +64,18 @@ export async function automaticSessionStart(provider, sessionId, cwd, env = proc
|
|
|
77
64
|
throw new SquareError('already_joined', `✕ ${name} already stands here — another session holds the name`);
|
|
78
65
|
}
|
|
79
66
|
const scopedEnv = operationEnv(provider, sessionId, env);
|
|
80
|
-
const claim = await claimSessionParticipant(squarePath, name, scopedEnv);
|
|
81
|
-
const square = await Square.at({ path: squarePath, hostLedger
|
|
67
|
+
const claim = await claimSessionParticipant(squarePath, name, hostLedger, scopedEnv);
|
|
68
|
+
const square = await Square.at({ path: squarePath, hostLedger, env: scopedEnv });
|
|
82
69
|
try {
|
|
83
70
|
const implicit = await square.implicitJoin(name);
|
|
84
71
|
if (implicit.state === 'done') {
|
|
85
72
|
if (claim?.status === 'acquired')
|
|
86
|
-
await releaseSessionParticipant(squarePath, name, scopedEnv);
|
|
73
|
+
await releaseSessionParticipant(squarePath, name, hostLedger, scopedEnv);
|
|
87
74
|
return undefined;
|
|
88
75
|
}
|
|
89
|
-
const route = resolvePrimaryWakeRoute({ location: squarePath, participant: name, sessionId, provider }, env, await defaultWakeRouteCapabilities(
|
|
76
|
+
const route = resolvePrimaryWakeRoute({ location: squarePath, participant: name, sessionId, provider }, env, await defaultWakeRouteCapabilities(hostLedger));
|
|
90
77
|
if (route !== undefined) {
|
|
91
|
-
const publisher = await openSquare(squarePath, { hostLedger
|
|
78
|
+
const publisher = await openSquare(squarePath, { hostLedger, env: scopedEnv });
|
|
92
79
|
try {
|
|
93
80
|
await publishWakeRoute(publisher.artifact, { ...route, ...(claim?.epoch === undefined || claim.epoch <= 0 ? {} : { epoch: claim.epoch }) }, { at: Date.now(), requireCurrentSession: true });
|
|
94
81
|
}
|
|
@@ -96,7 +83,7 @@ export async function automaticSessionStart(provider, sessionId, cwd, env = proc
|
|
|
96
83
|
await closeOpenSquare(publisher);
|
|
97
84
|
}
|
|
98
85
|
}
|
|
99
|
-
await
|
|
86
|
+
await hostLedger.ensurePresence({
|
|
100
87
|
location: squarePath,
|
|
101
88
|
participant: name,
|
|
102
89
|
session: sessionId,
|
|
@@ -108,7 +95,7 @@ export async function automaticSessionStart(provider, sessionId, cwd, env = proc
|
|
|
108
95
|
}
|
|
109
96
|
catch (error) {
|
|
110
97
|
if (claim?.status === 'acquired')
|
|
111
|
-
await releaseSessionParticipant(squarePath, name, scopedEnv).catch(() => undefined);
|
|
98
|
+
await releaseSessionParticipant(squarePath, name, hostLedger, scopedEnv).catch(() => undefined);
|
|
112
99
|
throw error;
|
|
113
100
|
}
|
|
114
101
|
finally {
|
|
@@ -129,7 +116,7 @@ export async function automaticSessionEnd(provider, sessionId, cwd, env = proces
|
|
|
129
116
|
}))[0];
|
|
130
117
|
const expectedEpoch = binding === undefined
|
|
131
118
|
? undefined
|
|
132
|
-
: (await readParticipantOwner(squarePath, binding.participant,
|
|
119
|
+
: (await readParticipantOwner(squarePath, binding.participant, hostLedger))?.epoch;
|
|
133
120
|
await closeOpenSquare(probe);
|
|
134
121
|
const square = await Square.at({ path: squarePath, hostLedger, env: scopedEnv });
|
|
135
122
|
try {
|