@astrosheep/square 0.3.95 → 0.3.97
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/artifact.d.ts +1 -1
- package/dist/artifact.js +11 -17
- package/dist/attention-presentation.d.ts +5 -4
- package/dist/attention-presentation.js +18 -8
- package/dist/boundary-presentation.js +31 -26
- package/dist/channel.d.ts +74 -0
- package/dist/channel.js +92 -0
- package/dist/claude-delivery.js +3 -9
- package/dist/cli/observation-commands.js +2 -2
- package/dist/codex-hook.d.ts +0 -2
- package/dist/codex-hook.js +0 -1
- package/dist/decisions.d.ts +2 -11
- package/dist/decisions.js +3 -8
- package/dist/delivery-health.js +3 -13
- package/dist/delivery.d.ts +1 -11
- package/dist/delivery.js +2 -9
- package/dist/identity.d.ts +0 -1
- package/dist/identity.js +0 -1
- package/dist/inbox.js +11 -7
- package/dist/mcp.js +65 -63
- package/dist/model.d.ts +6 -0
- package/dist/model.js +19 -0
- package/dist/notifications.d.ts +1 -1
- package/dist/ports.d.ts +5 -5
- package/dist/presentation-operations.d.ts +1 -0
- package/dist/sqlite-square.d.ts +3 -2
- package/dist/sqlite-square.js +91 -9
- package/dist/square-core.d.ts +1 -0
- package/dist/square-domain.js +22 -7
- package/dist/square-facade.d.ts +36 -10
- package/dist/square-sqlite.js +33 -4
- package/dist/square-tools.d.ts +1 -0
- package/dist/square-tools.js +9 -1
- package/dist/views.d.ts +1 -2
- package/dist/views.js +1 -9
- package/guides/operation-cancellation.md +5 -1
- package/guides/primitive-status-consolidation.md +1 -1
- package/guides/receive-primitive.md +4 -2
- package/guides/row-runtime-delivery-evidence.md +3 -3
- package/guides/row-storage-design.md +5 -1
- package/guides/square-api.md +63 -7
- package/package.json +5 -2
- package/plugins/claude/.claude-plugin/plugin.json +1 -1
- package/plugins/codex/.codex-plugin/plugin.json +1 -1
- package/plugins/codex/hooks/hooks.json +6 -6
- package/plugins/paseo/client/marble.ts +7 -0
- package/plugins/paseo/client/markdown.tsx +65 -9
- package/plugins/paseo/client/palette.ts +43 -20
- package/plugins/paseo/client/square-message.tsx +57 -48
- package/plugins/paseo/shared/message.ts +1 -2
- package/plugins/pi/square-pi.js +6 -4
package/dist/square-facade.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { DeliveryDeferral, MetadataMatch } from './delivery-deferral.js';
|
|
2
2
|
export type { DeliveryDeferral, MetadataMatch, MetadataScalar } from './delivery-deferral.js';
|
|
3
3
|
import type { ActivityId, Perception, Reach } from './square-core.js';
|
|
4
|
-
import type { Owner, StoredAct, WakeAddress, ActivityMetadata, DirectedNotificationRoute } from './model.js';
|
|
4
|
+
import type { Owner, StoredAct, WakeAddress, ActivityMetadata, ActivityDelivery, DirectedNotificationRoute } from './model.js';
|
|
5
5
|
import type { WakeTransportPort, SquareResourceOwner } from './ports.js';
|
|
6
6
|
export type { ActivityId, Perception, Reach } from './square-core.js';
|
|
7
|
-
export type { Owner, WakeAddress, ActivityMetadata, JsonValue, DirectedNotificationRoute } from './model.js';
|
|
7
|
+
export type { Owner, WakeAddress, ActivityMetadata, ActivityDelivery, JsonValue, DirectedNotificationRoute } from './model.js';
|
|
8
8
|
/** Indexed archive event, including read bookkeeping. */
|
|
9
9
|
export type ArchiveRecord = Readonly<StoredAct>;
|
|
10
10
|
export interface Activity {
|
|
@@ -14,6 +14,7 @@ export interface Activity {
|
|
|
14
14
|
readonly actor: string;
|
|
15
15
|
readonly body?: string;
|
|
16
16
|
readonly metadata?: ActivityMetadata;
|
|
17
|
+
readonly delivery?: ActivityDelivery;
|
|
17
18
|
readonly mentions: readonly string[];
|
|
18
19
|
readonly reach?: Reach;
|
|
19
20
|
readonly target?: string;
|
|
@@ -49,6 +50,22 @@ export interface ExpressResult {
|
|
|
49
50
|
readonly hint?: string;
|
|
50
51
|
readonly observation?: ExpressObservation;
|
|
51
52
|
}
|
|
53
|
+
export type ChannelTruncate = number | false;
|
|
54
|
+
export interface ChannelSendInput {
|
|
55
|
+
readonly from: string;
|
|
56
|
+
readonly to: string | readonly string[];
|
|
57
|
+
readonly body: string;
|
|
58
|
+
readonly truncate?: ChannelTruncate;
|
|
59
|
+
readonly metadata?: ActivityMetadata;
|
|
60
|
+
}
|
|
61
|
+
export interface ChannelSendResult {
|
|
62
|
+
readonly id: ActivityId;
|
|
63
|
+
readonly at: number;
|
|
64
|
+
readonly from: string;
|
|
65
|
+
readonly to: readonly string[];
|
|
66
|
+
readonly body: string;
|
|
67
|
+
readonly metadata?: ActivityMetadata;
|
|
68
|
+
}
|
|
52
69
|
export interface ListenerChangeResult {
|
|
53
70
|
readonly activity: Activity | null;
|
|
54
71
|
readonly observation?: ListenerObservation;
|
|
@@ -69,6 +86,20 @@ export interface CatchOptions extends ObservationOptions {
|
|
|
69
86
|
readonly limit?: number;
|
|
70
87
|
readonly replace?: boolean;
|
|
71
88
|
}
|
|
89
|
+
export interface PendingOptions {
|
|
90
|
+
readonly match?: MetadataMatch;
|
|
91
|
+
/** Oldest first; defaults to 100, maximum 100. */
|
|
92
|
+
readonly limit?: number;
|
|
93
|
+
}
|
|
94
|
+
export interface PendingResult {
|
|
95
|
+
readonly activities: readonly PerceivedActivity[];
|
|
96
|
+
/** Matching unconsumed activities outside this page. */
|
|
97
|
+
readonly remaining: number;
|
|
98
|
+
}
|
|
99
|
+
export interface AckResult {
|
|
100
|
+
/** Newly consumed addressed IDs; repeated acknowledgement is a no-op. */
|
|
101
|
+
readonly consumed: number;
|
|
102
|
+
}
|
|
72
103
|
export type CatchReason = 'drained' | 'idle' | 'capped' | 'quorum' | 'replaced' | 'already-active';
|
|
73
104
|
export interface CatchResult {
|
|
74
105
|
readonly activities: readonly PerceivedActivity[];
|
|
@@ -128,14 +159,6 @@ export interface HistoryResult {
|
|
|
128
159
|
readonly activities: readonly Activity[];
|
|
129
160
|
readonly observation?: HistoryObservation;
|
|
130
161
|
}
|
|
131
|
-
export interface SquareSnapshot {
|
|
132
|
-
readonly context: string;
|
|
133
|
-
readonly actCount: number;
|
|
134
|
-
readonly hardCap: number | null;
|
|
135
|
-
readonly throttlePerMinute?: number;
|
|
136
|
-
readonly participants: readonly Pick<ParticipantSummary, 'name' | 'presence' | 'listening'>[];
|
|
137
|
-
delivered(name: string, id: ActivityId): boolean;
|
|
138
|
-
}
|
|
139
162
|
export interface OpenOptions {
|
|
140
163
|
readonly clock?: () => number;
|
|
141
164
|
readonly wakeTransport?: WakeTransportPort | false;
|
|
@@ -170,6 +193,7 @@ export interface JoinResult {
|
|
|
170
193
|
}
|
|
171
194
|
export interface Participant {
|
|
172
195
|
readonly name: string;
|
|
196
|
+
readonly generation: ActivityId;
|
|
173
197
|
express(body: string | undefined, options?: ExpressOptions, control?: OperationControl): Promise<ExpressResult>;
|
|
174
198
|
express(input: ExpressInput, control?: OperationControl): Promise<ExpressResult>;
|
|
175
199
|
listen(target: string, options?: ObservationOptions, control?: OperationControl): Promise<ListenerChangeResult>;
|
|
@@ -177,6 +201,8 @@ export interface Participant {
|
|
|
177
201
|
unlisten(target: string, options?: ObservationOptions, control?: OperationControl): Promise<ListenerChangeResult>;
|
|
178
202
|
listening(options?: ObservationOptions, control?: OperationControl): Promise<ListeningResult>;
|
|
179
203
|
catch(options?: CatchOptions, control?: OperationControl): Promise<CatchResult>;
|
|
204
|
+
pending(options?: PendingOptions, control?: OperationControl): Promise<PendingResult>;
|
|
205
|
+
ack(ids: readonly ActivityId[], control?: OperationControl): Promise<AckResult>;
|
|
180
206
|
/** Leave without a message. Only an omitted or empty body is accepted. */
|
|
181
207
|
done(body?: string, options?: ObservationOptions, control?: OperationControl): Promise<LifecycleResult>;
|
|
182
208
|
deferDelivery(input: Readonly<{
|
package/dist/square-sqlite.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { DatabaseSync as MemoryDatabase } from 'node:sqlite';
|
|
2
|
-
import { SquareError, nameKey, isWakeRouteKind, validateOwner, validateActivityMetadata, activityMetadataHasContent } from './model.js';
|
|
2
|
+
import { SquareError, nameKey, isWakeRouteKind, validateOwner, validateActivityMetadata, validateActivityDelivery, activityMetadataHasContent } from './model.js';
|
|
3
3
|
import { validateMetadataMatch, matchingDeferrals, validateDeferralId } from './delivery-deferral.js';
|
|
4
4
|
import { deriveLanding, landingFacts } from './square-domain.js';
|
|
5
5
|
import { claimAttempt, prepareAttempt, settleAttempt } from './delivery-attempts.js';
|
|
@@ -269,7 +269,16 @@ export function validateStoredActivity(value) {
|
|
|
269
269
|
string(a.actor, true);
|
|
270
270
|
switch (a.kind) {
|
|
271
271
|
case 'say':
|
|
272
|
-
shape(a, [...common], ['body', 'mentions', 'reach', 'reply', 'metadata']);
|
|
272
|
+
shape(a, [...common], ['body', 'mentions', 'reach', 'reply', 'metadata', 'delivery']);
|
|
273
|
+
if (Object.hasOwn(a, 'delivery')) {
|
|
274
|
+
requireFact(a.delivery !== undefined, 'say delivery is malformed.');
|
|
275
|
+
try {
|
|
276
|
+
validateActivityDelivery(a.delivery);
|
|
277
|
+
}
|
|
278
|
+
catch {
|
|
279
|
+
throw invalidArtifact('say delivery is malformed.');
|
|
280
|
+
}
|
|
281
|
+
}
|
|
273
282
|
if (Object.hasOwn(a, 'body'))
|
|
274
283
|
string(a.body);
|
|
275
284
|
if (Object.hasOwn(a, 'metadata')) {
|
|
@@ -311,7 +320,7 @@ export function validateStoredActivity(value) {
|
|
|
311
320
|
function activity(row) {
|
|
312
321
|
const h = head(row), payload = object(json(row.payload_json));
|
|
313
322
|
// Payload cannot shadow indexed structural columns.
|
|
314
|
-
const allowed = h.kind === 'say' ? ['body', 'mentions', 'metadata'] : h.kind === 'done' ? ['body'] : h.kind === 'read' ? ['through'] : h.kind === 'listen' || h.kind === 'ignore' || h.kind === 'unlisten' ? ['target'] : [];
|
|
323
|
+
const allowed = h.kind === 'say' ? ['body', 'mentions', 'metadata', 'delivery'] : h.kind === 'done' ? ['body'] : h.kind === 'read' ? ['through'] : h.kind === 'listen' || h.kind === 'ignore' || h.kind === 'unlisten' ? ['target'] : [];
|
|
315
324
|
requireFact(Object.keys(payload).every(k => allowed.includes(k)));
|
|
316
325
|
return immutable(validateStoredActivity({ ...h, ...payload }));
|
|
317
326
|
}
|
|
@@ -530,6 +539,27 @@ export function createSqliteDriver(db) {
|
|
|
530
539
|
}
|
|
531
540
|
if (filter.attentionOnly)
|
|
532
541
|
base.sql += " AND d.route IN ('mention','reply','bell')";
|
|
542
|
+
if (filter.metadataMatch !== undefined) {
|
|
543
|
+
// Walk object keys rather than JSON-path strings: dots, quotes and array-like
|
|
544
|
+
// keys are literal, and arrays must never act as metadata objects.
|
|
545
|
+
base.sql += ` AND NOT EXISTS (
|
|
546
|
+
SELECT 1 FROM json_each(?) field WHERE NOT EXISTS (
|
|
547
|
+
WITH RECURSIVE walk(value,type,depth) AS (
|
|
548
|
+
SELECT json_extract(a.payload_json,'$.metadata'),json_type(a.payload_json,'$.metadata'),0
|
|
549
|
+
UNION ALL
|
|
550
|
+
SELECT child.value,child.type,walk.depth+1
|
|
551
|
+
FROM walk JOIN json_each(CASE WHEN walk.type='object' THEN walk.value ELSE '{}' END) child
|
|
552
|
+
ON child.key=json_extract(field.value,'$.path['||walk.depth||']')
|
|
553
|
+
WHERE walk.depth<json_array_length(field.value,'$.path')
|
|
554
|
+
)
|
|
555
|
+
SELECT 1 FROM walk WHERE depth=json_array_length(field.value,'$.path')
|
|
556
|
+
AND (type=json_type(field.value,'$.equals')
|
|
557
|
+
OR type IN ('integer','real') AND json_type(field.value,'$.equals') IN ('integer','real'))
|
|
558
|
+
AND value IS json_extract(field.value,'$.equals')
|
|
559
|
+
)
|
|
560
|
+
)`;
|
|
561
|
+
base.args.push(encode(filter.metadataMatch.fields));
|
|
562
|
+
}
|
|
533
563
|
return base;
|
|
534
564
|
}
|
|
535
565
|
function directedHead(row, recipient) {
|
|
@@ -682,7 +712,6 @@ export function createSqliteDriver(db) {
|
|
|
682
712
|
const k = encode(owner(name)), r = one('SELECT MAX(at) AS latest FROM receipts WHERE owner_json=?', [k]), e = one('SELECT MAX(r.act_index) AS latest FROM receipts r JOIN activities a ON a.act_index=r.act_index WHERE r.owner_json=? AND r.act_index>? AND a.actor_json IS NOT NULL', [k, integer(afterIndex, -1)]);
|
|
683
713
|
return immutable({ ...(r.latest === null ? {} : { latestAt: finite(r.latest) }), ...(e.latest === null ? {} : { latestActorActivityIndex: integer(e.latest) }) });
|
|
684
714
|
},
|
|
685
|
-
receiptAssignments: () => immutable(all('SELECT owner_json,act_index FROM receipts ORDER BY owner_json,act_index').map(r => ({ owner: decoded(r.owner_json, true), index: integer(r.act_index) }))),
|
|
686
715
|
deliveryDeferrals(name, generation) {
|
|
687
716
|
const canonical = owner(name);
|
|
688
717
|
const current = read.seat(canonical);
|
package/dist/square-tools.d.ts
CHANGED
|
@@ -13,6 +13,7 @@ interface ToolDefinition {
|
|
|
13
13
|
/** Human text identical to what the CLI prints; domain receipts stay inside the adapter. */
|
|
14
14
|
run(square: Square, args: JsonObject, control: OperationControl, identity: ToolIdentity): Promise<string>;
|
|
15
15
|
}
|
|
16
|
+
export declare function squareToolsEnabled(env?: NodeJS.ProcessEnv): boolean;
|
|
16
17
|
export declare const SQUARE_TOOL_INSTRUCTIONS = "Join once. Then express to speak, and catch to take in what reached you. History looks back without taking anything in.";
|
|
17
18
|
export declare const SQUARE_TOOLS: readonly ToolDefinition[];
|
|
18
19
|
export declare function squareToolFailure(error: unknown, signal?: AbortSignal): JsonObject;
|
package/dist/square-tools.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod/v4';
|
|
2
|
-
import { isSquareError } from './model.js';
|
|
2
|
+
import { isSquareError, SquareError } from './model.js';
|
|
3
3
|
import { requireOwner, requireJoinName, selectOwnSeat, CATCH_DEFAULT_LIMIT } from './square-api.js';
|
|
4
4
|
import { renderCatchOutcome, renderExpression, renderFailureLines, renderHistoryResult, renderJoinResult, renderLifecycleResult, renderListenerChange, renderStatusResult, } from './operation-presentation.js';
|
|
5
5
|
const location = z.string().optional().describe('Which square: a .square file path. Relative paths start from the working directory. Leave it out for the configured square.');
|
|
@@ -19,6 +19,14 @@ function tool(name, description, shape, run, render) {
|
|
|
19
19
|
return render(receipt, operationArgs) ?? '';
|
|
20
20
|
} };
|
|
21
21
|
}
|
|
22
|
+
export function squareToolsEnabled(env = process.env) {
|
|
23
|
+
const raw = env.SQUARE_TOOLS?.trim().toLowerCase();
|
|
24
|
+
if (raw === undefined || raw === '' || raw === '1' || raw === 'true')
|
|
25
|
+
return true;
|
|
26
|
+
if (raw === '0' || raw === 'false' || raw === 'none')
|
|
27
|
+
return false;
|
|
28
|
+
throw new SquareError('invalid_args', 'Invalid SQUARE_TOOLS: expected 0, 1, true, false, or none.');
|
|
29
|
+
}
|
|
22
30
|
export const SQUARE_TOOL_INSTRUCTIONS = 'Join once. Then express to speak, and catch to take in what reached you. History looks back without taking anything in.';
|
|
23
31
|
const target = z.string().describe('The participant to turn toward or away from.');
|
|
24
32
|
export const SQUARE_TOOLS = [
|
package/dist/views.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type ActivityId } from './square-core.js';
|
|
2
2
|
import { type StoredAct } from './model.js';
|
|
3
3
|
import type { ActivityFilter, SquareRead } from './ports.js';
|
|
4
|
-
import type { Activity, ArchiveRecord, PerceivedActivity, HistoryQuery, HistoryContinuation, ParticipantsResult,
|
|
4
|
+
import type { Activity, ArchiveRecord, PerceivedActivity, HistoryQuery, HistoryContinuation, ParticipantsResult, EntryPresentation, StatusResult, SquareObservation, CatchPresence } from './square-facade.js';
|
|
5
5
|
export declare const HISTORY_DEFAULT_LIMIT = 10;
|
|
6
6
|
export declare const HISTORY_MAX_LIMIT = 100;
|
|
7
7
|
export declare const NON_READ: readonly ["join", "done", "say", "listen", "ignore", "unlisten"];
|
|
@@ -17,7 +17,6 @@ export declare function selectHistory(facts: SquareRead, query: HistoryQuery, li
|
|
|
17
17
|
totalMatches: number;
|
|
18
18
|
};
|
|
19
19
|
export declare function publicActivities(activities: readonly ArchiveRecord[]): Activity[];
|
|
20
|
-
export declare function snapshot(facts: SquareRead, now: number): SquareSnapshot;
|
|
21
20
|
export declare function recoveryObservation(facts: SquareRead, name: string, now: number): {
|
|
22
21
|
participant: string;
|
|
23
22
|
activitySummaries: import("./square-facade.js").UnreadActivitySummary[];
|
package/dist/views.js
CHANGED
|
@@ -19,6 +19,7 @@ export function toPublicActivity(stored) {
|
|
|
19
19
|
...(stored.kind === 'say' && stored.reach !== undefined ? { reach: stored.reach } : {}),
|
|
20
20
|
...('body' in stored && stored.body !== undefined ? { body: stored.body } : {}),
|
|
21
21
|
...(stored.kind === 'say' && stored.metadata !== undefined ? { metadata: stored.metadata } : {}),
|
|
22
|
+
...(stored.kind === 'say' && stored.delivery !== undefined ? { delivery: stored.delivery } : {}),
|
|
22
23
|
mentions: stored.kind === 'say' ? stored.mentions ?? [] : [], ...('target' in stored ? { target: stored.target } : {}),
|
|
23
24
|
...(stored.kind === 'say' && stored.reply !== undefined ? { reply: formatActivityId(stored.reply) } : {}) };
|
|
24
25
|
}
|
|
@@ -110,15 +111,6 @@ export function selectHistory(facts, query, limit, kinds, presentation = true) {
|
|
|
110
111
|
export function publicActivities(activities) {
|
|
111
112
|
return activities.flatMap((activity) => activity.kind === 'read' ? [] : [toPublicActivity(activity)]);
|
|
112
113
|
}
|
|
113
|
-
export function snapshot(facts, now) {
|
|
114
|
-
const header = facts.header();
|
|
115
|
-
const names = new Map(facts.roster().map((p) => [nameKey(p.name), p.name]));
|
|
116
|
-
const receipts = new Set(facts.receiptAssignments().map((r) => JSON.stringify([r.owner, r.index])));
|
|
117
|
-
return { context: [...header.preamble, ...header.warmup].join('\n'), actCount: facts.activityCount({ kinds: NON_READ }), hardCap: header.hardCap,
|
|
118
|
-
...(header.throttlePerMinute === undefined ? {} : { throttlePerMinute: header.throttlePerMinute }),
|
|
119
|
-
participants: coreParticipants(facts, now).filter((p) => p.presence !== 'never-joined').map(({ name, presence, listening }) => ({ name, presence, listening })),
|
|
120
|
-
delivered(name, id) { return receipts.has(JSON.stringify([names.get(nameKey(name)) ?? name, parseRequiredActivityId(id)])); } };
|
|
121
|
-
}
|
|
122
114
|
export function recoveryObservation(facts, name, now) {
|
|
123
115
|
const known = resolveKnownName(facts, name);
|
|
124
116
|
return { participant: known, activitySummaries: unreadActivitySummaries(facts, known, now), standingCount: inSquareCount(facts),
|
|
@@ -8,7 +8,11 @@ Library operations accept a final non-serializable control value:
|
|
|
8
8
|
|
|
9
9
|
The signal is checked before lifecycle work and before artifact mutation, and it is propagated through artifact reads, transactions, change waits, and ownership lock acquisition. An idle `catch` rejects promptly when cancelled; it does not wake later and consume activity. Cancellation before an artifact transition prevents mutation.
|
|
10
10
|
|
|
11
|
-
Commit boundaries are one-way. Once an activity or observation commits, later cancellation cannot
|
|
11
|
+
Commit boundaries are one-way. Once an activity or observation commits, later cancellation cannot
|
|
12
|
+
roll it back or turn the result into a retry. A caller may discard the response after the commit,
|
|
13
|
+
but the committed activity remains recoverable through `history` or a later `catch`; catch does not
|
|
14
|
+
require a second acknowledgement. The separate `pending` query never consumes; its optional
|
|
15
|
+
follow-up `ack(ids)` commits exact receipts with the same cancellation boundary.
|
|
12
16
|
|
|
13
17
|
The single catch lease and independent delivery-deferral leases have distinct lifetimes. Cancelling
|
|
14
18
|
an active catch releases only that catch's lease. Cancelling a deferral operation before commit
|
|
@@ -72,7 +72,7 @@ The amended guidance's reachable-latest clause is applied: the selector remains
|
|
|
72
72
|
- `test/core.test.js`: status and participants continue sharing actual authored and receipt times, including a fresh rejoin and watcher.
|
|
73
73
|
- `test/process/square-cli-render.test.js`: the compact ten-person preview now includes a valid historical never-joined actor in the artifact. Status still hides that actor but its executable continuation uses the full count 14 rather than filtered count 13; participants prints the complete roster. Existing exact rejoin, attention, clipping/public-id continuation and presence feedback remain covered.
|
|
74
74
|
|
|
75
|
-
No observation timing change is intended: optional viewer discovery still precedes status's resource read; the clock is sampled once inside the transaction, and all domain data, classification, perception and rendering annotations are assembled in that read. Queries perform no I/O or mutations themselves. SDK participant/snapshot shapes and MCP serialization of data
|
|
75
|
+
No observation timing change is intended: optional viewer discovery still precedes status's resource read; the clock is sampled once inside the transaction, and all domain data, classification, perception and rendering annotations are assembled in that read. Queries perform no I/O or mutations themselves. At the time, SDK participant/snapshot shapes and MCP serialization of data remained unchanged; the SDK snapshot was subsequently retired. No join/claim is introduced.
|
|
76
76
|
|
|
77
77
|
Production reference search for `coreStatus|StatusObservation|StatusPresentation|ParticipantsPresentation|statusPresentation|participantsPresentation|StatusResult` returns no matches. Neither status nor participants has a duplicate roster in its projection. `git diff --check` passes.
|
|
78
78
|
|
|
@@ -79,8 +79,10 @@ primitive entrypoints without constructing Square.
|
|
|
79
79
|
|
|
80
80
|
## Square composition
|
|
81
81
|
|
|
82
|
-
Square uses these functions for production landing, catch and `markSeen`
|
|
83
|
-
its existing activity, audience and receipt tables.
|
|
82
|
+
Square uses these functions for production landing, catch and `markSeen` (including explicit
|
|
83
|
+
`Participant.ack`) against its existing activity, audience and receipt tables. `Participant.pending`
|
|
84
|
+
uses the same addressed/unconsumed relation without writing receipts; optional metadata matching
|
|
85
|
+
is applied by storage before the page limit. Numeric activity indexes stay
|
|
84
86
|
internal keys; the primitive does not know Square IDs. Square retains validation,
|
|
85
87
|
limits, filtering, perception, ownership, leases, hints and error mapping. The
|
|
86
88
|
empty-catch read probe does not hydrate or acquire a writer; a nonempty probe is
|
|
@@ -30,9 +30,9 @@ rg -n 'validateSquareState|exportSqliteState|initializeSqlite|writeSquareSnapsho
|
|
|
30
30
|
- `square-state.ts` retains legacy validation for the separately implemented migration and test oracle. Normal v1 recognition validates framing and refuses with `migration_required`; it never decodes v1 history. Common per-activity validation is also used by the row codec.
|
|
31
31
|
- `artifact.ts::readSquareSnapshot` and `square-sqlite.ts::exportSqliteState` are explicit export/integrity capabilities. Doctor intentionally reads all authority and compares maintained indices against a rebuild. Neither is a hot-runtime fallback.
|
|
32
32
|
- `createSquareSnapshot` initializes a new artifact. `writeSquareSnapshot/writeSquareFile` are explicit build `--force`/fixture import, not whole-state transaction callbacks. Existing v1 still refuses before destructive work. `initializeSqlite` also supplies the migration's shared rebuild; it calls the same `deriveLanding`, not another production fold.
|
|
33
|
-
-
|
|
33
|
+
- Historical (retired SDK API): `snapshot().delivered()` copied raw receipt assignments into a detached exact-owner Set; it does not retain a query or transaction capability and copies no activity history.
|
|
34
34
|
- `.state` matches elsewhere are participant/admission states, transport outcomes or Claude's native `$.state` API, not artifact snapshots. `packages/agent-delivery` remains untouched.
|
|
35
|
-
- `
|
|
35
|
+
- `square_snapshot` in the benchmark is instrumentation for detecting forbidden legacy reads, not a runtime path.
|
|
36
36
|
|
|
37
37
|
### Production source size
|
|
38
38
|
|
|
@@ -59,7 +59,7 @@ Evidence locations:
|
|
|
59
59
|
|
|
60
60
|
| Invariant | Tests |
|
|
61
61
|
|---|---|
|
|
62
|
-
|
|
|
62
|
+
| Landing audience priority and directed attention, including mixed spelling, reply/mention/listen/ignore/bell and departure | `test/row-domain.test.js` |
|
|
63
63
|
| Sparse receipts, exact raw owners/orphans, unseen hole vs later catch, repeat no-op, filtered remaining, historical catch vs latest-join pending, distinct cursor/presence | `test/row-domain.test.js`, `test/perception-projection.test.js` |
|
|
64
64
|
| Exact v2 schema, optional field preservation, immutable detached facts, expired capabilities, synchronous callbacks, caught storage failure rollback, no-op revision, selected corruption vs doctor | `test/artifact.test.js`, `test/core.test.js` |
|
|
65
65
|
| Two real processes serialize catches; process death rolls activity and indices back; busy COMMIT retains callback/result; abort preserves reason; revision read has a positive SQL control | `test/sqlite-storage.test.js` |
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# Row-oriented artifact design
|
|
2
2
|
|
|
3
|
+
> Historical design: the public SDK `Square.snapshot()` and its closure were retired. Snapshot-specific proposals below record the design at the time, not the current API.
|
|
4
|
+
|
|
3
5
|
**Historical accepted design for artifact format 2.** The current runtime uses format 3 for the
|
|
4
6
|
`unlisten` event; see [Square API](square-api.md#artifact-format-and-explicit-migration) for current
|
|
5
7
|
format/migration behavior. The schema and delivery-stage terms below record the original row-storage
|
|
@@ -428,7 +430,9 @@ No production structure below carries `.state`, all `.activities`, or a deferred
|
|
|
428
430
|
| public Square.snapshot().delivered(name,id) | explicit receiptAssignments + detached roster resolution + small header/status in ONE read txn, as below. Other production callers must not use this for count/standing. |
|
|
429
431
|
| doctor / explicit import/export tests | full selected-row validation and replay comparison of indices; detached result includes standing count, not state for CLI header. Legacy validator lives only in explicit migration/test oracle. No automatic repair. |
|
|
430
432
|
|
|
431
|
-
### Public SDK snapshot closure
|
|
433
|
+
### Public SDK snapshot closure (retired)
|
|
434
|
+
|
|
435
|
+
This historical design described the removed SDK `Square.snapshot()` API; it is no longer supported.
|
|
432
436
|
|
|
433
437
|
Keep synchronous arbitrary `delivered(name,id)`. `snapshot()` intentionally copies ALL raw receipt assignments into a private detached Set keyed by JSON.stringify([rawOwner,index]), along with an immutable nameKey->first-roster-spelling map. Closure validates/parses id with current parseRequiredActivityId, resolves `map[nameKey(name)] ?? name`, and tests that exact owner/index set. This covers dormant raw owner keys, orphan assigned coordinates, unknown-name fallback, and arbitrary later calls after port close. It does not query a DB or retain SquareRead. Later writes do not alter this snapshot. No receipt times/activity bodies are copied. This O(receipts) exception is necessary for the existing synchronous API, and is limited to explicit SDK snapshot calls; lifecycle/status/poll/render use narrower helpers.
|
|
434
438
|
|
package/guides/square-api.md
CHANGED
|
@@ -197,7 +197,7 @@ shared dispatcher's timeout or retry policy.
|
|
|
197
197
|
|
|
198
198
|
## One set of operations and defaults
|
|
199
199
|
|
|
200
|
-
Square owns `history`, `status`, `participants`, `
|
|
200
|
+
Square owns `history`, `status`, `participants`, `stream`, and recovery observations.
|
|
201
201
|
A file-backed `stream` follows the path with a fresh artifact read for each page, so atomic file
|
|
202
202
|
replacement is visible even while the resource holds its original connection. Its iterator owns
|
|
203
203
|
its observation lifetime: `return()` interrupts a pending pull; closing a local Square does not close
|
|
@@ -211,7 +211,7 @@ their landed directed activities and adds `perception` and the landing route `vi
|
|
|
211
211
|
(`mention`, `reply`, `attention`, or `bell`). Perception follows the viewer's actual landed audience;
|
|
212
212
|
`via` is absent when no directed route exists. Stream starts at a bounded tail or after an `ActivityId`
|
|
213
213
|
like `act/12`; it never consumes activity.
|
|
214
|
-
Participant owns `express`, `catch`, `listen`, `unlisten`, `ignore`, `listening`, `done`,
|
|
214
|
+
Participant owns `express`, `catch`, `pending`, `ack`, `listen`, `unlisten`, `ignore`, `listening`, `done`,
|
|
215
215
|
`deferDelivery`, `renewDeliveryDeferral`, and `releaseDeliveryDeferral`. History belongs only to
|
|
216
216
|
Square; there is no `Participant.history`.
|
|
217
217
|
|
|
@@ -271,6 +271,62 @@ Operations that accept an `OperationControl` use a final argument with `signal`
|
|
|
271
271
|
`onProgress`. Listener/lifecycle operations take optional observation options before that argument;
|
|
272
272
|
participant selection, seat discovery and host cleanup methods do not take an `OperationControl`.
|
|
273
273
|
|
|
274
|
+
## Pending query and exact acknowledgement
|
|
275
|
+
|
|
276
|
+
`Participant.pending(options?, control?)` and `Participant.ack(ids, control?)` separate a read-only
|
|
277
|
+
query from explicit consumption. `ChannelEndpoint` from `@astrosheep/square/channel` exposes the
|
|
278
|
+
identical methods by forwarding to its captured Participant; it has no independent inbox or storage.
|
|
279
|
+
|
|
280
|
+
`Channel.send` / `Square.send` address joined members, including detached members. Attachment gates
|
|
281
|
+
proactive wake, not landing: a detached recipient retains its unread addressed activity without a
|
|
282
|
+
wake and can query/ack it after reattachment. Recipient validation remains all-or-nothing; a missing
|
|
283
|
+
or departed recipient rejects the entire send without landing activity or waking other recipients.
|
|
284
|
+
|
|
285
|
+
```ts
|
|
286
|
+
import type { ChannelEndpoint, MetadataMatch } from '@astrosheep/square/channel';
|
|
287
|
+
|
|
288
|
+
async function drain(endpoint: ChannelEndpoint, match: MetadataMatch) {
|
|
289
|
+
for (;;) {
|
|
290
|
+
const page = await endpoint.pending({ match });
|
|
291
|
+
if (page.activities.length === 0) break;
|
|
292
|
+
// Process the entire page successfully before acknowledging its exact IDs.
|
|
293
|
+
for (const activity of page.activities) await processNotice(activity);
|
|
294
|
+
const { consumed } = await endpoint.ack(page.activities.map(activity => activity.id));
|
|
295
|
+
// consumed may be smaller if another consumer acknowledged some IDs first.
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
- `pending({match?, limit?} = {}, control?)` returns
|
|
301
|
+
`{activities: readonly PerceivedActivity[], remaining: number}`. It selects only landed,
|
|
302
|
+
addressed, unconsumed says, oldest first. Body, metadata, delivery information, perception and
|
|
303
|
+
route use the same public records as catch; bodies are full stored bodies, not clipped previews.
|
|
304
|
+
- Limit defaults to 100 and must be an integer from 1 through 100. The optional `MetadataMatch`
|
|
305
|
+
uses exactly the nested own-property scalar equality semantics described below (AND across fields).
|
|
306
|
+
Storage applies addressedness, consumption and metadata matching **before** limiting.
|
|
307
|
+
`remaining` counts matching unconsumed activities outside the returned page, in the same read
|
|
308
|
+
transaction. It is not the global unread count or a durable cursor.
|
|
309
|
+
- A pending query consumes nothing, changes no read horizon and writes no delivery/presentation
|
|
310
|
+
evidence. Deferrals, catch leases, cancellation and prior clipped presentation do not hide these
|
|
311
|
+
explicit reads. Like catch, pending includes historical addressed receipt holes before a rejoin;
|
|
312
|
+
it is not the proactive delivery eligibility query.
|
|
313
|
+
- `ack(ids: readonly ActivityId[], control?)` returns `{consumed: number}`, the count of newly
|
|
314
|
+
consumed exact IDs. It validates that **every** supplied ID is addressed to this participant before
|
|
315
|
+
recording any receipts. Malformed, nonexistent or unaddressed IDs reject the whole batch with
|
|
316
|
+
`invalid_args` (`reason: 'not_addressed'` for valid but unaddressed IDs). There is no implicit prefix
|
|
317
|
+
acknowledgement, no match reselection and no requirement for an earlier pending call.
|
|
318
|
+
- Duplicate IDs, repeated acknowledgement and an empty array are idempotent. Existing receipt
|
|
319
|
+
timestamps remain unchanged. Acknowledgement uses the same sparse receipts as catch/full
|
|
320
|
+
presentation, so it removes those IDs from pending and ordinary catch, but exact catch remains
|
|
321
|
+
repeatable. It does **not** assert wake acceptance or presentation and writes no such evidence.
|
|
322
|
+
- Both operations require their captured current owner, generation and attached seat; even an empty
|
|
323
|
+
query/ack cannot reuse a detached, retired or replaced handle. No storage format change is needed.
|
|
324
|
+
Cancellation before the receipt transaction prevents consumption; a committed ack is not undone.
|
|
325
|
+
- To drain all matching notices, keep querying and acknowledging pages until an **empty** page.
|
|
326
|
+
Acknowledging one page exposes the next without a cursor. Do not silently stop after the default
|
|
327
|
+
page or treat a snapshot `remaining: 0` as proof that concurrent producers have stopped. Query and
|
|
328
|
+
ack are separate operations, not an exclusive claim or an exactly-once external-effect guarantee.
|
|
329
|
+
|
|
274
330
|
## Temporary proactive delivery deferral
|
|
275
331
|
|
|
276
332
|
SDK Participants expose three operations. There are no CLI/MCP/Pi authoring
|
|
@@ -307,9 +363,9 @@ try {
|
|
|
307
363
|
releasing one cannot end another. A captured current owner/join generation is required for every
|
|
308
364
|
mutation. Stale handles retain the ownership refusal; done/takeover/rejoin retire old leases.
|
|
309
365
|
- Lease writes change delivery revision, not conversation history. They do not create a receipt,
|
|
310
|
-
change audience or unread counts, hide an archive record, or prohibit explicit catch.
|
|
311
|
-
|
|
312
|
-
separate, single quiet-wait lease with its existing filters and lifecycle.
|
|
366
|
+
change audience or unread counts, hide an archive record, or prohibit explicit catch/pending/ack.
|
|
367
|
+
Catch and ack consume normally; a consumed record is not replayed when a deferral ends. The catch
|
|
368
|
+
lease is a separate, single quiet-wait lease with its existing filters and lifecycle.
|
|
313
369
|
- Producer/sweep, atomic claims, session/native projections, final pre-send checks and proactive
|
|
314
370
|
presentation all share current-generation unexpired matching. Suppressed items get no seen or
|
|
315
371
|
presented receipt. An active pending observer rechecks on release and the earliest relevant
|
|
@@ -339,8 +395,8 @@ or history/status presentation annotations.
|
|
|
339
395
|
Express captures optional unread context before the attempt: the latest five directed,
|
|
340
396
|
unseen activities after the current join, each preview capped at 400 Unicode characters,
|
|
341
397
|
plus the count outside that preview. It hydrates only that page, not the entire cursor suffix.
|
|
342
|
-
This is a nonconsuming preview even when a short body fits in full;
|
|
343
|
-
normal full-notification presentation path
|
|
398
|
+
This is a nonconsuming preview even when a short body fits in full; consumption requires `catch`,
|
|
399
|
+
explicit `ack`, or the normal full-notification presentation path. Count and time facts come
|
|
344
400
|
from the committed transaction. Listener and lifecycle observations likewise use their mutation's
|
|
345
401
|
facts, with no postcommit context read. Join uses its mutation's essential facts and treats optional
|
|
346
402
|
entry/history enrichment as best-effort: `observation.enrichmentUnavailable` is explicit and the
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astrosheep/square",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.97",
|
|
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": {
|
|
@@ -46,11 +46,14 @@
|
|
|
46
46
|
"@types/cross-spawn": "^6.0.6",
|
|
47
47
|
"@types/node": "^22",
|
|
48
48
|
"@types/ws": "^8.18.1",
|
|
49
|
-
"square-v1": "npm:@astrosheep/square@0.3.70",
|
|
50
49
|
"typescript": "^5.8",
|
|
51
50
|
"ws": "^8.21.3"
|
|
52
51
|
},
|
|
53
52
|
"exports": {
|
|
53
|
+
"./channel": {
|
|
54
|
+
"types": "./dist/channel.d.ts",
|
|
55
|
+
"default": "./dist/channel.js"
|
|
56
|
+
},
|
|
54
57
|
"./delivery": {
|
|
55
58
|
"types": "./dist/delivery-primitives.d.ts",
|
|
56
59
|
"default": "./dist/delivery-primitives.js"
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"hooks": {
|
|
3
3
|
"SessionStart": [
|
|
4
|
-
{ "hooks": [{ "type": "command", "command": "square codex-hook", "timeout": 5 }] }
|
|
4
|
+
{ "hooks": [{ "type": "command", "command": "square codex-hook", "timeout": 5, "statusMessage": "Square" }] }
|
|
5
5
|
],
|
|
6
6
|
"SessionResume": [
|
|
7
|
-
{ "hooks": [{ "type": "command", "command": "square codex-hook", "timeout": 5 }] }
|
|
7
|
+
{ "hooks": [{ "type": "command", "command": "square codex-hook", "timeout": 5, "statusMessage": "Square" }] }
|
|
8
8
|
],
|
|
9
9
|
"SessionEnd": [
|
|
10
|
-
{ "hooks": [{ "type": "command", "command": "square codex-hook", "timeout": 3 }] }
|
|
10
|
+
{ "hooks": [{ "type": "command", "command": "square codex-hook", "timeout": 3, "statusMessage": "Square" }] }
|
|
11
11
|
],
|
|
12
12
|
"UserPromptSubmit": [
|
|
13
|
-
{ "hooks": [{ "type": "command", "command": "square codex-hook", "timeout": 5 }] }
|
|
13
|
+
{ "hooks": [{ "type": "command", "command": "square codex-hook", "timeout": 5, "statusMessage": "Square" }] }
|
|
14
14
|
],
|
|
15
15
|
"PostToolUse": [
|
|
16
16
|
{
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"type": "command",
|
|
20
20
|
"command": "square codex-hook",
|
|
21
21
|
"timeout": 5,
|
|
22
|
-
"statusMessage": "
|
|
22
|
+
"statusMessage": "Square"
|
|
23
23
|
}
|
|
24
24
|
]
|
|
25
25
|
}
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"type": "command",
|
|
32
32
|
"command": "square codex-hook",
|
|
33
33
|
"timeout": 5,
|
|
34
|
-
"statusMessage": "
|
|
34
|
+
"statusMessage": "Square"
|
|
35
35
|
}
|
|
36
36
|
]
|
|
37
37
|
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Seamless 512px stone tiles, rendered once offline (float canvas noise, dithered, JPEG):
|
|
3
|
+
* veinless honed stone — only the milky drift, on muted grey-white (light) or charcoal (dark).
|
|
4
|
+
* Kept tiny so they inline as data URIs.
|
|
5
|
+
*/
|
|
6
|
+
export const MARBLE_LIGHT = "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/4gHYSUNDX1BST0ZJTEUAAQEAAAHIAAAAAAQwAABtbnRyUkdCIFhZWiAH4AABAAEAAAAAAABhY3NwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAA9tYAAQAAAADTLQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlkZXNjAAAA8AAAACRyWFlaAAABFAAAABRnWFlaAAABKAAAABRiWFlaAAABPAAAABR3dHB0AAABUAAAABRyVFJDAAABZAAAAChnVFJDAAABZAAAAChiVFJDAAABZAAAAChjcHJ0AAABjAAAADxtbHVjAAAAAAAAAAEAAAAMZW5VUwAAAAgAAAAcAHMAUgBHAEJYWVogAAAAAAAAb6IAADj1AAADkFhZWiAAAAAAAABimQAAt4UAABjaWFlaIAAAAAAAACSgAAAPhAAAts9YWVogAAAAAAAA9tYAAQAAAADTLXBhcmEAAAAAAAQAAAACZmYAAPKnAAANWQAAE9AAAApbAAAAAAAAAABtbHVjAAAAAAAAAAEAAAAMZW5VUwAAACAAAAAcAEcAbwBvAGcAbABlACAASQBuAGMALgAgADIAMAAxADb/2wBDAAYEBAUEBAYFBQUGBgYHCQ4JCQgICRINDQoOFRIWFhUSFBQXGiEcFxgfGRQUHScdHyIjJSUlFhwpLCgkKyEkJST/2wBDAQYGBgkICREJCREkGBQYJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCT/wAARCAIAAgADASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAECCP/EABYQAQEBAAAAAAAAAAAAAAAAAAABEf/EABYBAQEBAAAAAAAAAAAAAAAAAAABAv/EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhEDEQA/AOnAGkQUBBcMAAAAAAAAAAAAAAAKAM1K1WaDFRqoAAAIqAioAgKCosBViLAVYiwGoIqCgKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADNjSUGLEarNBEVABFQUAEwxQEUAFRQWNMxYDQigoAACgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlUBmxmxvExBixMbxLFGMGrExBFMFAFBBUQFRQVUUBUFGtNZ1QXVZ1ZQUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAExMaEGLEsbsZqjIqAAqCCoCKCiqyqCiaAGiAurKysUblVmVoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAUAAAAAAKxWqlBkUQQFUQaRBnFwFAFQQXBREaRBMWACxqMrFGggAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACVFqAgACoqAAogpiCKAAAIAogICtRhQblVmVdBQ1NBRnTQaGdNBrRnWpQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASs1qs0EBAXTU01BoRVFixIsBUxQERUARUoIAAAgLKyqjWpqaAogC6gAsWMrqDWrrGroNCSqoAAmqigAAAAAAAAAAAAAAAAAAAAAAAAAAlZrVZoMi1MQRTDFBUIg1GozFBoRVERcAZFQEBQEqpQSggLogg0JpoKiaaCrrOmg0rMUFajKxRQQFUEABQAAAAAAAAAAAAAAAAAAAAAAABKlWogmGLhiiYKgJhikgCioEUFAwARFSggACVUoIjWICCsoLqCAaGAKAosVCINLEigqoqgCgAAAAAAAAAAAAAAAAAAAAAAAIACiCgJi4AIi1AFRYAoAAAAAhRKCAiCgKCKIM1K1UsUZFwxBBcRQAQUAGousxYo0RFgNAAAAAAAAAAAAAAAAAmgommgoaAAAAAAAAAAAgogioqgAAAAABWa0lgM1FwBFBAUwURFqAgUQQxRRkaQAMXEBqRMakAxZDFAAUAAAAAAAAAAAAAKCWs6tZBdXWV0F0TTQWVpjVlBoSVQAAAAAAAARQAAAAAAAABLExpMBBRASqKM1GkoMigIoAJigEBUFkWJGooAAAAAAAAAAAAAAAAFAGbGW8SwGRcAQDACAg1KusxQaEiqAAAAAAAAAAAAAAAAAAACAmKKIlaxmgiNIgiLWaDWjKg0JFiixZQQUIKAAAAAAAAAAAAAAAACVQGUaxMBAxUERUUFRYg1FSKoAAAAAAAAAAAAAAAAAAAAAAJVKDNRazQKgIAYoEaiRYooKAAAAAAAAAAAAAAAAAAAAAYAJhigM4WNIDOCiCxSCgAAAAAAAAAAAAAAAAAAAAAAADNZrdiWAwLggBgosWJFgKCgAAAAAAAAAAAAAAAAAAAAAAAAAAgAKAAAAAAAAAAAAAAAgAKAAAAAAAACYoDOGNGAzhjWAM4uKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAogCgAAAAAAAAAAAAAAAAAAAAAAAAAAAigAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACCoCgAAAAAAAAAAAAAAACAKAAAgAKAAAAAAACAAoAAAAAAAAAAAAAAAAAAAAAAAABQAAAAAAAAAAAAAAAAAAAAEABQAAAAAAAAAAABNNBQTQURQAAAAAAAAAAAAAAAAAAAAAASgIAAC6gooAAAAAAAAAAAAACKlARagGrqAKqGgoaABqaC6mpoCggACCoCg0gCgAAAAAAAAAAAAAAAAAAAIqUBCpoLpqAKIoKqGoKAoAAAAAAAAAgKIICKKIKgAIC6ampqDWms6aCqixRUUBFBAFFAAAAAAAAAAAAAAAAAAAAAABKqUEqLWUA1NFFXWdXQXTUQG5WtYiwGhFAAAAAAAABAUERUAENAtTS1nQUTRBSVCUGpV1nV1RpWY1AUAAAAAAAAAAAAAAAAAAAAAAAAAEtRNS0FtTU00BAAVFAABVlRYCxpmKCiKAAAAAAACaAzVSgmppWQXUTTQXTUTQa0QQaIzqqNyrKxK1KDcVmNaAAAAAAAAAAAAABQTV1k0GhNNBRNNBRNTQaNZ00GNTU1NBdNQBdE1UFBQCCqCwAVWVgLFIIACgAAamgAiaCpVSgzWa1WagyLiKAigIIDWrGVBqNSsStSg3KusauoN6usSqo1ogChAAAAAAABKqUEqKgBqamg1prOmg1prOmguppUBlNKiC6miKNSrrMWINqzFUVUVBRBRViCDSsxVFEUBLSpQNTUoC6iaaDWomloJUBBEUUQUQZFARTFxRFiYsQaWVlYo3FZlWAqpGgAAAAAAAAGa1WaCVKVEDUEAAA1dZUFShQZqVqxARFAFgsgLFiRqKKAAKIIoqgoqCCoAlVFERpmggAIFRAQAFQAAAAUFRYgYKgCgCrEFGpWozGoCgAAAAAAAVmrUBKzjSAiNJiDI1iAyoqglaSglStVlBBRQVFQWLEjQCgoAALCLAUABFQBAQEVKCIqVRKzatZABcQQXAAAFMIqjOKogAKCoqAIqixqMtAqpFAAAAAABKlVKCAiCoACYoomCmAhVSoFjNaqWAypgoC4uARSRZAFwxYBiY1ggki4CgAAUARFqAVmqiAgAlZaqKIuCgYYKDNhjWGIJigoC4YggCiAANRIsBcWEWARQAAAAAAARQGKjeM4gguGKIsMMAwxcATEaTALExuxmwGcMaxMBFAFixIsQVUVQAAAAAAAAZaTAZFKgzUWoogAAigKigKggoEUUAEqNICCoA1GY1AVUiwFAAAAAAAAAASxQExMaEEwxRRMMUBMTGgBMVKCVFRBBQBYRYooAAAAAAAAAAAJUrTNBEWs0EqLUAVIsQAFDRFBVQ0F1dZ1dQUTQAwVRJGsABYAKAAAAAAAAAAAAAAAAAAAAlVKCVFAAAGokUAAAAAAAAAAAABKpQYrNbrNQYotQBYiqCoAAIBqCi6rIDWmoqCxYkaiigICgoAAAAAAAAAAAAAAAAAAAA/9k=";
|
|
7
|
+
export const MARBLE_DARK = "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/4gHYSUNDX1BST0ZJTEUAAQEAAAHIAAAAAAQwAABtbnRyUkdCIFhZWiAH4AABAAEAAAAAAABhY3NwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAA9tYAAQAAAADTLQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlkZXNjAAAA8AAAACRyWFlaAAABFAAAABRnWFlaAAABKAAAABRiWFlaAAABPAAAABR3dHB0AAABUAAAABRyVFJDAAABZAAAAChnVFJDAAABZAAAAChiVFJDAAABZAAAAChjcHJ0AAABjAAAADxtbHVjAAAAAAAAAAEAAAAMZW5VUwAAAAgAAAAcAHMAUgBHAEJYWVogAAAAAAAAb6IAADj1AAADkFhZWiAAAAAAAABimQAAt4UAABjaWFlaIAAAAAAAACSgAAAPhAAAts9YWVogAAAAAAAA9tYAAQAAAADTLXBhcmEAAAAAAAQAAAACZmYAAPKnAAANWQAAE9AAAApbAAAAAAAAAABtbHVjAAAAAAAAAAEAAAAMZW5VUwAAACAAAAAcAEcAbwBvAGcAbABlACAASQBuAGMALgAgADIAMAAxADb/2wBDAAYEBAUEBAYFBQUGBgYHCQ4JCQgICRINDQoOFRIWFhUSFBQXGiEcFxgfGRQUHScdHyIjJSUlFhwpLCgkKyEkJST/2wBDAQYGBgkICREJCREkGBQYJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCT/wAARCAIAAgADASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAECCP/EABYQAQEBAAAAAAAAAAAAAAAAAAABEf/EABUBAQEAAAAAAAAAAAAAAAAAAAAB/8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEQMRAD8A54AVFEAUQAAAAAAAAAAAAAAAABVRQWKkAURVBFARQQAAAAQAEABEUBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFiLAVUigKCgAgAgKIKKCIAAJUVAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABUAVWV0GtNTTQaE00FEFFQEABQAQQABFARGkBMFKCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAumoA1oigoigAgKIoAACKgAAAKCFioDNFqAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKigoCgaIgoigogAAAAAqAKgAgqUEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABYJFBQAEVAAAU1AFQAAAFRQAUESqKMi1EAAAXDAQXAEFQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACKkagAoCCgIACAAgAKIoCooACgAgYYqKJgogAAAqiIogyKAguIAAAKgAAAAAAAAAAAAAAAAAAAAAAAAAAEaZUGgAAAEUBEVAQVAURQURQAAAAUAABRBRADAAVAQVAQVARQAQAAAAAAAAAAAAAAAAAAAAAAAAAAAUAFEFF0QQUEAABAAAAURQUAAAFEUAFUAEAAAAEFQERUAAARUAAAAAAAAAAAAAAAAAAAAAAAAAAAVAAAFEUAEAAAAAAAVFBQAAAAAVWVBTTUBRFAAARUBBUBBUBAAAAAAAAAAAAAAAAAAAwAAAAAAAAAAAAAAAAAAAAAAAVFBRFAABAAUAFAAABRAFQQFSiACAAAAAAAAAAAAAAAAEBQigIoCCmAiNICAAAAAAAAAAAAAAAAAAAAsEUAAAAFEUFEAVABRAAAEqKgAAAAAAAAAAAAAAAAAALFSAKAAqAKgAgqAgAAAAAAAAAAAAAAAAAAAAAAAKIoKIoCooCKAiKAiKAgAAAAAAAAAAAAAAAAACoAqoAogCgAAAlRagAAAAAAAAAAAAAAAAAAAAAAAAKqRQFAAEARUAQAAAAAAAAAAAAAAAAAAAAAAAXRAFNQBoQAqAAAAAAAAAAAAAAAAAAAAAAAAACxUgDQmgACglVEBAAAAAAAAAAAAAAAAAAAAAAAAAAABRFBAAAAAAAAAAAAAAAAAAAAAAAAAAAAU1DQXTUAXRAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVFBBQEFAQAAAAAAAAAAAAAAAFAAABBUAAABQRQAAAAAAARUAAAAAAAAAAAAAAAAAAAAABQAUEFAQVAQVAAAAAAAAAAAAAAAUAAAAAAxTATBQEFQAAAEBRAAAAAAAAAAAAAAAAAAAAAAABUUBUUAUBBQEwxQGcRpAQAAAAAAAAABUAURQBQAFAAABVGRUQRGqgIAAAAAAAAAAAAAAAAAAAAAAAAAChi4AKAAqiAIAAIACIoCCoAAAAAAACgAsAXBYCKKCC4AgoCIoCM1pFGaLYiAAAAAAAAAAAAAACooCCgIKmACgILhgNYYoACggACLUABAAAQAEAAAAAAFAAAFiKCxYiwFCAAAAoohioCJWkBmo0iCIoCCgIAAAAAAAACgAoIooJiY0YDKrgCLgqigoIKAiNIDIqICKAgUARQERQEAAUAFAAUBBQBQAVBRQAFQBUABFQBFQERRBEVAAAAAAAAAFiKCgoAKAAAACKALFZVRQAEBBEVKCAKACACAIqAAoAAKqAKAACgAoIKigoIAgoAIAAAIoJiiCVlpKCAAAAAAAAKigsVAFABRFABFFEEFisqCiCioCCBUAAAAAQKCAAKigAAKigoAKEVQBAURQEAAAAQQFQBUAAAERQERUAAAAAABRFBQAAAFQBRNUARQFRQAABACoACCAuiAKgAAAAAoACgAoAoigCCiiAKIIAAAgCgAAAJVQBABKAAAAAAAAqAKqQBQAAQFEAURQFZAaEAUQARagCAAAAAAAAAAqKAqAKqKACqIoAgCAigIAACAqoAoigIqAgIAAAAAAAAAAAACiAKgAaaALpqACoAqooAACCUAAAAAAAAAAAABUUFVFAUAEVAAFAUQRFAQVAAAAAEABFQAAAAAAAAAAAAAAAAAAAAAAFAAAARUAAAAAAAAAAAAAABqKysBoRQAFEAQAVRBQEMUQQAERUAQAAAAAAAAAAAAAAAAAAAAAAAf/9k=";
|