@astrosheep/square 0.3.61 → 0.3.63

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.
Files changed (90) hide show
  1. package/claude-plugin/.claude-plugin/plugin.json +1 -1
  2. package/claude-plugin/skills/square/SKILL.md +5 -7
  3. package/codex-plugin/.codex-plugin/plugin.json +1 -1
  4. package/dist/activity.d.ts +6 -2
  5. package/dist/activity.js +168 -133
  6. package/dist/artifact.d.ts +4 -0
  7. package/dist/artifact.js +43 -14
  8. package/dist/attention-presentation.d.ts +1 -0
  9. package/dist/attention-presentation.js +8 -6
  10. package/dist/automatic-session.js +14 -24
  11. package/dist/boundary-presentation.d.ts +1 -2
  12. package/dist/boundary-presentation.js +4 -19
  13. package/dist/cli/context.d.ts +2 -0
  14. package/dist/cli/context.js +2 -18
  15. package/dist/cli/harness-command.js +1 -1
  16. package/dist/cli/mcp-server-command.d.ts +2 -0
  17. package/dist/cli/mcp-server-command.js +13 -0
  18. package/dist/cli/observation-commands.js +47 -19
  19. package/dist/cli/program.js +5 -2
  20. package/dist/cli/registry.js +2 -0
  21. package/dist/cli/square-commands.d.ts +1 -1
  22. package/dist/cli/square-commands.js +93 -125
  23. package/dist/decisions.d.ts +2 -0
  24. package/dist/decisions.js +44 -3
  25. package/dist/delivery-operations.d.ts +1 -2
  26. package/dist/delivery-operations.js +1 -4
  27. package/dist/file-changes.d.ts +12 -0
  28. package/dist/file-changes.js +235 -0
  29. package/dist/help.js +4 -8
  30. package/dist/host-ledger-file-adapter.d.ts +15 -13
  31. package/dist/host-ledger-file-adapter.js +131 -79
  32. package/dist/host-ledger-root.d.ts +2 -0
  33. package/dist/host-ledger-root.js +9 -0
  34. package/dist/host-ledger.d.ts +4 -24
  35. package/dist/inbox.d.ts +10 -5
  36. package/dist/inbox.js +152 -67
  37. package/dist/index.d.ts +3 -1
  38. package/dist/index.js +1 -0
  39. package/dist/mcp.d.ts +7 -0
  40. package/dist/mcp.js +122 -0
  41. package/dist/mention-parse.d.ts +8 -0
  42. package/dist/mention-parse.js +107 -0
  43. package/dist/model.d.ts +5 -0
  44. package/dist/model.js +4 -1
  45. package/dist/notifications.d.ts +1 -0
  46. package/dist/notifications.js +25 -20
  47. package/dist/participant-host.js +2 -2
  48. package/dist/ports.d.ts +2 -9
  49. package/dist/presentation.d.ts +12 -1
  50. package/dist/presentation.js +42 -12
  51. package/dist/presented.js +2 -1
  52. package/dist/registry.d.ts +8 -4
  53. package/dist/registry.js +41 -74
  54. package/dist/routes.d.ts +19 -2
  55. package/dist/routes.js +48 -5
  56. package/dist/runtime.d.ts +2 -0
  57. package/dist/runtime.js +2 -0
  58. package/dist/square-actions.d.ts +26 -13
  59. package/dist/square-actions.js +200 -84
  60. package/dist/square-application.d.ts +58 -0
  61. package/dist/square-application.js +183 -0
  62. package/dist/square-facade.d.ts +24 -9
  63. package/dist/square-file-adapter.d.ts +5 -12
  64. package/dist/square-file-adapter.js +12 -64
  65. package/dist/square-projections.d.ts +3 -2
  66. package/dist/square-projections.js +12 -3
  67. package/dist/square-storage.js +27 -34
  68. package/dist/square-wiring.d.ts +12 -7
  69. package/dist/square-wiring.js +36 -32
  70. package/dist/state-cell.d.ts +1 -1
  71. package/dist/stream.js +30 -26
  72. package/dist/views.d.ts +3 -3
  73. package/dist/views.js +4 -4
  74. package/dist/wake-attempts.js +2 -1
  75. package/dist/wake-evidence.js +2 -8
  76. package/dist/wakes.d.ts +1 -0
  77. package/dist/wakes.js +5 -5
  78. package/dist/watch.d.ts +6 -1
  79. package/dist/watch.js +20 -18
  80. package/extensions/square-pi.js +100 -112
  81. package/guides/application-boundary.md +32 -0
  82. package/guides/architect.md +77 -77
  83. package/guides/brainstorm.md +197 -197
  84. package/guides/change-waits.md +28 -0
  85. package/guides/host-ledger.md +9 -0
  86. package/guides/mcp.md +9 -0
  87. package/guides/operation-cancellation.md +17 -0
  88. package/guides/participant.md +7 -7
  89. package/package.json +8 -2
  90. package/skills/square/SKILL.md +5 -7
package/dist/routes.js CHANGED
@@ -10,7 +10,7 @@ export async function defaultWakeRouteCapabilities(hostLedger) {
10
10
  let userCapable = hostLedger !== undefined;
11
11
  if (hostLedger !== undefined) {
12
12
  try {
13
- await hostLedger.listPresence({ scopes: ['user'], now: Date.now() });
13
+ await hostLedger.listPresence({ now: Date.now() });
14
14
  }
15
15
  catch {
16
16
  userCapable = false;
@@ -109,9 +109,44 @@ export function applyWakeRouteToState(state, route, at = Date.now()) {
109
109
  return !(itemLocation === location && routeIdentityKey(item, itemLocation) === routeIdentityKey(route, location));
110
110
  }), { ...route, location, updatedAt: at }];
111
111
  }
112
- export function dropSessionWakeRoutesFromState(state, location, sessionId) {
112
+ export function dropSessionWakeRoutesFromState(state, location, sessionId, expectedEpoch) {
113
113
  const canonical = canonicalRouteLocationSync(location);
114
- state.routes = (state.routes ?? []).filter((item) => !(item.sessionId === sessionId && canonicalRouteLocationSync(item.location) === canonical));
114
+ state.routes = (state.routes ?? []).filter((item) => {
115
+ if (item.sessionId !== sessionId || canonicalRouteLocationSync(item.location) !== canonical)
116
+ return true;
117
+ if (expectedEpoch === undefined)
118
+ return false;
119
+ return item.epoch !== expectedEpoch;
120
+ });
121
+ }
122
+ /**
123
+ * Drop one ended session's routes at a location, atomically with the lifecycle decide.
124
+ *
125
+ * A route survives when the ending transaction did not commit `done` and this session
126
+ * still holds the sole live presence for its participant — an in-flight same-session
127
+ * rejoin. `liveParticipants === undefined` means the ledger could not be read, so
128
+ * nothing is dropped on suspicion. An explicit epoch fence additionally keeps routes
129
+ * published by a later generation.
130
+ */
131
+ export function dropEndedSessionWakeRoutesFromState(state, location, sessionId, opts) {
132
+ const canonical = canonicalRouteLocationSync(location);
133
+ state.routes = (state.routes ?? []).filter((item) => {
134
+ if (item.sessionId !== sessionId || canonicalRouteLocationSync(item.location) !== canonical)
135
+ return true;
136
+ if (opts.participant !== undefined && nameKey(item.participant) !== nameKey(opts.participant))
137
+ return true;
138
+ if (!opts.force) {
139
+ // Keep only a route whose participant is still joined and whose ended session still
140
+ // holds the sole live presence — an in-flight same-session rejoin. A no-longer-joined
141
+ // participant is retired even when a stale presence row survives.
142
+ if (isCurrentlyJoined(state.acts, item.participant)
143
+ && (opts.liveParticipants === undefined || opts.liveParticipants.has(nameKey(item.participant))))
144
+ return true;
145
+ }
146
+ if (opts.expectedEpoch !== undefined && item.epoch !== opts.expectedEpoch)
147
+ return true;
148
+ return false;
149
+ });
115
150
  }
116
151
  export function dropParticipantWakeRoutesFromState(state, location, participant) {
117
152
  const canonical = canonicalRouteLocationSync(location);
@@ -163,8 +198,16 @@ export async function retireWakeRouteFromArtifact(artifact, route, opts = {}) {
163
198
  return opts.expectedEpoch !== undefined && itemEpoch !== opts.expectedEpoch;
164
199
  }) }, result: undefined }));
165
200
  }
166
- export async function retireWakeRoutesForSessionFromArtifact(artifact, route) {
167
- await artifact.transact((state) => { dropSessionWakeRoutesFromState(state, route.location, route.sessionId); return { state, result: undefined }; });
201
+ export async function retireWakeRoutesForSessionFromArtifact(artifact, route, opts = {}) {
202
+ const location = canonicalRouteLocationSync(route.location);
203
+ await artifact.transact((state) => ({ state: { ...state, routes: (state.routes ?? []).filter((item) => {
204
+ if (canonicalRouteLocationSync(item.location) !== location || item.sessionId !== route.sessionId)
205
+ return true;
206
+ if (opts.expectedEpoch === undefined)
207
+ return false;
208
+ const itemEpoch = item.epoch;
209
+ return itemEpoch !== undefined && itemEpoch !== opts.expectedEpoch;
210
+ }) }, result: undefined }));
168
211
  }
169
212
  export async function canonicalRouteLocation(location) {
170
213
  return canonicalRouteLocationSync(location);
package/dist/runtime.d.ts CHANGED
@@ -7,6 +7,8 @@ export declare const WATCH_STALE_MS: number;
7
7
  export declare const LOCK_RETRY_MS: number;
8
8
  export declare const THROTTLE_WINDOW_MS: number;
9
9
  export declare const UNREAD_BLOCK_GRACE_MS: number;
10
+ /** A held express waits for the hand to lower, but not forever: past this budget it gives up exactly like --no-wait (draft saved, retry printed). 0 disables waiting. */
11
+ export declare const HELD_WAIT_BUDGET_MS: number;
10
12
  export declare function nowMs(): number;
11
13
  /** Pure directed-activity filter. Bell matches every viewer; mentions match by audience. */
12
14
  export declare function matchesMentionTarget(act: {
package/dist/runtime.js CHANGED
@@ -40,6 +40,8 @@ export const WATCH_STALE_MS = parseIntegerEnv('SQUARE_WATCH_STALE_MS', scaledMs(
40
40
  export const LOCK_RETRY_MS = parseIntegerEnv('SQUARE_LOCK_RETRY_MS', 25);
41
41
  export const THROTTLE_WINDOW_MS = parseIntegerEnv('SQUARE_THROTTLE_WINDOW_MS', 60000);
42
42
  export const UNREAD_BLOCK_GRACE_MS = parseIntegerEnv('SQUARE_UNREAD_BLOCK_GRACE_MS', 90000);
43
+ /** A held express waits for the hand to lower, but not forever: past this budget it gives up exactly like --no-wait (draft saved, retry printed). 0 disables waiting. */
44
+ export const HELD_WAIT_BUDGET_MS = parseIntegerEnv('SQUARE_HELD_WAIT_BUDGET_MS', 10 * 60 * 1000);
43
45
  export function nowMs() {
44
46
  const override = process.env.SQUARE_NOW_MS;
45
47
  if (override === undefined)
@@ -1,37 +1,50 @@
1
1
  import { type SquareState } from './model.js';
2
2
  import type { WakeTransportPort } from './ports.js';
3
- import type { Activity, CatchOptions, CatchResult, ExpressOptions, ExpressResult, OwnershipFenceOptions } from './square-facade.js';
3
+ import type { Activity, CatchOptions, CatchResult, ExpressOptions, ExpressResult, OperationControl, OwnershipFenceOptions } from './square-facade.js';
4
4
  import { type CatchProjection } from './catch-decisions.js';
5
5
  import { type HostContext } from './participant-host.js';
6
6
  export interface OperationContext extends HostContext {
7
7
  readonly wakeTransport?: WakeTransportPort;
8
8
  }
9
9
  export type { OwnershipFenceOptions };
10
- export declare function catchUp(square: OperationContext, name: string, options?: CatchOptions, project?: (state: SquareState) => CatchProjection): Promise<CatchResult>;
11
- export declare function join(square: OperationContext, name: string): Promise<{
10
+ export declare function catchUp(square: OperationContext, name: string, options?: CatchOptions, project?: (state: SquareState) => CatchProjection, control?: OperationControl): Promise<CatchResult>;
11
+ export declare function join(square: OperationContext, name: string, control?: OperationControl): Promise<{
12
12
  readonly name: string;
13
13
  readonly activity: Activity | null;
14
14
  }>;
15
15
  /** End the standing participant and immediately let the caller reclaim the name. */
16
- export declare function takeover(square: OperationContext, name: string, _oldSessionIds?: readonly string[]): Promise<{
16
+ export declare function takeover(square: OperationContext, name: string, _oldSessionIds?: readonly string[], control?: OperationControl): Promise<{
17
17
  readonly name: string;
18
18
  readonly activities: readonly Activity[];
19
19
  readonly epoch?: number;
20
20
  }>;
21
- export declare function implicitJoin(square: OperationContext, name: string): Promise<{
21
+ export declare function implicitJoin(square: OperationContext, name: string, control?: OperationControl): Promise<{
22
22
  readonly name: string;
23
23
  readonly state: 'joined' | 'active' | 'done';
24
24
  readonly activity: Activity | null;
25
25
  }>;
26
- export declare function express(square: OperationContext, name: string, body: string, options?: ExpressOptions): Promise<ExpressResult>;
26
+ export declare function express(square: OperationContext, name: string, body: string, options?: ExpressOptions, control?: OperationControl): Promise<ExpressResult>;
27
27
  export interface ListenerChangeResult {
28
28
  readonly activity: Activity | null;
29
29
  }
30
- export declare function listen(square: OperationContext, actor: string, target: string): Promise<ListenerChangeResult>;
31
- export declare function ignore(square: OperationContext, actor: string, target: string): Promise<ListenerChangeResult>;
32
- export declare function listening(square: OperationContext, actor: string): Promise<readonly string[]>;
33
- export declare function done(square: OperationContext, name: string, body?: string, fence?: OwnershipFenceOptions): Promise<ExpressResult>;
34
- /** SessionEnd retires the ended session's routes even when its presence row is gone. */
30
+ export declare function listen(square: OperationContext, actor: string, target: string, control?: OperationControl): Promise<ListenerChangeResult>;
31
+ export declare function ignore(square: OperationContext, actor: string, target: string, control?: OperationControl): Promise<ListenerChangeResult>;
32
+ export declare function listening(square: OperationContext, actor: string, control?: OperationControl): Promise<readonly string[]>;
33
+ export declare function done(square: OperationContext, name: string, body?: string, fence?: OwnershipFenceOptions, control?: OperationControl): Promise<ExpressResult>;
34
+ /**
35
+ * End one session's ownership of a participant inside the ownership claim critical
36
+ * section. The artifact `done` (when this session is still the owner) and retirement of
37
+ * this session's routes share one transaction, and the exact captured presence row is
38
+ * removed only while the lock is still held. A rejoin or takeover therefore lands either
39
+ * before the whole cleanup — and is part of the state being ended — or after it, with
40
+ * fresh presence and route rows that this cleanup can never touch.
41
+ */
35
42
  export declare function endOwnedSession(square: OperationContext, name: string, sessionId: string, expectedEpoch?: number): Promise<ExpressResult | null>;
36
- export declare function hold(square: OperationContext, name: string, reason?: string): Promise<ExpressResult>;
37
- export declare function resume(square: OperationContext, name: string): Promise<ExpressResult>;
43
+ /**
44
+ * Retire an ended session's orphan routes when no participant name is known. The
45
+ * ownership claim lock is held across the ledger read and the artifact transaction, so a
46
+ * rejoin that claims first is seen as a live participant and its route survives.
47
+ */
48
+ export declare function retireEndedSessionRoutes(square: OperationContext, sessionId: string): Promise<void>;
49
+ export declare function hold(square: OperationContext, name: string, reason?: string, control?: OperationControl): Promise<ExpressResult>;
50
+ export declare function resume(square: OperationContext, name: string, control?: OperationControl): Promise<ExpressResult>;