@astrosheep/square 0.3.69 → 0.3.71
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 +4 -5
- package/dist/activity-feed.js +14 -10
- package/dist/artifact.d.ts +26 -33
- package/dist/artifact.js +346 -317
- package/dist/attention-presentation.js +2 -9
- package/dist/automatic-session.js +6 -6
- package/dist/boundary-presentation.js +3 -3
- package/dist/catch-decisions.d.ts +19 -12
- package/dist/catch-decisions.js +32 -68
- package/dist/claude-delivery.js +7 -7
- package/dist/claude-mod.js +18 -7
- package/dist/cli/catch-presentation.d.ts +7 -0
- package/dist/cli/catch-presentation.js +55 -0
- package/dist/cli/context.d.ts +1 -1
- package/dist/cli/context.js +5 -23
- package/dist/cli/express-presentation.d.ts +10 -0
- package/dist/cli/express-presentation.js +196 -0
- package/dist/cli/maintenance-commands.d.ts +4 -0
- package/dist/cli/maintenance-commands.js +29 -6
- package/dist/cli/observation-commands.d.ts +7 -5
- package/dist/cli/observation-commands.js +275 -262
- package/dist/cli/program.d.ts +1 -1
- package/dist/cli/program.js +43 -56
- package/dist/cli/registry.js +2 -1
- package/dist/cli/square-commands.d.ts +3 -9
- package/dist/cli/square-commands.js +134 -255
- package/dist/codex-queue.js +4 -1
- package/dist/decisions.d.ts +26 -74
- package/dist/decisions.js +190 -335
- package/dist/delivery-health.js +13 -22
- package/dist/delivery-operations.d.ts +0 -11
- package/dist/delivery-operations.js +44 -33
- package/dist/delivery.d.ts +33 -32
- package/dist/delivery.js +70 -81
- package/dist/harness-claude.js +1 -1
- package/dist/harness-codex.js +1 -1
- package/dist/harness-pi.js +1 -1
- package/dist/help.js +6 -1
- package/dist/inbox.d.ts +27 -0
- package/dist/inbox.js +55 -18
- package/dist/index.d.ts +2 -4
- package/dist/index.js +1 -1
- package/dist/list.d.ts +7 -1
- package/dist/list.js +49 -122
- package/dist/mcp.d.ts +1 -1
- package/dist/mcp.js +7 -37
- package/dist/model.d.ts +4 -44
- package/dist/model.js +1 -3
- package/dist/notifications.d.ts +1 -1
- package/dist/notifications.js +13 -7
- package/dist/open-square.d.ts +16 -2
- package/dist/open-square.js +40 -1
- package/dist/perception-projection.d.ts +6 -15
- package/dist/perception-projection.js +6 -26
- package/dist/{opencode-delivery.d.ts → plugins/opencode/delivery.d.ts} +1 -1
- package/dist/{opencode-delivery.js → plugins/opencode/delivery.js} +18 -18
- package/dist/{opencode.d.ts → plugins/opencode/index.d.ts} +2 -2
- package/dist/{opencode.js → plugins/opencode/index.js} +9 -9
- package/dist/ports.d.ts +156 -11
- package/dist/presentation-operations.d.ts +1 -1
- package/dist/presentation-operations.js +35 -44
- package/dist/presentation.d.ts +12 -19
- package/dist/presentation.js +33 -54
- package/dist/routes.d.ts +7 -14
- package/dist/routes.js +33 -62
- package/dist/runtime.d.ts +12 -39
- package/dist/runtime.js +33 -164
- package/dist/square-actions.d.ts +11 -21
- package/dist/square-actions.js +171 -271
- package/dist/square-application.d.ts +31 -55
- package/dist/square-application.js +637 -141
- package/dist/square-core.d.ts +3 -94
- package/dist/square-core.js +8 -353
- package/dist/square-domain.d.ts +24 -0
- package/dist/square-domain.js +77 -0
- package/dist/square-facade.d.ts +360 -9
- package/dist/square-migration.d.ts +24 -0
- package/dist/square-migration.js +211 -0
- package/dist/square-projections.d.ts +2 -42
- package/dist/square-projections.js +1 -37
- package/dist/square-sqlite.d.ts +59 -0
- package/dist/square-sqlite.js +702 -0
- package/dist/stream.d.ts +3 -10
- package/dist/stream.js +81 -52
- package/dist/views.d.ts +27 -95
- package/dist/views.js +217 -87
- package/dist/wake-eligibility.d.ts +15 -5
- package/dist/wake-eligibility.js +32 -16
- package/dist/wakes.d.ts +3 -3
- package/dist/wakes.js +31 -27
- package/guides/application-facade-delivery-evidence.md +200 -0
- package/guides/application-facade-design.md +95 -0
- package/guides/change-waits.md +4 -4
- package/guides/migration.md +77 -0
- package/guides/pi-native-delivery.md +1 -1
- package/guides/primitive-catch-consolidation.md +85 -0
- package/guides/primitive-history-consolidation.md +76 -0
- package/guides/primitive-status-consolidation.md +87 -0
- package/guides/primitive-storage-consolidation.md +128 -0
- package/guides/row-runtime-delivery-evidence.md +160 -0
- package/guides/row-storage-design.md +567 -0
- package/package.json +5 -7
- package/{claude-plugin → plugins/claude}/.claude-plugin/plugin.json +1 -1
- package/{codex-plugin → plugins/codex}/.codex-plugin/plugin.json +1 -1
- package/plugins/opencode/delivery.ts +149 -0
- package/plugins/opencode/index.ts +136 -0
- package/plugins/paseo/OVERVIEW.md +14 -0
- package/plugins/paseo/README.md +54 -0
- package/plugins/paseo/client/square-message.tsx +106 -0
- package/plugins/paseo/client/transform.ts +24 -0
- package/plugins/paseo/index.client.tsx +19 -0
- package/plugins/paseo/package.json +19 -0
- package/plugins/paseo/paseo-plugin.json +7 -0
- package/plugins/paseo/shared/message.ts +29 -0
- package/{extensions → plugins/pi}/square-pi.js +8 -5
- package/dist/activity.d.ts +0 -14
- package/dist/activity.js +0 -248
- package/dist/square-file-adapter.d.ts +0 -26
- package/dist/square-file-adapter.js +0 -85
- package/dist/square-state.d.ts +0 -6
- package/dist/square-state.js +0 -138
- package/dist/square-storage.d.ts +0 -14
- package/dist/square-storage.js +0 -188
- package/dist/square-wiring.d.ts +0 -33
- package/dist/square-wiring.js +0 -109
- package/dist/watch.d.ts +0 -8
- package/dist/watch.js +0 -252
- /package/{claude-plugin → plugins/claude}/hooks/hooks.json +0 -0
- /package/{claude-plugin → plugins/claude}/hooks/register.js +0 -0
- /package/{claude-plugin → plugins/claude}/skills/square/SKILL.md +0 -0
- /package/{claude-plugin → plugins/claude}/types.d.ts +0 -0
- /package/{codex-plugin → plugins/codex}/hooks/hooks.json +0 -0
|
@@ -25,17 +25,13 @@ export function renderAttentionDescription({ actor, recipient, route }) {
|
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
27
|
export function renderAttentionPreview(attention) {
|
|
28
|
-
// The fence is what keeps the body from being re-rendered by Markdown. It grows past any
|
|
29
|
-
// backtick run in the body so a body containing a fence cannot break out of this one.
|
|
30
|
-
// Everything outside the fence is the system's voice, which participant bodies cannot fake.
|
|
31
|
-
const fence = '`'.repeat(Math.max(3, longestBacktickRun(attention.body) + 1));
|
|
32
28
|
return [
|
|
33
|
-
|
|
29
|
+
'<square-activity>',
|
|
34
30
|
`· ${displayAttentionPath(attention.squarePath)} · ${formatActivityId(attention.actIndex)}`,
|
|
35
31
|
`● ${renderAttentionDescription(attention)}`,
|
|
36
32
|
'',
|
|
37
33
|
previewAttentionBody(attention.body),
|
|
38
|
-
|
|
34
|
+
'</square-activity>',
|
|
39
35
|
// A clipped body ends with the full command to read it all: a labeled caption, then the
|
|
40
36
|
// command bare on its own line so it can be copied and run as it is.
|
|
41
37
|
...(attentionBodyIsClipped(attention.body)
|
|
@@ -43,6 +39,3 @@ export function renderAttentionPreview(attention) {
|
|
|
43
39
|
: []),
|
|
44
40
|
].join('\n');
|
|
45
41
|
}
|
|
46
|
-
function longestBacktickRun(value) {
|
|
47
|
-
return value.match(/`+/g)?.reduce((longest, run) => Math.max(longest, run.length), 0) ?? 0;
|
|
48
|
-
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { promises as fs } from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
import { openSquare } from './square
|
|
3
|
+
import { openSquare } from './open-square.js';
|
|
4
4
|
import { closeOpenSquare } from './open-square.js';
|
|
5
|
-
import { Square } from './square-
|
|
6
|
-
import {
|
|
5
|
+
import { Square } from './square-application.js';
|
|
6
|
+
import { currentParticipant } from './views.js';
|
|
7
7
|
import { automaticParticipant, harnessSessionSources } from './participant-identity.js';
|
|
8
8
|
import { SquareError } from './model.js';
|
|
9
9
|
import { projectSessionBindings } from './square-projections.js';
|
|
@@ -49,10 +49,10 @@ export async function automaticSessionStart(provider, sessionId, cwd, env = proc
|
|
|
49
49
|
const name = automaticParticipant(provider, sessionId, env);
|
|
50
50
|
const hostLedger = hostLedgerForEnv(env);
|
|
51
51
|
let bindings;
|
|
52
|
-
let
|
|
52
|
+
let standing;
|
|
53
53
|
try {
|
|
54
54
|
bindings = await hostLedger.listPresence({ location: squarePath, participant: name });
|
|
55
|
-
|
|
55
|
+
standing = await currentParticipant(reader, name);
|
|
56
56
|
}
|
|
57
57
|
finally {
|
|
58
58
|
await closeOpenSquare(reader);
|
|
@@ -60,7 +60,7 @@ export async function automaticSessionStart(provider, sessionId, cwd, env = proc
|
|
|
60
60
|
if (bindings.some((binding) => binding.session !== sessionId)) {
|
|
61
61
|
throw new SquareError('already_joined', `✕ ${name} already stands here — another session holds the name`);
|
|
62
62
|
}
|
|
63
|
-
if (
|
|
63
|
+
if (standing !== undefined && !bindings.some((binding) => binding.session === sessionId)) {
|
|
64
64
|
throw new SquareError('already_joined', `✕ ${name} already stands here — another session holds the name`);
|
|
65
65
|
}
|
|
66
66
|
const scopedEnv = operationEnv(provider, sessionId, env);
|
|
@@ -2,7 +2,7 @@ import { hostLedgerRoot } from './host-ledger-root.js';
|
|
|
2
2
|
import { createHash } from 'node:crypto';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { withFileLock } from './file-lock.js';
|
|
5
|
-
import { openSquare } from './square
|
|
5
|
+
import { openSquare } from './open-square.js';
|
|
6
6
|
import { closeOpenSquare } from './open-square.js';
|
|
7
7
|
import { presentPending } from './presentation-operations.js';
|
|
8
8
|
import { hostLedgerForEnv } from './registry.js';
|
|
@@ -117,8 +117,8 @@ async function presentPendingAtBoundaryUnlocked(sessionId, present, lookup = ses
|
|
|
117
117
|
// A stale projection can outlive its activity; still surface the bounded preview,
|
|
118
118
|
// but there is no artifact observation to commit.
|
|
119
119
|
if (!outcome.presented) {
|
|
120
|
-
const
|
|
121
|
-
if (
|
|
120
|
+
const exists = await square.artifact.read((facts) => facts.activity(index) !== undefined, signal).catch(() => undefined);
|
|
121
|
+
if (exists?.value === false)
|
|
122
122
|
await renderOnce();
|
|
123
123
|
}
|
|
124
124
|
});
|
|
@@ -1,17 +1,24 @@
|
|
|
1
|
-
import { type
|
|
2
|
-
import { type
|
|
3
|
-
import {
|
|
1
|
+
import { type ActivityId } from './square-core.js';
|
|
2
|
+
import { type StoredAct } from './model.js';
|
|
3
|
+
import type { DirectedFilter, SquareRead, SquareWrite } from './ports.js';
|
|
4
4
|
import type { CatchOptions } from './square-facade.js';
|
|
5
|
-
export interface
|
|
6
|
-
readonly
|
|
7
|
-
readonly
|
|
8
|
-
readonly
|
|
9
|
-
readonly consumedThrough: string | null;
|
|
10
|
-
readonly changed: boolean;
|
|
5
|
+
export interface CatchSelection {
|
|
6
|
+
readonly participant: string;
|
|
7
|
+
readonly activities: readonly StoredAct[];
|
|
8
|
+
readonly consumedThrough: ActivityId | null;
|
|
11
9
|
readonly remaining: number;
|
|
10
|
+
readonly sayNumbers: Readonly<Record<number, number>>;
|
|
11
|
+
readonly standingCount: number;
|
|
12
|
+
readonly held: boolean;
|
|
13
|
+
readonly now: number;
|
|
14
|
+
readonly ownActivityCount: number;
|
|
15
|
+
readonly hardCap: number | null;
|
|
16
|
+
readonly terminalStatus: 'capped' | 'quorum' | undefined;
|
|
12
17
|
}
|
|
18
|
+
/** Capture a selected page (or an empty completion) without opening another resource. */
|
|
19
|
+
export declare function observeCatchSelection(facts: SquareRead, participant: string, activities: readonly StoredAct[], filter: DirectedFilter, at: number): CatchSelection;
|
|
13
20
|
export declare const CATCH_DEFAULT_LIMIT = 10;
|
|
14
21
|
export declare const CATCH_MAX_LIMIT = 100;
|
|
15
|
-
export
|
|
16
|
-
/**
|
|
17
|
-
export declare function decideCatch(
|
|
22
|
+
export declare function catchLimit(value: number | undefined): number;
|
|
23
|
+
/** Selection, receipts and resulting cursor belong to one artifact write transaction. */
|
|
24
|
+
export declare function decideCatch(facts: SquareWrite, requestedName: string, options: CatchOptions, at: number): CatchSelection;
|
package/dist/catch-decisions.js
CHANGED
|
@@ -1,88 +1,52 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
import { formatActivityId, parseActivityId } from './square-core.js';
|
|
2
|
+
import { inSquareCount, readCursor, watchTerminalStatus } from './runtime.js';
|
|
3
|
+
import { SquareError } from './model.js';
|
|
4
|
+
import { resolveKnownName } from './decisions.js';
|
|
5
|
+
/** Capture a selected page (or an empty completion) without opening another resource. */
|
|
6
|
+
export function observeCatchSelection(facts, participant, activities, filter, at) {
|
|
7
|
+
const cursor = readCursor(facts, participant);
|
|
8
|
+
return {
|
|
9
|
+
participant, activities, consumedThrough: cursor < 0 ? null : formatActivityId(cursor),
|
|
10
|
+
remaining: facts.directedCount(participant, filter),
|
|
11
|
+
sayNumbers: activities.length === 0 ? {} : facts.sayOrdinals(activities.map((item) => item.index)),
|
|
12
|
+
standingCount: inSquareCount(facts), held: facts.hold().active, now: at,
|
|
13
|
+
ownActivityCount: facts.participant(participant).sayCount, hardCap: facts.header().hardCap,
|
|
14
|
+
terminalStatus: watchTerminalStatus(facts, participant),
|
|
15
|
+
};
|
|
16
|
+
}
|
|
8
17
|
export const CATCH_DEFAULT_LIMIT = 10;
|
|
9
18
|
export const CATCH_MAX_LIMIT = 100;
|
|
10
|
-
function catchLimit(value) {
|
|
19
|
+
export function catchLimit(value) {
|
|
11
20
|
const limit = value ?? CATCH_DEFAULT_LIMIT;
|
|
12
21
|
if (!Number.isSafeInteger(limit) || limit < 1 || limit > CATCH_MAX_LIMIT) {
|
|
13
22
|
throw new SquareError('invalid_args', `Catch limit must be a positive integer no greater than ${CATCH_MAX_LIMIT}.`);
|
|
14
23
|
}
|
|
15
24
|
return limit;
|
|
16
25
|
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const
|
|
20
|
-
if (known === undefined) {
|
|
21
|
-
throw new SquareError('invalid_args', `✕ ${participantIdentity(requestedName)} has never stepped into this square`, { reason: 'never_joined' });
|
|
22
|
-
}
|
|
23
|
-
return known;
|
|
24
|
-
}
|
|
25
|
-
/** Pure catch selection and acknowledgement over one SquareState snapshot. */
|
|
26
|
-
export function decideCatch(state, requestedName, options, at, project = derivePerceptionProjection) {
|
|
27
|
-
const viewer = resolveCatchName(state, requestedName);
|
|
26
|
+
/** Selection, receipts and resulting cursor belong to one artifact write transaction. */
|
|
27
|
+
export function decideCatch(facts, requestedName, options, at) {
|
|
28
|
+
const viewer = resolveKnownName(facts, requestedName);
|
|
28
29
|
const limit = catchLimit(options.limit);
|
|
29
|
-
|
|
30
|
+
let delivered;
|
|
31
|
+
let filter = { unseenOnly: true };
|
|
30
32
|
if (options.id !== undefined) {
|
|
31
|
-
if (['idle', 'from', 'mention', 'limit'].some((key) => Object.hasOwn(options, key)))
|
|
33
|
+
if (['idle', 'from', 'mention', 'limit'].some((key) => Object.hasOwn(options, key)))
|
|
32
34
|
throw new SquareError('invalid_args', 'Catch id cannot be combined with idle, from, mention or limit.');
|
|
33
|
-
}
|
|
34
35
|
const index = parseActivityId(options.id);
|
|
35
36
|
if (index === undefined)
|
|
36
37
|
throw new SquareError('invalid_args', 'Invalid catch id: expected an activity id like act/12.');
|
|
37
|
-
const activity =
|
|
38
|
-
if (activity === undefined || activity.kind !== 'say' ||
|
|
38
|
+
const activity = facts.activity(index);
|
|
39
|
+
if (activity === undefined || activity.kind !== 'say' || facts.directedAt(viewer, index) === undefined) {
|
|
39
40
|
throw new SquareError('invalid_args', `✕ ${formatActivityId(index)} isn't addressed to you`, {
|
|
40
|
-
reason: 'not_addressed',
|
|
41
|
-
activityId: formatActivityId(index),
|
|
42
|
-
activityExists: activity !== undefined,
|
|
41
|
+
reason: 'not_addressed', activityId: formatActivityId(index), activityExists: activity !== undefined,
|
|
43
42
|
});
|
|
44
43
|
}
|
|
45
|
-
|
|
46
|
-
const changed = recordObservation(state, viewer, index, 'seen', at);
|
|
47
|
-
const cursor = delivery.cursorFor(viewer);
|
|
48
|
-
return {
|
|
49
|
-
viewer,
|
|
50
|
-
delivered: [activity],
|
|
51
|
-
perceptions: new Map([[index, perception]]),
|
|
52
|
-
consumedThrough: cursor < 0 ? null : formatActivityId(cursor),
|
|
53
|
-
changed,
|
|
54
|
-
remaining: state.acts.filter((item) => item.kind === 'say' && delivery.directedTo(item, viewer) && !delivery.isSeen(viewer, item.index)).length,
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
const filter = { participants: options.from, mention: options.mention === true ? viewer : undefined };
|
|
58
|
-
const authors = activityAuthors(state.acts);
|
|
59
|
-
const delivered = [];
|
|
60
|
-
const perceptions = new Map();
|
|
61
|
-
const matching = [];
|
|
62
|
-
for (const activity of state.acts) {
|
|
63
|
-
if (activity.kind !== 'say' || !delivery.directedTo(activity, viewer))
|
|
64
|
-
continue;
|
|
65
|
-
const replyAuthor = activity.reply === undefined ? undefined : authors.get(activity.reply);
|
|
66
|
-
if (!matchesCatchSelection(activity.actor, audienceOf(activity), filter, replyAuthor))
|
|
67
|
-
continue;
|
|
68
|
-
if (delivery.isSeen(viewer, activity.index))
|
|
69
|
-
continue;
|
|
70
|
-
matching.push(activity);
|
|
44
|
+
delivered = [activity];
|
|
71
45
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
let changed = false;
|
|
76
|
-
for (const activity of delivered) {
|
|
77
|
-
changed = recordObservation(state, viewer, activity.index, 'seen', at) || changed;
|
|
46
|
+
else {
|
|
47
|
+
filter = { unseenOnly: true, ...(options.from === undefined ? {} : { senders: options.from }), ...(options.mention === true ? { attentionOnly: true } : {}) };
|
|
48
|
+
delivered = facts.activities(facts.directed(viewer, filter, { edge: 'oldest', limit }).items.map((item) => item.index));
|
|
78
49
|
}
|
|
79
|
-
|
|
80
|
-
return
|
|
81
|
-
viewer,
|
|
82
|
-
delivered,
|
|
83
|
-
perceptions,
|
|
84
|
-
consumedThrough: consumed < 0 ? null : formatActivityId(consumed),
|
|
85
|
-
changed,
|
|
86
|
-
remaining: Math.max(0, matching.length - delivered.length),
|
|
87
|
-
};
|
|
50
|
+
facts.markSeen(viewer, delivered.map((item) => item.index), at);
|
|
51
|
+
return observeCatchSelection(facts, viewer, delivered, filter, at);
|
|
88
52
|
}
|
package/dist/claude-delivery.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { stat } from 'node:fs/promises';
|
|
2
|
-
import { openSquare } from './square
|
|
2
|
+
import { openSquare } from './open-square.js';
|
|
3
3
|
import { closeOpenSquare } from './open-square.js';
|
|
4
4
|
import { hostLedgerForEnv } from './registry.js';
|
|
5
|
-
import {
|
|
5
|
+
import { projectPresentationEvidence, presentationSuppressesWake } from './square-projections.js';
|
|
6
|
+
import { nativePendingPreview } from './inbox.js';
|
|
6
7
|
import { presentPending } from './presentation-operations.js';
|
|
7
8
|
import { canonicalPath } from './canonical-path.js';
|
|
8
9
|
import { parseActivityId } from './square-core.js';
|
|
@@ -54,8 +55,7 @@ async function currentDelivery(row, hostLedger) {
|
|
|
54
55
|
return undefined;
|
|
55
56
|
const square = await openSquare(owner.location, { hostLedger });
|
|
56
57
|
try {
|
|
57
|
-
const
|
|
58
|
-
const preview = nativePendingPreview(state, { location: row.location, routeKind: 'claude-native', sessionId: row.session, participant: row.participant, actIndex: index, epoch: native.epoch, address: { endpoint: native.endpoint }, cancelledThrough: owner.cancelledThrough, now: Date.now() });
|
|
58
|
+
const { value: preview } = await square.artifact.read((facts) => nativePendingPreview(facts, { location: row.location, routeKind: 'claude-native', sessionId: row.session, participant: row.participant, actIndex: index, epoch: native.epoch, address: { endpoint: native.endpoint }, cancelledThrough: owner.cancelledThrough, now: Date.now() }));
|
|
59
59
|
if (!preview || nativePayload(row.claimToken, preview.payload) !== native.payload)
|
|
60
60
|
return undefined;
|
|
61
61
|
return { cancelledThrough: owner.cancelledThrough, clipped: preview.clipped };
|
|
@@ -82,7 +82,7 @@ async function dispatchClaude(request, hostLedger, timeoutMs, beforeSend, env =
|
|
|
82
82
|
let payload;
|
|
83
83
|
try {
|
|
84
84
|
const index = parseActivityId(request.activity);
|
|
85
|
-
const preview = index === undefined ? undefined :
|
|
85
|
+
const preview = index === undefined ? undefined : (await square.artifact.read((facts) => nativePendingPreview(facts, { location: request.location, routeKind: 'claude-native', sessionId: request.route.sessionId, participant: request.participant, actIndex: index, epoch: request.route.epoch, address: { endpoint: request.route.address.endpoint }, cancelledThrough: owner.cancelledThrough, now: Date.now() }))).value;
|
|
86
86
|
if (!preview)
|
|
87
87
|
return { outcome: 'not-capable', diagnostic: 'Catch or consumption owns this activity.' };
|
|
88
88
|
payload = nativePayload(request.claimToken, preview.payload);
|
|
@@ -127,11 +127,11 @@ export async function observeClaudeDelivery(sessionId, text, operation, env = pr
|
|
|
127
127
|
continue;
|
|
128
128
|
const square = await openSquare(row.location, { hostLedger: ledger, env });
|
|
129
129
|
try {
|
|
130
|
-
await presentPending({ artifact: square.artifact, hostLedger: ledger, location: row.location, participant: row.participant, session: sessionId, activity: row.activity, sink: { present() { } }, markSeen: !pending.clipped, current: (
|
|
130
|
+
await presentPending({ artifact: square.artifact, hostLedger: ledger, location: row.location, participant: row.participant, session: sessionId, activity: row.activity, sink: { present() { } }, markSeen: !pending.clipped, current: (facts) => {
|
|
131
131
|
const index = parseActivityId(row.activity);
|
|
132
132
|
if (index === undefined)
|
|
133
133
|
return false;
|
|
134
|
-
const preview = nativePendingPreview(
|
|
134
|
+
const preview = nativePendingPreview(facts, { location: row.location, routeKind: 'claude-native', sessionId: row.session, participant: row.participant, actIndex: index, epoch: native.epoch, address: { endpoint: native.endpoint }, cancelledThrough: pending.cancelledThrough, now: Date.now() });
|
|
135
135
|
return preview !== undefined && nativePayload(row.claimToken, preview.payload) === native.payload;
|
|
136
136
|
} });
|
|
137
137
|
}
|
package/dist/claude-mod.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { automaticSessionStart, operationEnv } from './automatic-session.js';
|
|
2
2
|
import { claimSessionParticipant, hostLedgerForEnv } from './registry.js';
|
|
3
|
-
import { openSquare } from './square
|
|
3
|
+
import { openSquare } from './open-square.js';
|
|
4
4
|
import { closeOpenSquare } from './open-square.js';
|
|
5
5
|
import { publishWakeRoute, retireWakeRouteFromArtifact } from './routes.js';
|
|
6
|
-
import { Square } from './square-
|
|
6
|
+
import { Square } from './square-application.js';
|
|
7
7
|
import { observeClaudeDelivery } from './claude-delivery.js';
|
|
8
8
|
import { processActNotificationsOnce } from './notifications.js';
|
|
9
9
|
import { sweepPending } from './delivery-operations.js';
|
|
@@ -61,8 +61,9 @@ export async function runClaudeMod(inputText, env = process.env) {
|
|
|
61
61
|
const probe = await openSquare(row.location, { hostLedger: ledger, env: scoped, signal });
|
|
62
62
|
let eligible = false;
|
|
63
63
|
try {
|
|
64
|
-
const
|
|
65
|
-
|
|
64
|
+
const { value: last } = await probe.artifact.read((facts) => facts.activityHeads({
|
|
65
|
+
actors: [row.participant], actorMatch: 'exact', kinds: ['join', 'done'],
|
|
66
|
+
}, { edge: 'newest', limit: 1 }).items[0], signal);
|
|
66
67
|
eligible = last?.kind === 'done' && `act/${last.index}` === row.activity;
|
|
67
68
|
}
|
|
68
69
|
finally {
|
|
@@ -111,8 +112,7 @@ export async function runClaudeMod(inputText, env = process.env) {
|
|
|
111
112
|
await ledger.ensurePresence({ ...current, epoch });
|
|
112
113
|
const square = await openSquare(binding.location, { hostLedger: ledger, env: scoped, signal });
|
|
113
114
|
try {
|
|
114
|
-
const
|
|
115
|
-
const existing = state.routes?.find((route) => route.participant === binding.participant && route.sessionId === input.sessionId && route.kind === 'claude-native' && route.epoch === epoch);
|
|
115
|
+
const { value: existing } = await square.artifact.read((facts) => facts.routes().find((route) => route.participant === binding.participant && route.sessionId === input.sessionId && route.kind === 'claude-native' && route.epoch === epoch), signal);
|
|
116
116
|
if (!supported) {
|
|
117
117
|
if (existing)
|
|
118
118
|
await retireWakeRouteFromArtifact(square.artifact, existing, { expectedEpoch: epoch });
|
|
@@ -120,7 +120,18 @@ export async function runClaudeMod(inputText, env = process.env) {
|
|
|
120
120
|
}
|
|
121
121
|
const cutoff = cancelled?.epoch === epoch || (lateCancelledJoin && current.epoch === binding.epoch && (current.updatedAt ?? Infinity) <= input.cancelAt) ? input.cancelAt : undefined;
|
|
122
122
|
if (cutoff !== undefined) {
|
|
123
|
-
const
|
|
123
|
+
const { value: through } = await square.artifact.read((facts) => {
|
|
124
|
+
let beforeIndex;
|
|
125
|
+
for (;;) {
|
|
126
|
+
const page = facts.activityHeads({ beforeIndex }, { edge: 'newest', limit: 100 });
|
|
127
|
+
const last = [...page.items].reverse().find((activity) => activity.at <= cutoff);
|
|
128
|
+
if (last !== undefined)
|
|
129
|
+
return last.index;
|
|
130
|
+
if (!page.hasMore)
|
|
131
|
+
return -1;
|
|
132
|
+
beforeIndex = page.items[0].index;
|
|
133
|
+
}
|
|
134
|
+
}, signal);
|
|
124
135
|
await ledger.suppressPresence({ ...current, epoch }, through);
|
|
125
136
|
}
|
|
126
137
|
if (!existing || existing.address.endpoint !== input.endpoint)
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ApplicationOutcome, CatchApplicationData, CatchApplicationOptions, CatchProjection, OperationProgress } from '../square-facade.js';
|
|
2
|
+
export declare function renderCatchProgress(squarePath: string, progress: OperationProgress): string | undefined;
|
|
3
|
+
/** Render settled catch facts; no selection, terminal decisions, receipts or wait machinery. */
|
|
4
|
+
export declare function renderCatchOutcome(squarePath: string, outcome: ApplicationOutcome<CatchApplicationData, CatchProjection>, options?: CatchApplicationOptions): {
|
|
5
|
+
stdout: string;
|
|
6
|
+
exitCode: number;
|
|
7
|
+
};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { parseActivityId } from '../square-application.js';
|
|
2
|
+
import { participantCommandPrefix, renderAmbientEvent, renderWatchAlreadyActive, renderWatchForceTakeover, renderWatchReplaceMissing, renderWatchReplaced, renderWatchStatus, withPathOutput, } from '../presentation.js';
|
|
3
|
+
export function renderCatchProgress(squarePath, progress) {
|
|
4
|
+
if (progress.kind !== 'catch-started' || !progress.replacementRequested)
|
|
5
|
+
return undefined;
|
|
6
|
+
const options = { squarePath, name: progress.participant };
|
|
7
|
+
return (progress.replaced
|
|
8
|
+
? renderWatchForceTakeover(options) : renderWatchReplaceMissing(options)) + '\n';
|
|
9
|
+
}
|
|
10
|
+
function continuationCommand(squarePath, name, options) {
|
|
11
|
+
const args = ['--now'];
|
|
12
|
+
if (options.from?.length)
|
|
13
|
+
args.push('--from', options.from.join(','));
|
|
14
|
+
if (options.mention)
|
|
15
|
+
args.push('--mention');
|
|
16
|
+
if (options.limit !== undefined)
|
|
17
|
+
args.push('--limit', String(options.limit));
|
|
18
|
+
return `${participantCommandPrefix(squarePath, name)} catch ${args.join(' ')}`;
|
|
19
|
+
}
|
|
20
|
+
/** Render settled catch facts; no selection, terminal decisions, receipts or wait machinery. */
|
|
21
|
+
export function renderCatchOutcome(squarePath, outcome, options = {}) {
|
|
22
|
+
const { data, projection } = outcome;
|
|
23
|
+
const location = projection.location ?? squarePath;
|
|
24
|
+
const name = projection.participant;
|
|
25
|
+
const stop = projection.stop ?? data.status;
|
|
26
|
+
const header = { participantCount: projection.standingCount, held: projection.held };
|
|
27
|
+
const statusOptions = {
|
|
28
|
+
squarePath: location, name, presence: projection.presence,
|
|
29
|
+
showCatchHint: !projection.automaticDeliveryAvailable,
|
|
30
|
+
ownActivityCount: projection.ownActivityCount, hardCap: projection.hardCap,
|
|
31
|
+
};
|
|
32
|
+
if (stop === 'already-active' || stop === 'replaced') {
|
|
33
|
+
return {
|
|
34
|
+
stdout: withPathOutput(location, stop === 'already-active'
|
|
35
|
+
? renderWatchAlreadyActive(statusOptions) : renderWatchReplaced(statusOptions), header),
|
|
36
|
+
exitCode: stop === 'already-active' ? 1 : 0,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
const rendered = data.activities.map((activity) => renderAmbientEvent(activity, name, {
|
|
40
|
+
now: projection.now, actNumber: projection.sayNumbers[parseActivityId(activity.id)],
|
|
41
|
+
perception: activity.perception, mention: options.mention ? name : undefined,
|
|
42
|
+
})).filter(Boolean).join('\n\n');
|
|
43
|
+
const remaining = data.remaining === 0 ? ''
|
|
44
|
+
: `○ ${data.remaining} matching ${data.remaining === 1 ? 'activity remains' : 'activities remain'}\n${continuationCommand(location, name, options)}`;
|
|
45
|
+
const terminal = stop === undefined ? '' : renderWatchStatus({
|
|
46
|
+
...statusOptions, status: stop,
|
|
47
|
+
...(stop === 'stale' && options.idle !== undefined ? { idleMs: options.idle } : {}),
|
|
48
|
+
});
|
|
49
|
+
const fallback = stop === undefined && !projection.automaticDeliveryAvailable && data.remaining === 0
|
|
50
|
+
? `${participantCommandPrefix(location, name)} catch --idle 30m\n stay available for new activity` : '';
|
|
51
|
+
return {
|
|
52
|
+
stdout: withPathOutput(location, [terminal, rendered, remaining, fallback].filter(Boolean).join('\n\n'), header),
|
|
53
|
+
exitCode: stop === 'capped' ? 1 : 0,
|
|
54
|
+
};
|
|
55
|
+
}
|
package/dist/cli/context.d.ts
CHANGED
|
@@ -23,7 +23,6 @@ export declare function parseBoundedLimit(value: string | undefined, flag: strin
|
|
|
23
23
|
export declare function parseNonNegativeInteger(value: string, flag: string): number;
|
|
24
24
|
export declare function parseHardCap(value: string): HardCap;
|
|
25
25
|
export declare function parseNameList(value: string, flag: string): string[];
|
|
26
|
-
export declare function requireParticipant(name: string | undefined): string;
|
|
27
26
|
export interface ParsedGlobalArgs {
|
|
28
27
|
squarePath?: string;
|
|
29
28
|
explicitSquarePath: boolean;
|
|
@@ -34,4 +33,5 @@ export interface ParsedGlobalArgs {
|
|
|
34
33
|
export declare function parseGlobalArgs(rawArgs: string[]): Promise<ParsedGlobalArgs>;
|
|
35
34
|
export declare function locationIsRequired(command: string): boolean;
|
|
36
35
|
export declare function defaultContext(command: string, squarePath?: string, name?: string): CommandContext;
|
|
36
|
+
export declare function applicationFor(context: CommandContext): import("../square-facade.js").SquareApplication;
|
|
37
37
|
export declare function requireSquarePath(context: CommandContext): string;
|
package/dist/cli/context.js
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import os from 'node:os';
|
|
2
2
|
import { commandUsageHint } from '../help.js';
|
|
3
3
|
import { parseParticipantList, validateName } from '../model.js';
|
|
4
|
-
import {
|
|
5
|
-
import { projectSessionBindings } from '../square-projections.js';
|
|
6
|
-
import { sessionIdsFromEnvironment } from '../participant-identity.js';
|
|
4
|
+
import { createSquareApplication } from '../square-application.js';
|
|
7
5
|
export async function readStdin() {
|
|
8
6
|
try {
|
|
9
7
|
let content = '';
|
|
@@ -87,12 +85,6 @@ export function parseNameList(value, flag) {
|
|
|
87
85
|
validateName(name);
|
|
88
86
|
return names;
|
|
89
87
|
}
|
|
90
|
-
export function requireParticipant(name) {
|
|
91
|
-
if (!name)
|
|
92
|
-
fail('✕ missing required option: --as <name>');
|
|
93
|
-
validateName(name);
|
|
94
|
-
return name;
|
|
95
|
-
}
|
|
96
88
|
const LOCATION_REQUIRED_COMMANDS = new Set([
|
|
97
89
|
'build',
|
|
98
90
|
'stream',
|
|
@@ -110,6 +102,7 @@ const LOCATION_REQUIRED_COMMANDS = new Set([
|
|
|
110
102
|
'participants',
|
|
111
103
|
'mcp-server',
|
|
112
104
|
'doctor',
|
|
105
|
+
'migrate',
|
|
113
106
|
]);
|
|
114
107
|
export async function parseGlobalArgs(rawArgs) {
|
|
115
108
|
const args = [...rawArgs];
|
|
@@ -128,11 +121,6 @@ export async function parseGlobalArgs(rawArgs) {
|
|
|
128
121
|
}
|
|
129
122
|
}
|
|
130
123
|
const command = args[0];
|
|
131
|
-
if (name === undefined) {
|
|
132
|
-
const configured = process.env.SQUARE_PARTICIPANT_NAME?.trim();
|
|
133
|
-
if (configured)
|
|
134
|
-
name = configured;
|
|
135
|
-
}
|
|
136
124
|
if (name !== undefined)
|
|
137
125
|
validateName(name);
|
|
138
126
|
const explicitSquarePath = requestedPath !== undefined;
|
|
@@ -142,15 +130,6 @@ export async function parseGlobalArgs(rawArgs) {
|
|
|
142
130
|
fail(`✕ ${command} needs a square location\nsquare ls`);
|
|
143
131
|
}
|
|
144
132
|
const squarePath = requestedPath ?? configured;
|
|
145
|
-
if (name === undefined && squarePath !== undefined && command !== undefined && locationIsRequired(command)) {
|
|
146
|
-
const bindings = (await Promise.all(sessionIdsFromEnvironment().map((sessionId) => projectSessionBindings({
|
|
147
|
-
hostLedger: createHostLedgerPort(),
|
|
148
|
-
location: squarePath,
|
|
149
|
-
sessionId,
|
|
150
|
-
})))).flat();
|
|
151
|
-
const names = new Set(bindings.map((binding) => binding.participant));
|
|
152
|
-
name = names.size === 1 ? [...names][0] : undefined;
|
|
153
|
-
}
|
|
154
133
|
return { squarePath, explicitSquarePath: explicitSquarePath || configured !== undefined, multipleSquares: false, name, args };
|
|
155
134
|
}
|
|
156
135
|
export function locationIsRequired(command) {
|
|
@@ -159,6 +138,9 @@ export function locationIsRequired(command) {
|
|
|
159
138
|
export function defaultContext(command, squarePath, name) {
|
|
160
139
|
return { command, cwd: process.cwd(), env: { ...process.env }, squarePath, name, homeDir: os.homedir() };
|
|
161
140
|
}
|
|
141
|
+
export function applicationFor(context) {
|
|
142
|
+
return createSquareApplication({ cwd: context.cwd, env: context.env, squarePath: context.squarePath, participant: context.name });
|
|
143
|
+
}
|
|
162
144
|
export function requireSquarePath(context) {
|
|
163
145
|
if (context.squarePath === undefined)
|
|
164
146
|
fail(`✕ ${context.command} needs a square location\nsquare ls`);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ApplicationOutcome, ExpressApplicationData, ExpressApplicationOptions, ExpressProjection, SquareApplication } from '../square-facade.js';
|
|
2
|
+
export interface ActivityOptions extends Omit<ExpressApplicationOptions, 'reply'> {
|
|
3
|
+
readonly reply?: string;
|
|
4
|
+
}
|
|
5
|
+
export declare function saveActivityDraft(squarePath: string, name: string, body: string, now?: number): string;
|
|
6
|
+
/** Retry choices are transport syntax, never a second admission decision. */
|
|
7
|
+
export declare function activityRetryCommand(squarePath: string, name: string, opts: ActivityOptions, force?: boolean): string;
|
|
8
|
+
export declare function renderExpression(squarePath: string, outcome: ApplicationOutcome<ExpressApplicationData, ExpressProjection>): string;
|
|
9
|
+
/** Body adaptation, terminal IO and drafts only; the application owns every attempt and wait. */
|
|
10
|
+
export declare function executeExpression(application: SquareApplication, squarePath: string, requestedName: string | undefined, rawInput: string, opts: ActivityOptions): Promise<void>;
|