@astrosheep/square 0.3.23 → 0.3.25

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.
@@ -1,38 +1,92 @@
1
- import { hasPresentedAttention } from './presented.js';
2
- import { lookupParticipant } from './registry.js';
1
+ import { deriveDeliveryModel } from './delivery.js';
2
+ import { nameKey } from './model.js';
3
+ import { readPresentedAttentions } from './presented.js';
4
+ import { canonicalSquarePath, readActiveBindings } from './registry.js';
3
5
  import { readWakeRoutes } from './routes.js';
4
6
  import { isWakeRouteAttemptable, readWakeAttempts, terminalWakeEvidence, } from './wake-attempts.js';
5
7
  import { openSquare } from './square-file-adapter.js';
6
8
  import { closeOpenSquare } from './open-square.js';
7
- import { notificationEvidence } from './views.js';
8
- /** Project every wake decision from the same primary evidence. */
9
- export async function wakeEvidence(squarePath, recipient, actIndex, now, env) {
9
+ import { observationFor } from './runtime.js';
10
+ import { entryPresentation } from './views.js';
11
+ function attentionKey(squarePath, recipient, actIndex) {
12
+ return JSON.stringify([canonicalSquarePath(squarePath), nameKey(recipient), actIndex]);
13
+ }
14
+ function projectionFromState(squarePath, state, now, env, delivery = deriveDeliveryModel(state)) {
15
+ const canonicalPath = canonicalSquarePath(squarePath);
16
+ const owners = new Map();
17
+ for (const binding of readActiveBindings(now)) {
18
+ if (binding.squarePath !== canonicalPath)
19
+ continue;
20
+ const key = nameKey(binding.name);
21
+ const recipientOwners = owners.get(key) ?? new Set();
22
+ recipientOwners.add(binding.ownerId);
23
+ owners.set(key, recipientOwners);
24
+ }
25
+ const routesByOwner = new Map();
26
+ for (const route of readWakeRoutes({ freshOnly: true, now, env })) {
27
+ const routes = routesByOwner.get(route.ownerId) ?? [];
28
+ routes.push(route);
29
+ routesByOwner.set(route.ownerId, routes);
30
+ }
31
+ const attemptsByAttention = new Map();
32
+ for (const attempt of readWakeAttempts({ env, now })) {
33
+ const key = attentionKey(attempt.attention.squarePath, attempt.attention.recipient, attempt.attention.actIndex);
34
+ const attempts = attemptsByAttention.get(key) ?? [];
35
+ attempts.push(attempt);
36
+ attemptsByAttention.set(key, attempts);
37
+ }
38
+ const presentedByAttention = new Map();
39
+ for (const presented of readPresentedAttentions(env, now)) {
40
+ const key = attentionKey(presented.squarePath, presented.name, presented.actIndex);
41
+ const presentedOwners = presentedByAttention.get(key) ?? new Set();
42
+ presentedOwners.add(presented.ownerId);
43
+ presentedByAttention.set(key, presentedOwners);
44
+ }
45
+ return {
46
+ evidence(recipient, actIndex) {
47
+ const recipientOwners = owners.get(nameKey(recipient)) ?? new Set();
48
+ const key = attentionKey(squarePath, recipient, actIndex);
49
+ const attempts = attemptsByAttention.get(key) ?? [];
50
+ const terminal = terminalWakeEvidence(attempts);
51
+ const routes = [...recipientOwners].flatMap((ownerId) => routesByOwner.get(ownerId) ?? []);
52
+ const presented = [...(presentedByAttention.get(key) ?? [])]
53
+ .some((ownerId) => recipientOwners.has(ownerId));
54
+ return {
55
+ delivered: delivery.isSeen(recipient, actIndex),
56
+ notified: (() => {
57
+ const observation = observationFor(state, recipient, actIndex);
58
+ return observation?.state === 'notified'
59
+ && observation.ownerId !== undefined
60
+ && recipientOwners.has(observation.ownerId);
61
+ })(),
62
+ presented,
63
+ attempts,
64
+ ...(terminal === undefined ? {} : { terminal }),
65
+ attemptableRoutes: terminal === undefined
66
+ ? routes.filter((route) => isWakeRouteAttemptable(route, attempts))
67
+ : [],
68
+ };
69
+ },
70
+ };
71
+ }
72
+ /** Capture the primary wake facts once and derive any number of eligibility decisions from them. */
73
+ export async function wakeEvidenceProjection(squarePath, now, env) {
10
74
  const square = await openSquare(squarePath, { clock: () => now });
11
75
  try {
12
- const { delivered, observation } = await notificationEvidence(square, recipient, actIndex);
13
- const owners = new Set(lookupParticipant(squarePath, recipient, now).map((binding) => binding.ownerId));
14
- const notified = observation?.state === 'notified'
15
- && observation.ownerId !== undefined
16
- && owners.has(observation.ownerId);
17
- const attempts = readWakeAttempts({ attention: { squarePath, recipient, actIndex }, env, now });
18
- const terminal = terminalWakeEvidence(attempts);
19
- const routes = readWakeRoutes({ freshOnly: true, now, env })
20
- .filter((route) => owners.has(route.ownerId));
21
- return {
22
- delivered,
23
- notified,
24
- presented: hasPresentedAttention(squarePath, recipient, actIndex, env, now),
25
- attempts,
26
- ...(terminal === undefined ? {} : { terminal }),
27
- attemptableRoutes: terminal === undefined
28
- ? routes.filter((route) => isWakeRouteAttemptable(route, attempts))
29
- : [],
30
- };
76
+ const { state } = await entryPresentation(square, '');
77
+ return projectionFromState(squarePath, state, now, env);
31
78
  }
32
79
  finally {
33
80
  await closeOpenSquare(square);
34
81
  }
35
82
  }
83
+ export function wakeEvidenceProjectionFromState(squarePath, state, now, env, delivery) {
84
+ return projectionFromState(squarePath, state, now, env, delivery);
85
+ }
86
+ /** Project every wake decision from the same primary evidence. */
87
+ export async function wakeEvidence(squarePath, recipient, actIndex, now, env) {
88
+ return (await wakeEvidenceProjection(squarePath, now, env)).evidence(recipient, actIndex);
89
+ }
36
90
  export function wakeIsEligible(evidence) {
37
91
  return !evidence.delivered
38
92
  && !evidence.notified
package/dist/watch.d.ts CHANGED
@@ -1,2 +1,3 @@
1
1
  import { type WatchOptions } from './model.js';
2
- export declare function cmdWatch(squarePath: string, name: string, opts: WatchOptions): Promise<void>;
2
+ /** `false` is reserved for a quiet --now; idle completion preserves its existing sweep boundary. */
3
+ export declare function cmdWatch(squarePath: string, name: string, opts: WatchOptions): Promise<boolean | undefined>;
package/dist/watch.js CHANGED
@@ -19,10 +19,15 @@ function watchOutputResult(squarePath, presentation, name, caught, opts = {}) {
19
19
  const delivered = caught.activities.flatMap((activity) => {
20
20
  const index = parseActivityId(activity.id);
21
21
  const stored = index === undefined ? undefined : presentation.activities.find((item) => item.index === index);
22
- return stored === undefined ? [] : [stored];
22
+ return stored === undefined ? [] : [{ activity: stored, perception: activity.perception }];
23
23
  });
24
- const publicItems = delivered.filter((item) => item.kind === 'say' || item.kind === 'done');
25
- const roomChanges = delivered.filter((item) => item.kind === 'join' || item.kind === 'done' || item.kind === 'hold' || item.kind === 'resume');
24
+ const publicItems = delivered
25
+ .map(({ activity }) => activity)
26
+ .filter((item) => item.kind === 'say' || item.kind === 'done');
27
+ const roomChanges = delivered
28
+ .map(({ activity }) => activity)
29
+ .filter((item) => item.kind === 'join' || item.kind === 'done' || item.kind === 'hold' || item.kind === 'resume');
30
+ const perceptions = new Map(delivered.map(({ activity, perception }) => [activity.index, perception]));
26
31
  return {
27
32
  type: 'output',
28
33
  stdout: renderWatchOutput([...presentation.activities], publicItems, roomChanges, {
@@ -30,7 +35,7 @@ function watchOutputResult(squarePath, presentation, name, caught, opts = {}) {
30
35
  squarePath,
31
36
  viewer: name,
32
37
  showCatchHint: !hasAutomaticDeliveryIdentity(),
33
- squareState: presentation.state,
38
+ perceptions,
34
39
  }),
35
40
  ...(opts.status ? { status: opts.status } : {}),
36
41
  };
@@ -118,12 +123,14 @@ async function cmdWatchNow(squarePath, name, opts) {
118
123
  ? watchOutputResult(squarePath, presentation, name, caught, { mention: opts.mention, ...(status ? { status } : {}) })
119
124
  : { type: 'terminal', status: status ?? 'empty-now' };
120
125
  await finishWatchResult(square, squarePath, name, result, undefined);
126
+ return caught.activities.length > 0;
121
127
  }
122
128
  finally {
123
129
  await facade.close();
124
130
  await closeOpenSquare(square);
125
131
  }
126
132
  }
133
+ /** `false` is reserved for a quiet --now; idle completion preserves its existing sweep boundary. */
127
134
  export async function cmdWatch(squarePath, name, opts) {
128
135
  let square;
129
136
  try {
@@ -144,8 +151,7 @@ export async function cmdWatch(squarePath, name, opts) {
144
151
  }
145
152
  if (opts.now) {
146
153
  await closeOpenSquare(square);
147
- await cmdWatchNow(squarePath, name, opts);
148
- return;
154
+ return cmdWatchNow(squarePath, name, opts);
149
155
  }
150
156
  const start = await beginWatch(square, squarePath, name, opts);
151
157
  if (start.type === 'active') {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astrosheep/square",
3
- "version": "0.3.23",
3
+ "version": "0.3.25",
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": {