@astrosheep/square 0.3.86 → 0.3.88
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 +6 -1
- package/dist/artifact.js +79 -10
- package/dist/boundary-presentation.d.ts +5 -4
- package/dist/boundary-presentation.js +21 -25
- package/dist/catch-decisions.js +2 -1
- package/dist/claude-delivery-status.d.ts +8 -2
- package/dist/claude-delivery-status.js +26 -10
- package/dist/claude-delivery.d.ts +8 -4
- package/dist/claude-delivery.js +114 -104
- package/dist/claude-mcp-context.js +2 -2
- package/dist/claude-mod.js +119 -105
- package/dist/cli/context.d.ts +3 -1
- package/dist/cli/context.js +25 -1
- package/dist/cli/express-presentation.d.ts +3 -1
- package/dist/cli/express-presentation.js +14 -10
- package/dist/cli/mcp-server-command.js +2 -2
- package/dist/cli/observation-commands.js +1 -0
- package/dist/cli/registry.js +0 -2
- package/dist/cli/square-commands.d.ts +4 -2
- package/dist/cli/square-commands.js +21 -6
- package/dist/codex-hook.d.ts +3 -3
- package/dist/codex-hook.js +4 -4
- package/dist/codex-queue.d.ts +5 -6
- package/dist/codex-queue.js +9 -5
- package/dist/decisions.d.ts +3 -2
- package/dist/decisions.js +18 -6
- package/dist/delivery-health.d.ts +32 -2
- package/dist/delivery-health.js +108 -45
- package/dist/delivery-operations.d.ts +1 -2
- package/dist/delivery-operations.js +155 -196
- package/dist/delivery.d.ts +14 -23
- package/dist/delivery.js +48 -18
- package/dist/file-lock.d.ts +8 -1
- package/dist/file-lock.js +2 -0
- package/dist/help.js +8 -11
- package/dist/inbox.d.ts +35 -9
- package/dist/inbox.js +228 -144
- package/dist/index.d.ts +3 -4
- package/dist/index.js +1 -3
- package/dist/list.js +9 -4
- package/dist/mcp.js +12 -1
- package/dist/model.d.ts +39 -5
- package/dist/model.js +84 -0
- package/dist/notifications.d.ts +8 -6
- package/dist/notifications.js +56 -143
- package/dist/operation-presentation.js +7 -4
- package/dist/participant-identity.d.ts +0 -3
- package/dist/participant-identity.js +0 -31
- package/dist/paseo-delivery.d.ts +5 -6
- package/dist/paseo-delivery.js +13 -8
- package/dist/paseo.d.ts +1 -1
- package/dist/paseo.js +1 -1
- package/dist/plugins/opencode/delivery.d.ts +8 -3
- package/dist/plugins/opencode/delivery.js +187 -132
- package/dist/plugins/opencode/index.js +12 -38
- package/dist/ports.d.ts +112 -40
- package/dist/presentation-operations.d.ts +1 -1
- package/dist/presentation-operations.js +51 -35
- package/dist/presentation.js +8 -3
- package/dist/seats.d.ts +7 -0
- package/dist/seats.js +27 -0
- package/dist/session-lifecycle.d.ts +2 -2
- package/dist/session-lifecycle.js +10 -12
- package/dist/sqlite-square.d.ts +20 -9
- package/dist/sqlite-square.js +476 -341
- package/dist/square-api.d.ts +1 -0
- package/dist/square-api.js +3 -4
- package/dist/square-core.d.ts +3 -2
- package/dist/square-domain.d.ts +12 -5
- package/dist/square-domain.js +163 -7
- package/dist/square-facade.d.ts +16 -10
- package/dist/square-index.d.ts +24 -0
- package/dist/square-index.js +131 -0
- package/dist/square-legacy-framing.d.ts +9 -0
- package/dist/square-legacy-framing.js +56 -0
- package/dist/square-migration-host-ledger.d.ts +26 -0
- package/dist/square-migration-host-ledger.js +168 -0
- package/dist/square-migration.d.ts +5 -5
- package/dist/square-migration.js +373 -71
- package/dist/square-sqlite.d.ts +9 -9
- package/dist/square-sqlite.js +329 -79
- package/dist/square-stdio.d.ts +1 -1
- package/dist/square-stdio.js +12 -7
- package/dist/square-tools.d.ts +1 -1
- package/dist/square-tools.js +80 -27
- package/dist/stdio-server.js +4 -2
- package/dist/stream.d.ts +3 -2
- package/dist/stream.js +9 -10
- package/dist/views.d.ts +9 -14
- package/dist/views.js +52 -70
- package/dist/wakes.d.ts +6 -5
- package/dist/wakes.js +20 -17
- package/guides/application-facade-delivery-evidence.md +1 -1
- package/guides/claude-native.md +9 -9
- package/guides/mcp.md +2 -2
- package/guides/migration.md +107 -67
- package/guides/pi-tools.md +1 -1
- package/guides/row-storage-design.md +1 -1
- package/guides/square-api.md +61 -28
- package/package.json +1 -1
- package/plugins/claude/.claude-plugin/plugin.json +1 -1
- package/plugins/claude/hooks/register.js +1 -1
- package/plugins/claude/skills/square/SKILL.md +4 -4
- package/plugins/claude/types.d.ts +1 -1
- package/plugins/codex/.codex-plugin/plugin.json +1 -1
- package/plugins/opencode/delivery.ts +170 -118
- package/plugins/opencode/index.ts +12 -30
- package/plugins/pi/square-pi.js +56 -18
- package/skills/square/SKILL.md +4 -4
- package/dist/cli/ledger-command.d.ts +0 -12
- package/dist/cli/ledger-command.js +0 -72
- package/dist/host-ledger-file-adapter.d.ts +0 -47
- package/dist/host-ledger-file-adapter.js +0 -384
- package/dist/host-ledger-migration.d.ts +0 -27
- package/dist/host-ledger-migration.js +0 -264
- package/dist/host-ledger-root.d.ts +0 -2
- package/dist/host-ledger-root.js +0 -9
- package/dist/host-ledger-sqlite.d.ts +0 -65
- package/dist/host-ledger-sqlite.js +0 -368
- package/dist/host-ledger.d.ts +0 -195
- package/dist/host-ledger.js +0 -1
- package/dist/ledger-maintenance.d.ts +0 -30
- package/dist/ledger-maintenance.js +0 -110
- package/dist/open-square.d.ts +0 -38
- package/dist/open-square.js +0 -81
- package/dist/participant-host.d.ts +0 -23
- package/dist/participant-host.js +0 -92
- package/dist/registry.d.ts +0 -55
- package/dist/registry.js +0 -123
- package/dist/routes.d.ts +0 -39
- package/dist/routes.js +0 -99
- package/dist/square-actions.d.ts +0 -56
- package/dist/square-actions.js +0 -353
- package/dist/square-projections.d.ts +0 -31
- package/dist/square-projections.js +0 -64
- package/dist/wake-attempts.d.ts +0 -10
- package/dist/wake-attempts.js +0 -39
- package/dist/wake-eligibility.d.ts +0 -53
- package/dist/wake-eligibility.js +0 -123
- package/dist/wake-evidence.d.ts +0 -33
- package/dist/wake-evidence.js +0 -32
- package/guides/host-ledger.md +0 -58
- package/guides/indexed-host-ledger-performance.md +0 -39
package/dist/artifact.d.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { DatabaseSync } from 'node:sqlite';
|
|
2
2
|
import { type BuildOptions } from './model.js';
|
|
3
|
-
import type { SquareArtifactPort } from './ports.js';
|
|
3
|
+
import type { SquareResourceOwner, SquareArtifactPort } from './ports.js';
|
|
4
4
|
import { type SquareState } from './square-sqlite.js';
|
|
5
|
+
/** Explicit-lifetime holder of one reused artifact connection. Request cancellation
|
|
6
|
+
* never becomes the shared connection's lifetime; close drains the owner once. */
|
|
7
|
+
export declare function createSquareResourceOwner(): SquareResourceOwner;
|
|
5
8
|
/** All build paths share configuration validation and lazy guide preparation. */
|
|
6
9
|
export declare function prepareSquareBuild(options: Omit<BuildOptions, 'force'>, snippet: string): SquareState;
|
|
7
10
|
/** File build owns publication and CLI conflict semantics, not host resources. */
|
|
@@ -32,4 +35,6 @@ export declare function writeSquareFile(location: string, state: SquareState, si
|
|
|
32
35
|
export declare function readSquareSnapshot(location: string, signal?: AbortSignal): Promise<SquareSnapshot>;
|
|
33
36
|
export declare function readSquareRevision(location: string, signal?: AbortSignal): Promise<number>;
|
|
34
37
|
export declare function observeSquareRevision(location: string): Promise<import('./file-changes.js').VersionObserver<number | null>>;
|
|
38
|
+
export declare function readSquareDeliveryRevision(location: string, signal?: AbortSignal): Promise<number>;
|
|
39
|
+
export declare function observeSquareDeliveryRevision(location: string): Promise<import('./file-changes.js').VersionObserver<number | null>>;
|
|
35
40
|
export declare function diagnoseSquareFile(location: string): Promise<DiagnoseResult>;
|
package/dist/artifact.js
CHANGED
|
@@ -10,6 +10,33 @@ import { canonicalPath } from './canonical-path.js';
|
|
|
10
10
|
import { InternalSquareError, SquareError } from './model.js';
|
|
11
11
|
import { wrapSquareWrite } from './square-domain.js';
|
|
12
12
|
import { APPLICATION_ID, CURRENT_USER_VERSION, createSqliteDriver, initializeSqlite, exportSqliteState, inspectSqlite, invalidArtifact, validateSqliteHeader, emptyRuntimeState } from './square-sqlite.js';
|
|
13
|
+
/** Explicit-lifetime holder of one reused artifact connection. Request cancellation
|
|
14
|
+
* never becomes the shared connection's lifetime; close drains the owner once. */
|
|
15
|
+
export function createSquareResourceOwner() {
|
|
16
|
+
let held;
|
|
17
|
+
let closed = false;
|
|
18
|
+
return {
|
|
19
|
+
artifact(location) {
|
|
20
|
+
if (closed)
|
|
21
|
+
throw new SquareError('unavailable', 'Square resource owner is closed');
|
|
22
|
+
const key = path.resolve(location);
|
|
23
|
+
if (held === undefined)
|
|
24
|
+
held = { location: key, artifact: createArtifactPort(key) };
|
|
25
|
+
if (held.location !== key)
|
|
26
|
+
throw new SquareError('unavailable', `Square resource owner already holds ${held.location}; it cannot also open ${key}`);
|
|
27
|
+
return held.artifact;
|
|
28
|
+
},
|
|
29
|
+
async close() {
|
|
30
|
+
if (closed)
|
|
31
|
+
return;
|
|
32
|
+
closed = true;
|
|
33
|
+
const artifact = held?.artifact;
|
|
34
|
+
held = undefined;
|
|
35
|
+
if (artifact !== undefined)
|
|
36
|
+
await artifact.close();
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
}
|
|
13
40
|
const guideContents = new Map();
|
|
14
41
|
function readGuide(name) {
|
|
15
42
|
if (!['participant', 'architect', 'brainstorm'].includes(name))
|
|
@@ -40,7 +67,7 @@ export function prepareSquareBuild(options, snippet) {
|
|
|
40
67
|
hardCap: options.hardCap ?? null,
|
|
41
68
|
...(options.throttlePerMinute === undefined ? {} : { throttlePerMinute: options.throttlePerMinute }),
|
|
42
69
|
preamble: normalizedLines(snippet), warmup: normalizedLines(guides.join('\n\n')),
|
|
43
|
-
acts: [],
|
|
70
|
+
acts: [], runtime: emptyRuntimeState(),
|
|
44
71
|
};
|
|
45
72
|
}
|
|
46
73
|
/** File build owns publication and CLI conflict semantics, not host resources. */
|
|
@@ -93,9 +120,10 @@ const readMethods = [
|
|
|
93
120
|
'header', 'participant', 'roster', 'attention', 'incomingAttention', 'hold',
|
|
94
121
|
'activity', 'activityHeads', 'activities', 'activityCount', 'contextIndexes', 'sayOrdinals', 'recentSayTimes',
|
|
95
122
|
'audience', 'directed', 'directedAt', 'directedCount', 'pendingAudience',
|
|
96
|
-
'receipt', 'receiptFacts', 'receiptAssignments', 'lease', '
|
|
123
|
+
'receipt', 'receiptFacts', 'receiptAssignments', 'lease', 'participantCounts', 'seat', 'seatsForBody', 'completedSeatsForBody',
|
|
124
|
+
'deliveryEvidence', 'deliveryByToken', 'cancelledThrough',
|
|
97
125
|
];
|
|
98
|
-
const writeMethods = ['applyLanding', 'markSeen', 'putLease', 'removeLease', '
|
|
126
|
+
const writeMethods = ['applyLanding', 'markSeen', 'putLease', 'removeLease', 'storeSeat', 'removeSeat', 'updateWakeAddress', 'cancelThrough', 'claimDelivery', 'prepareDelivery', 'completeDelivery', 'observeNativeDelivery'];
|
|
99
127
|
/** One connection, ordered operations, guarded synchronous transaction capabilities. */
|
|
100
128
|
export function createArtifactPort(location, initial, externalSignal) {
|
|
101
129
|
let database;
|
|
@@ -146,7 +174,7 @@ export function createArtifactPort(location, initial, externalSignal) {
|
|
|
146
174
|
tail = result.then(() => undefined, () => undefined);
|
|
147
175
|
return result;
|
|
148
176
|
}
|
|
149
|
-
async function transaction(callback, write, signal) {
|
|
177
|
+
async function transaction(callback, write, signal, authority) {
|
|
150
178
|
const db = await connection(signal);
|
|
151
179
|
return inSqliteTransaction(db, write, () => validate(db), (header) => {
|
|
152
180
|
const driver = createSqliteDriver(db), version = header.revision;
|
|
@@ -170,12 +198,15 @@ export function createArtifactPort(location, initial, externalSignal) {
|
|
|
170
198
|
}
|
|
171
199
|
const reads = Object.fromEntries(readMethods.map(name => [name, guard(driver[name])]));
|
|
172
200
|
const writes = Object.fromEntries(writeMethods.map(name => [name, guard(driver[name])]));
|
|
173
|
-
const
|
|
201
|
+
const gate = write ? wrapSquareWrite(reads, writes, authority) : undefined;
|
|
202
|
+
const facts = gate?.facts ?? reads;
|
|
174
203
|
let value;
|
|
175
204
|
inCallback = true;
|
|
176
205
|
try {
|
|
177
206
|
value = callback(facts);
|
|
178
207
|
synchronous(value);
|
|
208
|
+
if (!failed)
|
|
209
|
+
gate?.complete();
|
|
179
210
|
}
|
|
180
211
|
finally {
|
|
181
212
|
inCallback = false;
|
|
@@ -184,13 +215,14 @@ export function createArtifactPort(location, initial, externalSignal) {
|
|
|
184
215
|
if (failed)
|
|
185
216
|
throw failure;
|
|
186
217
|
const changed = write && driver.changed;
|
|
187
|
-
|
|
218
|
+
const deliveryChanged = write && driver.deliveryChanged;
|
|
219
|
+
if (changed || deliveryChanged) {
|
|
188
220
|
if (version === Number.MAX_SAFE_INTEGER)
|
|
189
221
|
throw invalidArtifact('revision cannot advance beyond the safe integer limit.');
|
|
190
|
-
db.prepare('UPDATE square_meta SET revision
|
|
222
|
+
db.prepare('UPDATE square_meta SET revision=revision+?, delivery_revision=delivery_revision+? WHERE id=1').run(Number(changed), Number(deliveryChanged));
|
|
191
223
|
}
|
|
192
224
|
return {
|
|
193
|
-
value, version: version + Number(changed), changed
|
|
225
|
+
value, version: version + Number(changed), changed, deliveryChanged
|
|
194
226
|
};
|
|
195
227
|
}, signal);
|
|
196
228
|
}
|
|
@@ -203,8 +235,29 @@ export function createArtifactPort(location, initial, externalSignal) {
|
|
|
203
235
|
const { value, version } = await transaction(select, false, s);
|
|
204
236
|
return { value, version };
|
|
205
237
|
}, signal),
|
|
206
|
-
|
|
238
|
+
transactAs: (authority, change, signal) => queue(s => transaction(change, true, s, authority), signal),
|
|
207
239
|
revision,
|
|
240
|
+
async deliveryRevision(signal) {
|
|
241
|
+
return queue(async (s) => {
|
|
242
|
+
const db = await connection(s);
|
|
243
|
+
return inSqliteTransaction(db, false, () => validate(db), (header) => header.deliveryRevision, s);
|
|
244
|
+
}, signal);
|
|
245
|
+
},
|
|
246
|
+
async claimDelivery(input, signal) {
|
|
247
|
+
return (await this.transactAs({ kind: 'participant', seat: input.seat }, (facts) => facts.claimDelivery(input), signal)).value;
|
|
248
|
+
},
|
|
249
|
+
async prepareDelivery(input, signal) {
|
|
250
|
+
return (await this.transactAs({ kind: 'participant', seat: input.seat }, facts => facts.prepareDelivery(input), signal)).value;
|
|
251
|
+
},
|
|
252
|
+
async completeDelivery(input, signal) {
|
|
253
|
+
return (await this.transactAs({ kind: 'participant', seat: input.seat }, facts => facts.completeDelivery(input), signal)).value;
|
|
254
|
+
},
|
|
255
|
+
async cancelDeliveries(seat, through, signal) {
|
|
256
|
+
return (await this.transactAs({ kind: 'participant', seat }, facts => {
|
|
257
|
+
const boundary = through ?? facts.header().lastActIndex;
|
|
258
|
+
return boundary < 0 ? false : facts.cancelThrough(seat, boundary);
|
|
259
|
+
}, signal)).value;
|
|
260
|
+
},
|
|
208
261
|
async changed(since, timeout, signal) {
|
|
209
262
|
if (inCallback)
|
|
210
263
|
throw new TypeError('Square artifact operations cannot nest inside a callback.');
|
|
@@ -321,7 +374,7 @@ export async function writeSquareFile(location, state, signal) {
|
|
|
321
374
|
const revision = createSqliteDriver(db).header().revision;
|
|
322
375
|
if (revision === Number.MAX_SAFE_INTEGER)
|
|
323
376
|
throw invalidArtifact('revision cannot advance beyond the safe integer limit.');
|
|
324
|
-
for (const table of ['landed_audience', 'attention', 'participants', '
|
|
377
|
+
for (const table of ['landed_audience', 'attention', 'participants', 'delivery_cancellations', 'delivery_evidence', 'seats', 'catch_leases', 'receipts', 'activities', 'square_meta'])
|
|
325
378
|
db.exec(`DROP TABLE ${table}`);
|
|
326
379
|
initializeSqlite(db, state, revision + 1);
|
|
327
380
|
}, signal);
|
|
@@ -362,6 +415,22 @@ export function observeSquareRevision(location) {
|
|
|
362
415
|
}
|
|
363
416
|
});
|
|
364
417
|
}
|
|
418
|
+
export function readSquareDeliveryRevision(location, signal) {
|
|
419
|
+
return inspectFile(location, db => createSqliteDriver(db).header().deliveryRevision, signal);
|
|
420
|
+
}
|
|
421
|
+
export function observeSquareDeliveryRevision(location) {
|
|
422
|
+
return observeFileVersion(location, 'square-delivery-revision', async (file, signal) => {
|
|
423
|
+
try {
|
|
424
|
+
return await readSquareDeliveryRevision(file, signal);
|
|
425
|
+
}
|
|
426
|
+
catch (error) {
|
|
427
|
+
abort(signal);
|
|
428
|
+
if (error instanceof InternalSquareError && error.code === 'not_found')
|
|
429
|
+
return null;
|
|
430
|
+
throw error;
|
|
431
|
+
}
|
|
432
|
+
});
|
|
433
|
+
}
|
|
365
434
|
export async function diagnoseSquareFile(location) {
|
|
366
435
|
try {
|
|
367
436
|
return { problems: [], ...await inspectFile(await canonicalPath(location), inspectSqlite) };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
export
|
|
1
|
+
import { pendingAtBoundary } from './inbox.js';
|
|
2
|
+
import type { Body, PendingMembership } from './model.js';
|
|
3
|
+
export { pendingAtBoundary };
|
|
4
|
+
export declare function renderPendingAtBoundary(inbox: PendingMembership[]): string;
|
|
4
5
|
/**
|
|
5
6
|
* Serialize a boundary across hook processes so one stale inbox cannot render twice.
|
|
6
7
|
*
|
|
@@ -9,4 +10,4 @@ export declare function renderPendingAtBoundary(inbox: InboxMembership[]): strin
|
|
|
9
10
|
* presentation evidence live, and `presentPending` still re-checks the pending head, join, ownership
|
|
10
11
|
* claim and seen CAS. A source that cannot verify its reuse must read the inbox again.
|
|
11
12
|
*/
|
|
12
|
-
export declare function presentPendingAtBoundary<T>(
|
|
13
|
+
export declare function presentPendingAtBoundary<T>(identity: Body, present: (context: string) => T | Promise<T>, lookup?: (identity: Body, env?: NodeJS.ProcessEnv, signal?: AbortSignal) => Promise<PendingMembership[]> | PendingMembership[], env?: NodeJS.ProcessEnv, signal?: AbortSignal): Promise<T | undefined>;
|
|
@@ -1,15 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { squareIndexPath } from './square-index.js';
|
|
2
2
|
import { createHash } from 'node:crypto';
|
|
3
|
-
import path from 'node:path';
|
|
4
3
|
import { withFileLock } from './file-lock.js';
|
|
5
|
-
import {
|
|
6
|
-
import { closeOpenSquare } from './open-square.js';
|
|
4
|
+
import { createArtifactPort } from './artifact.js';
|
|
7
5
|
import { presentPending } from './presentation-operations.js';
|
|
8
|
-
import {
|
|
9
|
-
import { sessionInbox } from './inbox.js';
|
|
6
|
+
import { sessionInbox, projectBoundaryEligibility, pendingAtBoundary, pendingKey } from './inbox.js';
|
|
10
7
|
import { attentionBodyIsClipped, renderAttentionPreview, renderSquareReminder } from './attention-presentation.js';
|
|
11
|
-
|
|
12
|
-
export { pendingAtBoundary } from './square-projections.js';
|
|
8
|
+
export { pendingAtBoundary };
|
|
13
9
|
const CONTEXT_MAX = 1200;
|
|
14
10
|
const presentationLocks = new Map();
|
|
15
11
|
/** One settled promise loses to an abort so an in-process presentation wait stays bounded too. */
|
|
@@ -48,9 +44,9 @@ function renderBoundary(inbox) {
|
|
|
48
44
|
const { membership, notification } = entry;
|
|
49
45
|
const block = [
|
|
50
46
|
renderAttentionPreview({
|
|
51
|
-
squarePath: membership.
|
|
47
|
+
squarePath: membership.location,
|
|
52
48
|
actIndex: notification.actIndex,
|
|
53
|
-
recipient: membership.
|
|
49
|
+
recipient: membership.seat.participant,
|
|
54
50
|
actor: notification.actor,
|
|
55
51
|
route: notification.route,
|
|
56
52
|
body: notification.body,
|
|
@@ -74,12 +70,11 @@ function renderBoundary(inbox) {
|
|
|
74
70
|
complete,
|
|
75
71
|
};
|
|
76
72
|
}
|
|
77
|
-
async function presentPendingAtBoundaryUnlocked(
|
|
78
|
-
const inbox = await lookup(
|
|
73
|
+
async function presentPendingAtBoundaryUnlocked(identity, present, lookup = sessionInbox, env = process.env, signal) {
|
|
74
|
+
const inbox = await lookup(identity, env, signal);
|
|
79
75
|
if (signal?.aborted)
|
|
80
76
|
return undefined;
|
|
81
|
-
const
|
|
82
|
-
const pending = await projectBoundaryEligibility({ hostLedger, sessionId, inbox });
|
|
77
|
+
const pending = await projectBoundaryEligibility(inbox);
|
|
83
78
|
if (pending.length === 0 || signal?.aborted)
|
|
84
79
|
return undefined;
|
|
85
80
|
const delivered = renderBoundary(pending);
|
|
@@ -92,16 +87,17 @@ async function presentPendingAtBoundaryUnlocked(sessionId, present, lookup = ses
|
|
|
92
87
|
result = await present(delivered.context);
|
|
93
88
|
} };
|
|
94
89
|
for (const entry of delivered.complete) {
|
|
95
|
-
let
|
|
90
|
+
let artifact;
|
|
96
91
|
try {
|
|
92
|
+
artifact = createArtifactPort(entry.membership.location, undefined, signal);
|
|
97
93
|
try {
|
|
98
|
-
|
|
94
|
+
await artifact.read(facts => facts.header(), signal);
|
|
99
95
|
}
|
|
100
96
|
catch {
|
|
101
97
|
continue;
|
|
102
98
|
}
|
|
103
99
|
for (const index of entry.actIndexes) {
|
|
104
|
-
const key =
|
|
100
|
+
const key = pendingKey(entry.membership, index);
|
|
105
101
|
const prior = presentationLocks.get(key);
|
|
106
102
|
if (prior !== undefined) {
|
|
107
103
|
await awaitWithSignal(prior, signal);
|
|
@@ -111,11 +107,11 @@ async function presentPendingAtBoundaryUnlocked(sessionId, present, lookup = ses
|
|
|
111
107
|
return undefined;
|
|
112
108
|
continue;
|
|
113
109
|
}
|
|
114
|
-
const work = presentPending({ artifact
|
|
110
|
+
const work = presentPending({ artifact, location: entry.membership.location, participant: entry.membership.seat.participant, activity: index, seat: entry.membership.seat, sink: { present: renderOnce }, markSeen: entry.markSeen, now: Date.now(), signal }).then(async (outcome) => {
|
|
115
111
|
// A stale projection can outlive its activity; still surface the bounded preview,
|
|
116
112
|
// but there is no artifact observation to commit.
|
|
117
113
|
if (!outcome.presented) {
|
|
118
|
-
const exists = await
|
|
114
|
+
const exists = await artifact.read((facts) => facts.activity(index) !== undefined, signal).catch(() => undefined);
|
|
119
115
|
if (exists?.value === false)
|
|
120
116
|
await renderOnce();
|
|
121
117
|
}
|
|
@@ -132,8 +128,8 @@ async function presentPendingAtBoundaryUnlocked(sessionId, present, lookup = ses
|
|
|
132
128
|
}
|
|
133
129
|
}
|
|
134
130
|
finally {
|
|
135
|
-
if (
|
|
136
|
-
await
|
|
131
|
+
if (artifact !== undefined)
|
|
132
|
+
await artifact.close();
|
|
137
133
|
}
|
|
138
134
|
}
|
|
139
135
|
return result;
|
|
@@ -146,8 +142,8 @@ async function presentPendingAtBoundaryUnlocked(sessionId, present, lookup = ses
|
|
|
146
142
|
* presentation evidence live, and `presentPending` still re-checks the pending head, join, ownership
|
|
147
143
|
* claim and seen CAS. A source that cannot verify its reuse must read the inbox again.
|
|
148
144
|
*/
|
|
149
|
-
export async function presentPendingAtBoundary(
|
|
150
|
-
const
|
|
151
|
-
const ownerKey = createHash('sha256').update(
|
|
152
|
-
return withFileLock(
|
|
145
|
+
export async function presentPendingAtBoundary(identity, present, lookup = sessionInbox, env = process.env, signal) {
|
|
146
|
+
const indexPath = squareIndexPath(env);
|
|
147
|
+
const ownerKey = createHash('sha256').update(JSON.stringify(identity)).digest('hex');
|
|
148
|
+
return withFileLock(`${indexPath}.boundary-${ownerKey}.lock`, { retryMs: 10, signal }, () => presentPendingAtBoundaryUnlocked(identity, present, lookup, env, signal));
|
|
153
149
|
}
|
package/dist/catch-decisions.js
CHANGED
|
@@ -31,7 +31,8 @@ export function catchLimit(value) {
|
|
|
31
31
|
export function selectCatchPage(facts, requestedName, options) {
|
|
32
32
|
const participant = resolveKnownName(facts, requestedName);
|
|
33
33
|
const limit = catchLimit(options.limit);
|
|
34
|
-
const
|
|
34
|
+
const senders = options.from?.map((name) => resolveKnownName(facts, name));
|
|
35
|
+
const filter = { unseenOnly: true, ...(senders === undefined ? {} : { senders }), ...(options.mention === true ? { attentionOnly: true } : {}) };
|
|
35
36
|
return { participant, indexes: facts.directed(participant, filter, { edge: 'oldest', limit }).items.map((item) => item.index), filter };
|
|
36
37
|
}
|
|
37
38
|
/** Selection, receipts and resulting cursor belong to one artifact write transaction. */
|
|
@@ -1,5 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
export interface ClaudeDeliveryObservation {
|
|
2
|
+
readonly eventId: string;
|
|
3
|
+
readonly messageId: string;
|
|
4
|
+
readonly state: 'held' | 'released' | 'dropped';
|
|
5
|
+
readonly reason?: string;
|
|
6
|
+
readonly observedAt: number;
|
|
7
|
+
}
|
|
8
|
+
export interface ClaudeDeliveryStatus extends ClaudeDeliveryObservation {
|
|
3
9
|
readonly provider: 'claude';
|
|
4
10
|
readonly sessionId: string;
|
|
5
11
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createArtifactPort } from './artifact.js';
|
|
2
|
+
import { indexedSquareEntries } from './square-index.js';
|
|
2
3
|
const holdReasons = new Set(['explicit-setting', 'managed-setting', 'repo-setting', 'invalid-setting', 'bypass-default', 'mode-unknown', 'mode-mismatch', 'no-mode-asserted']);
|
|
3
4
|
const dropReasons = new Set(['expired', 'refused', 'dropped', 'discarded']);
|
|
4
5
|
const uuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
@@ -12,13 +13,28 @@ export async function recordClaudeDeliveryStatus(input, env = process.env) {
|
|
|
12
13
|
|| (input.state === 'held' ? !holdReasons.has(input.reason ?? '')
|
|
13
14
|
: input.state === 'dropped' ? !dropReasons.has(input.reason ?? '') : input.reason !== undefined))
|
|
14
15
|
return false;
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
16
|
+
for (const entry of await indexedSquareEntries({ channel: 'claude-code', session: input.sessionId }, env)) {
|
|
17
|
+
const artifact = createArtifactPort(entry.location);
|
|
18
|
+
try {
|
|
19
|
+
const { value: match } = await artifact.read((facts) => facts.roster().flatMap((participant) => {
|
|
20
|
+
const seat = facts.seat(participant.name);
|
|
21
|
+
if (seat === undefined || seat.body.session !== input.sessionId || seat.body.channel !== 'claude-code')
|
|
22
|
+
return [];
|
|
23
|
+
const evidence = facts.deliveryEvidence(seat.participant, seat.generation).find((row) => row.correlation?.harness === 'claude' && row.correlation.messageId === input.messageId && row.claimToken !== undefined);
|
|
24
|
+
return evidence === undefined ? [] : [{ seat, evidence }];
|
|
25
|
+
}));
|
|
26
|
+
if (match.length === 0)
|
|
27
|
+
continue;
|
|
28
|
+
const { seat, evidence } = match[0];
|
|
29
|
+
const ref = { participant: seat.participant, body: seat.body, generation: seat.generation };
|
|
30
|
+
return (await artifact.transactAs({ kind: 'participant', seat: ref }, (facts) => facts.observeNativeDelivery({ seat: ref, claimToken: evidence.claimToken, observation: {
|
|
31
|
+
eventId: input.eventId, messageId: input.messageId, state: input.state,
|
|
32
|
+
...(input.reason === undefined ? {} : { reason: input.reason }), observedAt: input.observedAt,
|
|
33
|
+
} }))).value;
|
|
34
|
+
}
|
|
35
|
+
finally {
|
|
36
|
+
await artifact.close();
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return false;
|
|
24
40
|
}
|
|
@@ -1,11 +1,15 @@
|
|
|
1
|
-
import type { HostLedgerPort, PresenceRecord } from './host-ledger.js';
|
|
2
1
|
import type { WakeTransportPort } from './ports.js';
|
|
3
2
|
export declare function nativeTokens(text: string): string[];
|
|
4
3
|
export declare function nativePayload(token: string, preview: string): string;
|
|
5
|
-
export declare function createClaudeWakeTransport(
|
|
6
|
-
/**
|
|
4
|
+
export declare function createClaudeWakeTransport(env?: NodeJS.ProcessEnv): WakeTransportPort;
|
|
5
|
+
/** Recognize the whole frame first; one inactive token vetoes it before any evidence/receipt write. */
|
|
7
6
|
export declare function observeClaudeDelivery(sessionId: string, text: string, operation: 'guard' | 'admitted' | 'stored', env?: NodeJS.ProcessEnv): Promise<{
|
|
8
7
|
recognized: boolean;
|
|
9
8
|
current: boolean;
|
|
10
9
|
}>;
|
|
11
|
-
export type ClaudeBinding =
|
|
10
|
+
export type ClaudeBinding = {
|
|
11
|
+
readonly location: string;
|
|
12
|
+
readonly participant: string;
|
|
13
|
+
readonly session: string;
|
|
14
|
+
readonly generation?: import('./square-core.js').ActivityId;
|
|
15
|
+
};
|