@astrosheep/square 0.4.0 → 0.4.1

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 (187) hide show
  1. package/dist/artifact.d.ts +1 -3
  2. package/dist/artifact.js +12 -36
  3. package/dist/attention-presentation.d.ts +2 -22
  4. package/dist/attention-presentation.js +9 -12
  5. package/dist/boundary-presentation.d.ts +3 -14
  6. package/dist/boundary-presentation.js +29 -104
  7. package/dist/card-presentation.d.ts +1 -0
  8. package/dist/card-presentation.js +2 -0
  9. package/dist/catch-decisions.js +1 -7
  10. package/dist/claude-delivery.d.ts +13 -8
  11. package/dist/claude-delivery.js +40 -93
  12. package/dist/claude-mcp-context.js +2 -2
  13. package/dist/claude-mod.js +28 -140
  14. package/dist/claude-transport.d.ts +3 -3
  15. package/dist/claude-transport.js +20 -44
  16. package/dist/cli/context.js +7 -9
  17. package/dist/cli/observation-commands.d.ts +2 -0
  18. package/dist/cli/observation-commands.js +12 -2
  19. package/dist/cli/registry.js +3 -1
  20. package/dist/codex-address.d.ts +2 -2
  21. package/dist/codex-boundary-state.d.ts +1 -5
  22. package/dist/codex-boundary-state.js +0 -4
  23. package/dist/codex-hook.d.ts +7 -10
  24. package/dist/codex-hook.js +69 -33
  25. package/dist/codex-queue.d.ts +10 -11
  26. package/dist/codex-queue.js +32 -32
  27. package/dist/codex-watch.d.ts +2 -0
  28. package/dist/codex-watch.js +100 -0
  29. package/dist/decisions.js +2 -2
  30. package/dist/delivery-deferral.d.ts +8 -17
  31. package/dist/delivery-deferral.js +0 -28
  32. package/dist/delivery-frame.d.ts +7 -0
  33. package/dist/delivery-frame.js +11 -0
  34. package/dist/delivery-ledger-sqlite.d.ts +97 -0
  35. package/dist/delivery-ledger-sqlite.js +496 -0
  36. package/dist/delivery-ledger.d.ts +196 -0
  37. package/dist/delivery-ledger.js +268 -0
  38. package/dist/delivery-lifetime.d.ts +6 -0
  39. package/dist/delivery-lifetime.js +45 -0
  40. package/dist/harness-links.js +61 -7
  41. package/dist/harness.js +12 -17
  42. package/dist/help.js +2 -0
  43. package/dist/http-delivery.d.ts +5 -9
  44. package/dist/http-delivery.js +20 -77
  45. package/dist/inbox.d.ts +6 -49
  46. package/dist/inbox.js +24 -371
  47. package/dist/index.d.ts +6 -3
  48. package/dist/index.js +4 -1
  49. package/dist/mcp.js +1 -1
  50. package/dist/model.d.ts +7 -47
  51. package/dist/model.js +1 -7
  52. package/dist/notifications.d.ts +24 -20
  53. package/dist/notifications.js +39 -108
  54. package/dist/operation-control.d.ts +4 -0
  55. package/dist/operation-control.js +20 -0
  56. package/dist/packages/agent-delivery/src/claude-native.d.ts +2 -0
  57. package/dist/packages/agent-delivery/src/claude-native.js +5 -0
  58. package/dist/packages/agent-delivery/src/codex-boundary.d.ts +11 -6
  59. package/dist/packages/agent-delivery/src/codex-boundary.js +31 -40
  60. package/dist/packages/agent-delivery/src/codex-hook.d.ts +17 -12
  61. package/dist/packages/agent-delivery/src/codex-hook.js +26 -39
  62. package/dist/packages/agent-delivery/src/codex.d.ts +3 -0
  63. package/dist/packages/agent-delivery/src/codex.js +41 -4
  64. package/dist/packages/agent-delivery/src/index.d.ts +3 -1
  65. package/dist/packages/agent-delivery/src/index.js +1 -1
  66. package/dist/packages/agent-delivery/src/paseo.js +11 -2
  67. package/dist/packages/agent-delivery/src/types.d.ts +1 -0
  68. package/dist/paseo-delivery.d.ts +5 -5
  69. package/dist/paseo-delivery.js +19 -97
  70. package/dist/paseo.d.ts +1 -1
  71. package/dist/paseo.js +1 -1
  72. package/dist/plugins/opencode/index.d.ts +5 -3
  73. package/dist/plugins/opencode/index.js +99 -21
  74. package/dist/plugins/opencode-shared/delivery.d.ts +23 -0
  75. package/dist/plugins/opencode-shared/delivery.js +109 -0
  76. package/dist/plugins/opencode-v1/index.d.ts +28 -0
  77. package/dist/plugins/opencode-v1/index.js +41 -0
  78. package/dist/plugins/opencode-v1/runtime.d.ts +56 -0
  79. package/dist/plugins/opencode-v1/runtime.js +152 -0
  80. package/dist/plugins/opencode-v1/transport.d.ts +13 -0
  81. package/dist/plugins/opencode-v1/transport.js +50 -0
  82. package/dist/plugins/paseo/shared/card-presentation.d.ts +10 -0
  83. package/dist/plugins/paseo/shared/card-presentation.js +7 -0
  84. package/dist/ports.d.ts +31 -90
  85. package/dist/session-lifecycle.d.ts +8 -7
  86. package/dist/session-lifecycle.js +40 -42
  87. package/dist/sqlite-square.d.ts +14 -23
  88. package/dist/sqlite-square.js +132 -139
  89. package/dist/square-api.js +4 -7
  90. package/dist/square-core.d.ts +0 -1
  91. package/dist/square-domain.d.ts +5 -17
  92. package/dist/square-domain.js +104 -221
  93. package/dist/square-facade.d.ts +18 -15
  94. package/dist/square-post.d.ts +53 -0
  95. package/dist/square-post.js +4 -0
  96. package/dist/square-posting.d.ts +13 -0
  97. package/dist/square-posting.js +174 -0
  98. package/dist/square-producer-sqlite.d.ts +11 -0
  99. package/dist/square-producer-sqlite.js +210 -0
  100. package/dist/square-sqlite.d.ts +15 -25
  101. package/dist/square-sqlite.js +150 -226
  102. package/dist/views.d.ts +2 -2
  103. package/dist/views.js +0 -1
  104. package/dist/wake-sink.d.ts +4 -11
  105. package/dist/wake-sink.js +8 -32
  106. package/dist/wake-transports.d.ts +4 -7
  107. package/dist/wake-transports.js +8 -39
  108. package/examples/symmetric-domains.mjs +29 -249
  109. package/guides/change-waits.md +13 -53
  110. package/guides/claude-native.md +19 -175
  111. package/guides/codex-delivery.md +55 -80
  112. package/guides/delivery-primitives.md +48 -207
  113. package/guides/operation-cancellation.md +2 -5
  114. package/guides/participant-ownership.md +25 -89
  115. package/guides/pi-native-delivery.md +19 -56
  116. package/guides/pi-tools.md +6 -8
  117. package/guides/square-api.md +113 -615
  118. package/package.json +8 -8
  119. package/plugins/claude/.claude-plugin/plugin.json +1 -1
  120. package/plugins/claude/hooks/hooks.json +1 -1
  121. package/plugins/claude/{hooks/register.js → mods/square.js} +4 -7
  122. package/plugins/codex/.codex-plugin/plugin.json +1 -1
  123. package/plugins/codex/hooks/hooks.json +11 -23
  124. package/plugins/opencode/index.ts +91 -23
  125. package/plugins/opencode-shared/delivery.ts +91 -0
  126. package/plugins/opencode-v1/index.ts +36 -0
  127. package/plugins/opencode-v1/runtime.ts +134 -0
  128. package/plugins/opencode-v1/transport.ts +41 -0
  129. package/plugins/paseo/OVERVIEW.md +5 -5
  130. package/plugins/paseo/README.md +7 -6
  131. package/plugins/paseo/client/markdown.tsx +5 -5
  132. package/plugins/paseo/client/square-message.tsx +28 -24
  133. package/plugins/paseo/client/transform.ts +8 -5
  134. package/plugins/paseo/shared/card-presentation.ts +16 -0
  135. package/plugins/paseo/shared/message.ts +6 -11
  136. package/plugins/pi/square-pi.js +156 -417
  137. package/dist/channel-artifact.d.ts +0 -10
  138. package/dist/channel-artifact.js +0 -55
  139. package/dist/channel-delivery.d.ts +0 -11
  140. package/dist/channel-delivery.js +0 -51
  141. package/dist/channel-domain.d.ts +0 -3
  142. package/dist/channel-domain.js +0 -83
  143. package/dist/channel-facade.d.ts +0 -76
  144. package/dist/channel-facade.js +0 -1
  145. package/dist/channel-internal.d.ts +0 -126
  146. package/dist/channel-internal.js +0 -440
  147. package/dist/channel-metadata.d.ts +0 -11
  148. package/dist/channel-metadata.js +0 -1
  149. package/dist/channel-ports.d.ts +0 -241
  150. package/dist/channel-ports.js +0 -1
  151. package/dist/channel-presentation.d.ts +0 -17
  152. package/dist/channel-presentation.js +0 -22
  153. package/dist/channel-sqlite-schema.d.ts +0 -13
  154. package/dist/channel-sqlite-schema.js +0 -81
  155. package/dist/channel-transport.d.ts +0 -62
  156. package/dist/channel-transport.js +0 -1
  157. package/dist/channel.d.ts +0 -84
  158. package/dist/channel.js +0 -60
  159. package/dist/claude-delivery-status.d.ts +0 -13
  160. package/dist/claude-delivery-status.js +0 -46
  161. package/dist/cmd/notify-once.d.ts +0 -2
  162. package/dist/cmd/notify-once.js +0 -29
  163. package/dist/delivery-attempts.d.ts +0 -52
  164. package/dist/delivery-attempts.js +0 -73
  165. package/dist/delivery-effects.d.ts +0 -139
  166. package/dist/delivery-effects.js +0 -163
  167. package/dist/delivery-health.d.ts +0 -51
  168. package/dist/delivery-health.js +0 -173
  169. package/dist/delivery-operations.d.ts +0 -22
  170. package/dist/delivery-operations.js +0 -198
  171. package/dist/delivery-primitives.d.ts +0 -5
  172. package/dist/delivery-primitives.js +0 -3
  173. package/dist/delivery.d.ts +0 -56
  174. package/dist/delivery.js +0 -80
  175. package/dist/plugins/opencode/delivery.d.ts +0 -19
  176. package/dist/plugins/opencode/delivery.js +0 -223
  177. package/dist/presentation-operations.d.ts +0 -5
  178. package/dist/presentation-operations.js +0 -86
  179. package/dist/sqlite-channel.d.ts +0 -15
  180. package/dist/sqlite-channel.js +0 -600
  181. package/dist/square-index.d.ts +0 -16
  182. package/dist/square-index.js +0 -106
  183. package/dist/wake-preview.d.ts +0 -7
  184. package/dist/wake-preview.js +0 -15
  185. package/plugins/opencode/delivery.ts +0 -198
  186. /package/dist/{channel-values.d.ts → square-values.d.ts} +0 -0
  187. /package/dist/{channel-values.js → square-values.js} +0 -0
@@ -1,29 +0,0 @@
1
- #!/usr/bin/env node
2
- import { resolve } from 'node:path';
3
- import { setTimeout as sleep } from 'node:timers/promises';
4
- import { processActNotificationsOnce, wakeGraceMs } from '../notifications.js';
5
- function args(argv) {
6
- let squarePath;
7
- let actIndex;
8
- for (let index = 0; index < argv.length; index += 1) {
9
- if (argv[index] === '--location' && argv[index + 1] !== undefined)
10
- squarePath = resolve(argv[++index]);
11
- else if (argv[index] === '--act-index' && /^\d+$/.test(argv[index + 1] ?? ''))
12
- actIndex = Number(argv[++index]);
13
- else
14
- throw new Error(`Unknown notify-once argument: ${argv[index]}`);
15
- }
16
- if (squarePath === undefined || actIndex === undefined)
17
- throw new Error('notify-once requires --location and --act-index.');
18
- return { squarePath, actIndex };
19
- }
20
- async function main() {
21
- if (process.env.SQUARE_DISABLE_PASEO_WAKE === '1')
22
- return;
23
- const { squarePath, actIndex } = args(process.argv.slice(2));
24
- await sleep(wakeGraceMs());
25
- await processActNotificationsOnce(squarePath, actIndex);
26
- }
27
- main().catch(() => {
28
- process.exitCode = 0;
29
- });
@@ -1,52 +0,0 @@
1
- export type DeliveryPurpose = 'dispatch' | 'presentation';
2
- export type AttemptOutcome = 'dispatching' | 'accepted' | 'failed' | 'unknown' | 'released' | 'presented' | 'clipped';
3
- export interface Attempt<D> {
4
- readonly purpose: DeliveryPurpose;
5
- readonly token: string;
6
- readonly ordinal: number;
7
- readonly outcome: AttemptOutcome;
8
- readonly at: number;
9
- readonly expiresAt?: number;
10
- readonly data: D;
11
- }
12
- /** One item/recipient/authority/purpose series, bound inside the caller's transaction.
13
- * The caller owns token uniqueness, isolation and rollback; replacements retain coordinates.
14
- */
15
- export interface AttemptRows<D> {
16
- list(): readonly Attempt<D>[];
17
- byToken(token: string): Attempt<D> | undefined;
18
- insert(attempt: Attempt<D>): void;
19
- replace(attempt: Attempt<D>): void;
20
- }
21
- export type AttemptClaim<D> = {
22
- readonly status: 'acquired';
23
- readonly token: string;
24
- readonly ordinal: number;
25
- } | {
26
- readonly status: 'busy' | 'terminal';
27
- readonly evidence: Attempt<D>;
28
- readonly interrupted?: true;
29
- };
30
- export declare function claimAttempt<D>(rows: AttemptRows<D>, input: {
31
- purpose: DeliveryPurpose;
32
- token: string;
33
- at: number;
34
- leaseMs: number;
35
- data: D;
36
- }): AttemptClaim<D>;
37
- export declare function prepareAttempt<D>(rows: AttemptRows<D>, input: {
38
- token: string;
39
- data: D;
40
- }): boolean;
41
- export declare function settleAttempt<D>(rows: AttemptRows<D>, input: {
42
- token: string;
43
- outcome: Exclude<AttemptOutcome, 'dispatching'>;
44
- at: number;
45
- data: D;
46
- }): boolean;
47
- type Custody = Pick<Attempt<unknown>, 'purpose' | 'outcome' | 'expiresAt'>;
48
- /** Presentation custody suppresses dispatch independently of dispatch acceptance. */
49
- export declare function presentationBlocksDispatch(attempts: readonly Custody[], now: number): boolean;
50
- /** An expired dispatch is uncertain, not permission for automatic replay. */
51
- export declare function automaticDispatchEligible(attempts: readonly Custody[], now: number): boolean;
52
- export {};
@@ -1,73 +0,0 @@
1
- function finite(value) {
2
- if (typeof value !== 'number' || !Number.isFinite(value))
3
- throw new RangeError('time must be finite');
4
- }
5
- function token(value) {
6
- if (typeof value !== 'string' || value.length === 0)
7
- throw new TypeError('token must be nonempty');
8
- }
9
- export function claimAttempt(rows, input) {
10
- if (input.purpose !== 'dispatch' && input.purpose !== 'presentation')
11
- throw new TypeError('unsupported purpose');
12
- token(input.token);
13
- finite(input.at);
14
- if (!Number.isSafeInteger(input.leaseMs) || input.leaseMs <= 0)
15
- throw new RangeError('leaseMs must be a positive safe integer');
16
- const expiresAt = input.at + input.leaseMs;
17
- finite(expiresAt);
18
- const attempts = rows.list();
19
- const terminal = attempts.find(row => row.outcome === 'unknown'
20
- || row.outcome === (input.purpose === 'dispatch' ? 'accepted' : 'presented'));
21
- if (terminal !== undefined)
22
- return { status: 'terminal', evidence: terminal };
23
- const dispatching = attempts.find(row => row.outcome === 'dispatching');
24
- if (dispatching !== undefined) {
25
- if (dispatching.expiresAt === undefined || dispatching.expiresAt > input.at)
26
- return { status: 'busy', evidence: dispatching };
27
- const { expiresAt: _expiry, ...previous } = dispatching;
28
- const evidence = { ...previous, outcome: 'unknown', at: input.at };
29
- rows.replace(evidence);
30
- return { status: 'terminal', evidence, interrupted: true };
31
- }
32
- const ordinal = (attempts[0]?.ordinal ?? -1) + 1;
33
- if (!Number.isSafeInteger(ordinal) || ordinal < 0)
34
- throw new RangeError('attempt ordinal exhausted');
35
- rows.insert({ purpose: input.purpose, token: input.token, ordinal, outcome: 'dispatching', at: input.at, expiresAt, data: input.data });
36
- return { status: 'acquired', token: input.token, ordinal };
37
- }
38
- export function prepareAttempt(rows, input) {
39
- token(input.token);
40
- const previous = rows.byToken(input.token);
41
- if (previous?.outcome !== 'dispatching')
42
- return false;
43
- rows.replace({ ...previous, data: input.data });
44
- return true;
45
- }
46
- export function settleAttempt(rows, input) {
47
- token(input.token);
48
- finite(input.at);
49
- if (!['accepted', 'failed', 'unknown', 'released', 'presented', 'clipped'].includes(input.outcome))
50
- throw new TypeError('unsupported completion');
51
- const previous = rows.byToken(input.token);
52
- if (previous === undefined)
53
- return false;
54
- if (previous.outcome === 'accepted' && input.outcome === 'accepted')
55
- return true;
56
- if (previous.outcome !== 'dispatching' && !(previous.outcome === 'unknown' && input.outcome === 'accepted'))
57
- return false;
58
- const { expiresAt: _expiry, ...retained } = previous;
59
- rows.replace({ ...retained, outcome: input.outcome, at: input.at, data: input.data });
60
- return true;
61
- }
62
- /** Presentation custody suppresses dispatch independently of dispatch acceptance. */
63
- export function presentationBlocksDispatch(attempts, now) {
64
- finite(now);
65
- return attempts.some(row => row.purpose === 'presentation'
66
- && (row.outcome === 'presented' || row.outcome === 'clipped' || row.outcome === 'unknown'
67
- || row.outcome === 'dispatching'));
68
- }
69
- /** An expired dispatch is uncertain, not permission for automatic replay. */
70
- export function automaticDispatchEligible(attempts, now) {
71
- return !presentationBlocksDispatch(attempts, now) && !attempts.some(row => row.purpose === 'dispatch'
72
- && (row.outcome === 'accepted' || row.outcome === 'unknown' || row.outcome === 'dispatching'));
73
- }
@@ -1,139 +0,0 @@
1
- export interface EffectClaim {
2
- readonly token: string;
3
- readonly ordinal: number;
4
- }
5
- /** Bound to one captured item/recipient/authority/purpose, not an encoded series key. */
6
- export interface EffectPort<C> {
7
- /** The caller's existing atomic claim operation. Undefined means no custody acquired. */
8
- claim(signal?: AbortSignal): Promise<EffectClaim | undefined>;
9
- /** Pre-effect policy only. Rejection means unverifiable/not current. */
10
- current(signal?: AbortSignal): Promise<boolean>;
11
- /**
12
- * No request signal: persistence has its own bounded lifetime. For presentation,
13
- * `presented` MUST complete the attempt and record ALL captured full-consumption
14
- * receipts in ONE atomic transaction (rollback both on error). `clipped`, `failed`,
15
- * `unknown` and `released` complete the attempt without full-consumption receipts.
16
- * No post-effect currentness/deferral/cancellation veto; captured authority still fences.
17
- */
18
- settle(claim: EffectClaim, completion: C): Promise<boolean>;
19
- }
20
- export type Persistence = {
21
- readonly status: 'recorded';
22
- } | {
23
- readonly status: 'not-recorded';
24
- } | {
25
- readonly status: 'error';
26
- readonly error: unknown;
27
- };
28
- export interface Settlement<C> {
29
- readonly completion: C;
30
- readonly persistence: Persistence;
31
- }
32
- export interface DispatchOutcome {
33
- readonly outcome: 'accepted' | 'failed' | 'unknown' | 'not-capable';
34
- readonly data?: unknown;
35
- }
36
- export type DispatchCompletion = {
37
- readonly outcome: 'accepted' | 'failed' | 'unknown';
38
- readonly reason: 'returned';
39
- readonly data?: unknown;
40
- } | {
41
- readonly outcome: 'unknown';
42
- readonly reason: 'threw';
43
- readonly error: unknown;
44
- } | {
45
- readonly outcome: 'unknown';
46
- readonly reason: 'timeout';
47
- } | {
48
- readonly outcome: 'released';
49
- readonly reason: 'not-current';
50
- readonly phase: 'initial' | 'final';
51
- } | {
52
- readonly outcome: 'released';
53
- readonly reason: 'not-capable';
54
- readonly data?: unknown;
55
- } | {
56
- readonly outcome: 'released';
57
- readonly reason: 'cancelled';
58
- };
59
- export interface DispatchContext {
60
- readonly claim: EffectClaim;
61
- readonly timeoutMs: number;
62
- readonly deadline: number;
63
- readonly signal?: AbortSignal;
64
- /** Policy only. Sender MUST recheck deadline/cancellation after this await before I/O. */
65
- beforeSend(): Promise<boolean>;
66
- }
67
- export interface DispatchReport {
68
- readonly observation: {
69
- readonly kind: 'not-invoked';
70
- } | {
71
- readonly kind: 'returned';
72
- readonly result: DispatchOutcome;
73
- } | {
74
- readonly kind: 'threw';
75
- readonly error: unknown;
76
- } | {
77
- readonly kind: 'timeout';
78
- };
79
- readonly settlement?: Settlement<DispatchCompletion>;
80
- }
81
- /** Timer bounds the external attempt only, not claim/currentness/persistence. No automatic retry. */
82
- export declare function dispatchEffect(port: EffectPort<DispatchCompletion>, send: (context: DispatchContext) => Promise<DispatchOutcome>, options: {
83
- readonly timeoutMs: number;
84
- readonly signal?: AbortSignal;
85
- }): Promise<DispatchReport>;
86
- export type PresentationCompletion = {
87
- readonly outcome: 'presented' | 'clipped';
88
- readonly reason: 'returned';
89
- } | {
90
- readonly outcome: 'failed' | 'unknown';
91
- readonly reason: 'threw';
92
- readonly error: unknown;
93
- } | {
94
- readonly outcome: 'released';
95
- readonly reason: 'not-current' | 'cancelled' | 'unused';
96
- };
97
- export interface PresentationWork<P> {
98
- readonly payload: P;
99
- readonly coverage: 'full' | 'clipped';
100
- readonly port: EffectPort<PresentationCompletion>;
101
- }
102
- declare const preparedBrand: unique symbol;
103
- export interface PreparedPresentation<P> {
104
- readonly [preparedBrand]: true;
105
- readonly payload: P;
106
- eligible(signal?: AbortSignal): Promise<boolean>;
107
- release(): Promise<Settlement<PresentationCompletion>>;
108
- }
109
- export interface PresentationControl {
110
- readonly signal?: AbortSignal;
111
- /** Default unknown; throwing or invalid classifiers also stay unknown. */
112
- readonly classifyError?: (error: unknown) => 'failed' | 'unknown';
113
- }
114
- export interface PresentationReport<P, R> {
115
- readonly observation: {
116
- readonly kind: 'not-invoked';
117
- } | {
118
- readonly kind: 'returned';
119
- readonly value: R;
120
- } | {
121
- readonly kind: 'threw';
122
- readonly error: unknown;
123
- readonly outcome: 'failed' | 'unknown';
124
- };
125
- readonly settlements: readonly {
126
- readonly prepared: PreparedPresentation<P>;
127
- readonly result: Settlement<PresentationCompletion>;
128
- }[];
129
- }
130
- export declare function preparePresentation<P>(work: PresentationWork<P>, control?: {
131
- readonly signal?: AbortSignal;
132
- }): Promise<PreparedPresentation<P> | undefined>;
133
- export declare function presentPrepared<P, R>(prepared: PreparedPresentation<P>, sink: (payload: P) => R | Promise<R>, control?: PresentationControl): Promise<PresentationReport<P, R>>;
134
- /** Takes all local custody synchronously, then owns eligibility/effect/settlement/cleanup. */
135
- export declare function presentPreparedBatch<P, B, R>(prepared: readonly PreparedPresentation<P>[], render: (eligible: readonly PreparedPresentation<P>[]) => {
136
- readonly payload: B;
137
- readonly included: readonly PreparedPresentation<P>[];
138
- }, sink: (payload: B) => R | Promise<R>, control?: PresentationControl): Promise<PresentationReport<P, R>>;
139
- export {};
@@ -1,163 +0,0 @@
1
- async function settle(port, claim, completion) {
2
- try {
3
- return { completion, persistence: { status: await port.settle(claim, completion) ? 'recorded' : 'not-recorded' } };
4
- }
5
- catch (error) {
6
- return { completion, persistence: { status: 'error', error } };
7
- }
8
- }
9
- async function current(port, signal) {
10
- try {
11
- return await port.current(signal);
12
- }
13
- catch {
14
- return false;
15
- }
16
- }
17
- /** Timer bounds the external attempt only, not claim/currentness/persistence. No automatic retry. */
18
- export async function dispatchEffect(port, send, options) {
19
- const notInvoked = { kind: 'not-invoked' };
20
- if (options.signal?.aborted)
21
- return { observation: notInvoked };
22
- const claim = await port.claim(options.signal);
23
- if (claim === undefined)
24
- return { observation: notInvoked };
25
- if (!await current(port, options.signal))
26
- return { observation: notInvoked,
27
- settlement: await settle(port, claim, { outcome: 'released', reason: 'not-current', phase: 'initial' }) };
28
- if (options.signal?.aborted)
29
- return { observation: notInvoked,
30
- settlement: await settle(port, claim, { outcome: 'released', reason: 'cancelled' }) };
31
- let denied = false;
32
- let timer;
33
- const deadline = Date.now() + options.timeoutMs;
34
- const timeout = new Promise(resolve => {
35
- timer = setTimeout(() => resolve({ kind: 'timeout' }), options.timeoutMs);
36
- });
37
- let observation;
38
- let completion;
39
- try {
40
- observation = await Promise.race([timeout, (async () => {
41
- try {
42
- return { kind: 'returned', result: await send({ claim, deadline, ...options,
43
- beforeSend: async () => {
44
- const allowed = await current(port, options.signal);
45
- if (!allowed)
46
- denied = true;
47
- return allowed;
48
- },
49
- }) };
50
- }
51
- catch (error) {
52
- return { kind: 'threw', error };
53
- }
54
- })()]);
55
- // Freeze before persistence. Late policy results/sender completions cannot rewrite it.
56
- completion = observation.kind === 'timeout' ? { outcome: 'unknown', reason: 'timeout' }
57
- : denied ? { outcome: 'released', reason: 'not-current', phase: 'final' }
58
- : observation.kind === 'threw' ? { outcome: 'unknown', reason: 'threw', error: observation.error }
59
- : observation.result.outcome === 'not-capable'
60
- ? { outcome: 'released', reason: 'not-capable', data: observation.result.data }
61
- : { outcome: observation.result.outcome, reason: 'returned', data: observation.result.data };
62
- }
63
- finally {
64
- if (timer !== undefined)
65
- clearTimeout(timer);
66
- }
67
- return { observation, settlement: await settle(port, claim, completion) };
68
- }
69
- const preparedBrand = Symbol('prepared presentation');
70
- const custody = new WeakMap();
71
- export async function preparePresentation(work, control) {
72
- if (control?.signal?.aborted)
73
- return undefined;
74
- const claim = await work.port.claim(control?.signal);
75
- if (claim === undefined)
76
- return undefined;
77
- let resolve;
78
- let decided = false;
79
- const state = {
80
- owned: false, coverage: work.coverage,
81
- eligible: signal => signal?.aborted ? Promise.resolve(false) : current(work.port, signal),
82
- done: new Promise(res => { resolve = res; }),
83
- finish(completion) {
84
- if (decided)
85
- return;
86
- decided = true;
87
- // Defer callbacks: every included handle is marked before any settlement starts.
88
- void Promise.resolve().then(() => settle(work.port, claim, completion)).then(resolve);
89
- },
90
- };
91
- const prepared = Object.freeze({
92
- [preparedBrand]: true,
93
- payload: work.payload,
94
- eligible: (signal) => state.owned ? Promise.resolve(false) : state.eligible(signal),
95
- release() {
96
- if (!state.owned) {
97
- state.owned = true;
98
- state.finish({ outcome: 'released', reason: 'unused' });
99
- }
100
- return state.done;
101
- },
102
- });
103
- custody.set(prepared, state);
104
- return prepared;
105
- }
106
- export function presentPrepared(prepared, sink, control) {
107
- return presentPreparedBatch([prepared], eligible => ({ payload: prepared.payload, included: eligible }), sink, control);
108
- }
109
- /** Takes all local custody synchronously, then owns eligibility/effect/settlement/cleanup. */
110
- export async function presentPreparedBatch(prepared, render, sink, control = {}) {
111
- const handles = [...prepared];
112
- const states = handles.map(handle => custody.get(handle));
113
- if (new Set(handles).size !== handles.length || states.some(state => state === undefined || state.owned)) {
114
- await Promise.all([...new Set(handles)].filter(handle => custody.has(handle) && !custody.get(handle).owned).map(handle => handle.release()));
115
- throw new TypeError('Presentation requires unique, unused prepared custody.');
116
- }
117
- const owned = states;
118
- for (const state of owned)
119
- state.owned = true;
120
- let observation = { kind: 'not-invoked' };
121
- try {
122
- const eligible = [];
123
- for (const [index, state] of owned.entries()) {
124
- if (await state.eligible(control.signal))
125
- eligible.push(handles[index]);
126
- else
127
- state.finish({ outcome: 'released', reason: control.signal?.aborted ? 'cancelled' : 'not-current' });
128
- }
129
- const rendered = render(Object.freeze(eligible));
130
- const included = [...rendered.included];
131
- if (new Set(included).size !== included.length || included.some(handle => !eligible.includes(handle)))
132
- throw new TypeError('Included presentations must be a unique subset of eligible custody.');
133
- if (included.length > 0 && !control.signal?.aborted) {
134
- let completion;
135
- try {
136
- const value = await sink(rendered.payload);
137
- observation = { kind: 'returned', value };
138
- completion = { outcome: 'presented', reason: 'returned' };
139
- }
140
- catch (error) {
141
- let outcome = 'unknown';
142
- try {
143
- if (control.classifyError?.(error) === 'failed')
144
- outcome = 'failed';
145
- }
146
- catch { /* conservative */ }
147
- observation = { kind: 'threw', error, outcome };
148
- completion = { outcome, reason: 'threw', error };
149
- }
150
- for (const handle of included) {
151
- const state = custody.get(handle);
152
- state.finish(completion.outcome === 'presented'
153
- ? { outcome: state.coverage === 'full' ? 'presented' : 'clipped', reason: 'returned' } : completion);
154
- }
155
- }
156
- }
157
- finally {
158
- for (const state of owned)
159
- state.finish({ outcome: 'released', reason: control.signal?.aborted ? 'cancelled' : 'unused' });
160
- await Promise.all(owned.map(state => state.done));
161
- }
162
- return { observation, settlements: await Promise.all(handles.map(async (handle, index) => ({ prepared: handle, result: await owned[index].done }))) };
163
- }
@@ -1,51 +0,0 @@
1
- import { type DirectedNotificationRoute } from './delivery.js';
2
- import type { DeliveryEvidence } from './ports.js';
3
- export interface WakeAttempt {
4
- readonly nativeObservations?: readonly NonNullable<DeliveryEvidence['nativeObservations']>[number][];
5
- readonly at: number;
6
- readonly attention: {
7
- readonly squarePath: string;
8
- readonly recipient: string;
9
- readonly messageIndex: number;
10
- };
11
- readonly routeKind: import('./model.js').WakeRouteKind;
12
- readonly outcome: 'accepted' | 'unknown' | 'failed';
13
- readonly signature?: string;
14
- readonly attemptN: number;
15
- readonly message?: string;
16
- readonly diagnostic?: unknown;
17
- }
18
- export interface WakeReleaseDiagnostic {
19
- readonly at: number;
20
- readonly attention: {
21
- readonly squarePath: string;
22
- readonly recipient: string;
23
- readonly messageIndex: number;
24
- };
25
- readonly routeKind?: import('./model.js').WakeRouteKind;
26
- readonly attemptN?: number;
27
- readonly session?: string;
28
- readonly signature?: string;
29
- readonly message?: string;
30
- readonly diagnostic?: unknown;
31
- }
32
- export type DeliveryHealthKind = 'awaiting' | 'wake-accepted' | 'wake-unknown' | 'presented-not-delivered' | 'unreachable';
33
- export interface DeliveryHealthItem {
34
- squarePath: string;
35
- recipient: string;
36
- messageIndex: number;
37
- actor: string;
38
- at: number;
39
- ageMs: number;
40
- route?: DirectedNotificationRoute;
41
- kind: DeliveryHealthKind;
42
- attempt?: WakeAttempt;
43
- }
44
- /** Classify current pending attention from the artifact's seats and delivery evidence. */
45
- export declare function classifyDeliveryHealth(squarePath: string, opts: {
46
- graceMs: number;
47
- now?: number;
48
- env?: NodeJS.ProcessEnv;
49
- }): Promise<DeliveryHealthItem[]>;
50
- export declare function renderDeliveryHealth(items: readonly DeliveryHealthItem[], releases?: readonly WakeReleaseDiagnostic[], now?: number, nativeAttempts?: readonly WakeAttempt[]): string[];
51
- export declare function doctorDeliveryHealth(squarePath: string, graceMs: number, now?: number, env?: NodeJS.ProcessEnv): Promise<string[]>;